mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 15:25:18 +00:00
[R4R] bep3 module audit revisions (#505)
* most audit revisions * remove expected income * update begin block spec * filter queryAtomicSwaps, add queryAssetSupplies * update old address * update test * Remove legacy method * remove legacy comment * address PR comments * IsValid for SwapDirection, SwapStatus * fix rng logging * query asset supplies * return [64]byte from rng * remove cross chain field from MsgCreateAtomicSwap * move swap filtering to querier * rename Limit field to SupplyLimit
This commit is contained in:
parent
04cb414593
commit
6c68e41758
@ -4,15 +4,9 @@ import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// BeginBlocker runs at the start of every block
|
||||
// BeginBlocker on every block expires outdated atomic swaps and removes closed
|
||||
// swap from long term storage (default storage time of 1 week)
|
||||
func BeginBlocker(ctx sdk.Context, k Keeper) {
|
||||
err := k.UpdateExpiredAtomicSwaps(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = k.DeleteClosedAtomicSwapsFromLongtermStorage(ctx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
k.UpdateExpiredAtomicSwaps(ctx)
|
||||
k.DeleteClosedAtomicSwapsFromLongtermStorage(ctx)
|
||||
}
|
||||
|
@ -52,22 +52,22 @@ func (suite *ABCITestSuite) ResetKeeper() {
|
||||
var randomNumbers []tmbytes.HexBytes
|
||||
for i := 0; i < 10; i++ {
|
||||
// Set up atomic swap variables
|
||||
expireHeight := int64(360)
|
||||
expireHeight := uint64(360)
|
||||
amount := cs(c("bnb", int64(100)))
|
||||
timestamp := ts(i)
|
||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
// Create atomic swap and check err to confirm creation
|
||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, randomNumberHash, timestamp, expireHeight,
|
||||
suite.addrs[0], suite.addrs[i], TestSenderOtherChain, TestRecipientOtherChain,
|
||||
amount, amount.String(), true)
|
||||
amount, true)
|
||||
suite.Nil(err)
|
||||
|
||||
// Store swap's calculated ID and secret random number
|
||||
swapID := bep3.CalculateSwapID(randomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
||||
swapIDs = append(swapIDs, swapID)
|
||||
randomNumbers = append(randomNumbers, randomNumber.Bytes())
|
||||
randomNumbers = append(randomNumbers, randomNumber[:])
|
||||
}
|
||||
suite.swapIDs = swapIDs
|
||||
suite.randomNumbers = randomNumbers
|
||||
@ -105,7 +105,7 @@ func (suite *ABCITestSuite) TestBeginBlocker_UpdateExpiredAtomicSwaps() {
|
||||
{
|
||||
name: "after deletion",
|
||||
firstCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 400),
|
||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 400 + bep3.DefaultLongtermStorageDuration),
|
||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 400 + int64(bep3.DefaultLongtermStorageDuration)),
|
||||
expectedStatus: bep3.NULL,
|
||||
expectInStorage: false,
|
||||
},
|
||||
@ -166,7 +166,7 @@ func (suite *ABCITestSuite) TestBeginBlocker_DeleteClosedAtomicSwapsFromLongterm
|
||||
name: "no action with long storage duration",
|
||||
firstCtx: suite.ctx,
|
||||
action: NULL,
|
||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + bep3.DefaultLongtermStorageDuration),
|
||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + int64(bep3.DefaultLongtermStorageDuration)),
|
||||
expectInStorage: true,
|
||||
},
|
||||
{
|
||||
@ -180,7 +180,7 @@ func (suite *ABCITestSuite) TestBeginBlocker_DeleteClosedAtomicSwapsFromLongterm
|
||||
name: "claim with long storage duration",
|
||||
firstCtx: suite.ctx,
|
||||
action: Claim,
|
||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + bep3.DefaultLongtermStorageDuration),
|
||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + int64(bep3.DefaultLongtermStorageDuration)),
|
||||
expectInStorage: false,
|
||||
},
|
||||
{
|
||||
@ -194,7 +194,7 @@ func (suite *ABCITestSuite) TestBeginBlocker_DeleteClosedAtomicSwapsFromLongterm
|
||||
name: "refund with long storage duration",
|
||||
firstCtx: suite.ctx,
|
||||
action: Refund,
|
||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + bep3.DefaultLongtermStorageDuration),
|
||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + int64(bep3.DefaultLongtermStorageDuration)),
|
||||
expectInStorage: false,
|
||||
},
|
||||
}
|
||||
@ -214,12 +214,12 @@ func (suite *ABCITestSuite) TestBeginBlocker_DeleteClosedAtomicSwapsFromLongterm
|
||||
case Refund:
|
||||
for _, swapID := range suite.swapIDs {
|
||||
swap, _ := suite.keeper.GetAtomicSwap(tc.firstCtx, swapID)
|
||||
refundCtx := suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + swap.ExpireHeight)
|
||||
refundCtx := suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + int64(swap.ExpireHeight))
|
||||
bep3.BeginBlocker(refundCtx, suite.keeper)
|
||||
err := suite.keeper.RefundAtomicSwap(refundCtx, suite.addrs[5], swapID)
|
||||
suite.Nil(err)
|
||||
// Add expire height to second ctx block height
|
||||
tc.secondCtx = tc.secondCtx.WithBlockHeight(tc.secondCtx.BlockHeight() + swap.ExpireHeight)
|
||||
tc.secondCtx = tc.secondCtx.WithBlockHeight(tc.secondCtx.BlockHeight() + int64(swap.ExpireHeight))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,6 @@ const (
|
||||
AttributeKeyAtomicSwapIDs = types.AttributeKeyAtomicSwapIDs
|
||||
AttributeKeyClaimSender = types.AttributeKeyClaimSender
|
||||
AttributeKeyDirection = types.AttributeKeyDirection
|
||||
AttributeKeyExpectedIncome = types.AttributeKeyExpectedIncome
|
||||
AttributeKeyExpireHeight = types.AttributeKeyExpireHeight
|
||||
AttributeKeyRandomNumber = types.AttributeKeyRandomNumber
|
||||
AttributeKeyRandomNumberHash = types.AttributeKeyRandomNumberHash
|
||||
@ -29,7 +28,6 @@ const (
|
||||
CreateAtomicSwap = types.CreateAtomicSwap
|
||||
DefaultLongtermStorageDuration = types.DefaultLongtermStorageDuration
|
||||
DefaultParamspace = types.DefaultParamspace
|
||||
DepositAtomicSwap = types.DepositAtomicSwap
|
||||
EventTypeClaimAtomicSwap = types.EventTypeClaimAtomicSwap
|
||||
EventTypeCreateAtomicSwap = types.EventTypeCreateAtomicSwap
|
||||
EventTypeRefundAtomicSwap = types.EventTypeRefundAtomicSwap
|
||||
@ -61,7 +59,6 @@ var (
|
||||
NewKeeper = keeper.NewKeeper
|
||||
NewQuerier = keeper.NewQuerier
|
||||
RegisterRoutes = rest.RegisterRoutes
|
||||
BytesToHex = types.BytesToHex
|
||||
CalculateRandomHash = types.CalculateRandomHash
|
||||
CalculateSwapID = types.CalculateSwapID
|
||||
DefaultGenesisState = types.DefaultGenesisState
|
||||
@ -83,7 +80,6 @@ var (
|
||||
ErrSwapNotRefundable = types.ErrSwapNotRefundable
|
||||
GenerateSecureRandomNumber = types.GenerateSecureRandomNumber
|
||||
GetAtomicSwapByHeightKey = types.GetAtomicSwapByHeightKey
|
||||
HexToBytes = types.HexToBytes
|
||||
NewAssetSupply = types.NewAssetSupply
|
||||
NewAtomicSwap = types.NewAtomicSwap
|
||||
NewGenesisState = types.NewGenesisState
|
||||
@ -98,8 +94,6 @@ var (
|
||||
NewSwapStatusFromString = types.NewSwapStatusFromString
|
||||
ParamKeyTable = types.ParamKeyTable
|
||||
RegisterCodec = types.RegisterCodec
|
||||
Uint64FromBytes = types.Uint64FromBytes
|
||||
Uint64ToBytes = types.Uint64ToBytes
|
||||
|
||||
// variable aliases
|
||||
AbsoluteMaximumBlockLock = types.AbsoluteMaximumBlockLock
|
||||
|
@ -6,31 +6,43 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
|
||||
"github.com/kava-labs/kava/x/bep3/types"
|
||||
)
|
||||
|
||||
// Query atomic swaps flags
|
||||
const (
|
||||
flagInvolve = "involve"
|
||||
flagExpiration = "expiration"
|
||||
flagStatus = "status"
|
||||
flagDirection = "direction"
|
||||
)
|
||||
|
||||
// GetQueryCmd returns the cli query commands for this module
|
||||
func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
// Group bep3 queries under a subcommand
|
||||
bep3QueryCmd := &cobra.Command{
|
||||
Use: "bep3",
|
||||
Short: "Querying commands for the bep3 module",
|
||||
DisableFlagParsing: true,
|
||||
SuggestionsMinimumDistance: 2,
|
||||
RunE: client.ValidateCmd,
|
||||
}
|
||||
|
||||
bep3QueryCmd.AddCommand(flags.GetCommands(
|
||||
QueryCalcSwapIDCmd(queryRoute, cdc),
|
||||
QueryCalcRandomNumberHashCmd(queryRoute, cdc),
|
||||
QueryGetAtomicSwapCmd(queryRoute, cdc),
|
||||
QueryGetAssetSupplyCmd(queryRoute, cdc),
|
||||
QueryGetAssetSuppliesCmd(queryRoute, cdc),
|
||||
QueryGetAtomicSwapCmd(queryRoute, cdc),
|
||||
QueryGetAtomicSwapsCmd(queryRoute, cdc),
|
||||
QueryParamsCmd(queryRoute, cdc),
|
||||
)...)
|
||||
@ -70,10 +82,10 @@ func QueryCalcRandomNumberHashCmd(queryRoute string, cdc *codec.Codec) *cobra.Co
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
// Prepare random number, timestamp, and hash for output
|
||||
randomNumberStr := fmt.Sprintf("Random number: %s\n", randomNumber)
|
||||
randomNumberStr := fmt.Sprintf("Random number: %s\n", string(randomNumber[:]))
|
||||
timestampStr := fmt.Sprintf("Timestamp: %d\n", timestamp)
|
||||
randomNumberHashStr := fmt.Sprintf("Random number hash: %s", hex.EncodeToString(randomNumberHash))
|
||||
output := []string{randomNumberStr, timestampStr, randomNumberHashStr}
|
||||
@ -87,13 +99,13 @@ func QueryCalcSwapIDCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "calc-swapid [random-number-hash] [sender] [sender-other-chain]",
|
||||
Short: "calculate swap ID for the given random number hash, sender, and sender other chain",
|
||||
Example: "bep3 calc-swapid 0677bd8a303dd981810f34d8e5cc6507f13b391899b84d3c1be6c6045a17d747 kava15qdefkmwswysgg4qxgcqpqr35k3m49pkx2jdfnw bnb1ud3q90r98l3mhd87kswv3h8cgrymzeljct8qn7",
|
||||
Example: "bep3 calc-swapid 0677bd8a303dd981810f34d8e5cc6507f13b391899b84d3c1be6c6045a17d747 kava1l0xsq2z7gqd7yly0g40y5836g0appumark77ny bnb1ud3q90r98l3mhd87kswv3h8cgrymzeljct8qn7",
|
||||
Args: cobra.MinimumNArgs(3),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
// Parse query params
|
||||
randomNumberHash, err := types.HexToBytes(args[0])
|
||||
randomNumberHash, err := hex.DecodeString(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -137,6 +149,33 @@ func QueryGetAssetSupplyCmd(queryRoute string, cdc *codec.Codec) *cobra.Command
|
||||
}
|
||||
}
|
||||
|
||||
// QueryGetAssetSuppliesCmd queries AssetSupplies in the store
|
||||
func QueryGetAssetSuppliesCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "supplies",
|
||||
Short: "get a list of all asset supplies",
|
||||
Example: "bep3 supplies",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAssetSupplies), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var assetSupplies types.AssetSupplies
|
||||
cdc.MustUnmarshalJSON(res, &assetSupplies)
|
||||
|
||||
if len(assetSupplies) == 0 {
|
||||
return fmt.Errorf("There are currently no asset supplies")
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
return cliCtx.PrintOutput(assetSupplies)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// QueryGetAtomicSwapCmd queries an AtomicSwap by swapID
|
||||
func QueryGetAtomicSwapCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
@ -148,7 +187,7 @@ func QueryGetAtomicSwapCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
// Decode swapID's hex encoded string to []byte
|
||||
swapID, err := types.HexToBytes(args[0])
|
||||
swapID, err := hex.DecodeString(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -176,29 +215,97 @@ func QueryGetAtomicSwapCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
|
||||
// QueryGetAtomicSwapsCmd queries AtomicSwaps in the store
|
||||
func QueryGetAtomicSwapsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
cmd := &cobra.Command{
|
||||
Use: "swaps",
|
||||
Short: "get a list of active atomic swaps",
|
||||
Example: "bep3 swaps",
|
||||
Short: "query atomic swaps with optional filters",
|
||||
Long: strings.TrimSpace(`Query for all paginated atomic swaps that match optional filters:
|
||||
Example:
|
||||
$ kvcli q bep3 swaps --involve=kava1l0xsq2z7gqd7yly0g40y5836g0appumark77ny
|
||||
$ kvcli q bep3 swaps --expiration=280
|
||||
$ kvcli q bep3 swaps --status=(Open|Completed|Expired)
|
||||
$ kvcli q bep3 swaps --direction=(Incoming|Outgoing)
|
||||
$ kvcli q bep3 swaps --page=2 --limit=100
|
||||
`,
|
||||
),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
bechInvolveAddr := viper.GetString(flagInvolve)
|
||||
strExpiration := viper.GetString(flagExpiration)
|
||||
strSwapStatus := viper.GetString(flagStatus)
|
||||
strSwapDirection := viper.GetString(flagDirection)
|
||||
page := viper.GetInt(flags.FlagPage)
|
||||
limit := viper.GetInt(flags.FlagLimit)
|
||||
|
||||
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAtomicSwaps), nil)
|
||||
var involveAddr sdk.AccAddress
|
||||
var expiration uint64
|
||||
var swapStatus types.SwapStatus
|
||||
var swapDirection types.SwapDirection
|
||||
|
||||
params := types.NewQueryAtomicSwaps(page, limit, involveAddr, expiration, swapStatus, swapDirection)
|
||||
|
||||
if len(bechInvolveAddr) != 0 {
|
||||
involveAddr, err := sdk.AccAddressFromBech32(bechInvolveAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.Involve = involveAddr
|
||||
}
|
||||
|
||||
if len(strExpiration) != 0 {
|
||||
expiration, err := strconv.ParseUint(strExpiration, 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
params.Expiration = expiration
|
||||
}
|
||||
|
||||
if len(strSwapStatus) != 0 {
|
||||
swapStatus := types.NewSwapStatusFromString(strSwapStatus)
|
||||
if !swapStatus.IsValid() {
|
||||
return fmt.Errorf("invalid swap status %s", strSwapStatus)
|
||||
}
|
||||
params.Status = swapStatus
|
||||
}
|
||||
|
||||
if len(strSwapDirection) != 0 {
|
||||
swapDirection := types.NewSwapDirectionFromString(strSwapDirection)
|
||||
if !swapDirection.IsValid() {
|
||||
return fmt.Errorf("invalid swap direction %s", strSwapDirection)
|
||||
}
|
||||
params.Direction = swapDirection
|
||||
}
|
||||
|
||||
bz, err := cdc.MarshalJSON(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var atomicSwaps types.AtomicSwaps
|
||||
cdc.MustUnmarshalJSON(res, &atomicSwaps)
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
if len(atomicSwaps) == 0 {
|
||||
return fmt.Errorf("There are currently no atomic swaps")
|
||||
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAtomicSwaps), bz)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var matchingAtomicSwaps types.AtomicSwaps
|
||||
cdc.UnmarshalJSON(res, &matchingAtomicSwaps)
|
||||
|
||||
if len(matchingAtomicSwaps) == 0 {
|
||||
return fmt.Errorf("No matching atomic swaps found")
|
||||
}
|
||||
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
return cliCtx.PrintOutput(atomicSwaps.String())
|
||||
return cliCtx.PrintOutput(matchingAtomicSwaps.String()) // nolint:errcheck
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().Int(flags.FlagPage, 1, "pagination page of atomic swaps to to query for")
|
||||
cmd.Flags().Int(flags.FlagLimit, 100, "pagination limit of atomic swaps to query for")
|
||||
cmd.Flags().String(flagInvolve, "", "(optional) filter by atomic swaps that involve an address")
|
||||
cmd.Flags().String(flagExpiration, "", "(optional) filter by atomic swaps that expire before a block height")
|
||||
cmd.Flags().String(flagStatus, "", "(optional) filter by atomic swap status, status: open/completed/expired")
|
||||
cmd.Flags().String(flagDirection, "", "(optional) filter by atomic swap direction, direction: incoming/outgoing")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
// QueryParamsCmd queries the bep3 module parameters
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
@ -27,6 +28,9 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||
bep3TxCmd := &cobra.Command{
|
||||
Use: "bep3",
|
||||
Short: "bep3 transactions subcommands",
|
||||
DisableFlagParsing: true,
|
||||
SuggestionsMinimumDistance: 2,
|
||||
RunE: client.ValidateCmd,
|
||||
}
|
||||
|
||||
bep3TxCmd.AddCommand(flags.PostCommands(
|
||||
@ -41,23 +45,23 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||
// GetCmdCreateAtomicSwap cli command for creating atomic swaps
|
||||
func GetCmdCreateAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "create [to] [recipient-other-chain] [sender-other-chain] [timestamp] [coins] [expected-income] [height-span] [cross-chain]",
|
||||
Use: "create [to] [recipient-other-chain] [sender-other-chain] [timestamp] [coins] [height-span]",
|
||||
Short: "create a new atomic swap",
|
||||
Example: fmt.Sprintf("%s tx %s create kava1xy7hrjy9r0algz9w3gzm8u6mrpq97kwta747gj bnb1urfermcg92dwq36572cx4xg84wpk3lfpksr5g7 bnb1uky3me9ggqypmrsvxk7ur6hqkzq7zmv4ed4ng7 now 100bnb 100bnb 360 true --from validator",
|
||||
Example: fmt.Sprintf("%s tx %s create kava1xy7hrjy9r0algz9w3gzm8u6mrpq97kwta747gj bnb1urfermcg92dwq36572cx4xg84wpk3lfpksr5g7 bnb1uky3me9ggqypmrsvxk7ur6hqkzq7zmv4ed4ng7 now 100bnb 360 --from validator",
|
||||
version.ClientName, types.ModuleName),
|
||||
Args: cobra.ExactArgs(8),
|
||||
Args: cobra.ExactArgs(6),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
|
||||
|
||||
from := cliCtx.GetFromAddress() // same as KavaExecutor.DeputyAddress (for cross-chain)
|
||||
from := cliCtx.GetFromAddress() // same as Kava executor's deputy address
|
||||
to, err := sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
recipientOtherChain := args[1] // same as OtherExecutor.DeputyAddress
|
||||
recipientOtherChain := args[1] // same as the other executor's deputy address
|
||||
senderOtherChain := args[2]
|
||||
|
||||
// Timestamp defaults to time.Now() unless it's explicitly set
|
||||
@ -77,10 +81,10 @@ func GetCmdCreateAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
// Print random number, timestamp, and hash to user's console
|
||||
fmt.Printf("\nRandom number: %s\n", hex.EncodeToString(randomNumber.Bytes()))
|
||||
fmt.Printf("\nRandom number: %s\n", string(randomNumber[:]))
|
||||
fmt.Printf("Timestamp: %d\n", timestamp)
|
||||
fmt.Printf("Random number hash: %s\n\n", hex.EncodeToString(randomNumberHash))
|
||||
|
||||
@ -89,21 +93,14 @@ func GetCmdCreateAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
expectedIncome := args[5]
|
||||
|
||||
heightSpan, err := strconv.ParseInt(args[6], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
crossChain, err := strconv.ParseBool(args[7])
|
||||
heightSpan, err := strconv.ParseUint(args[5], 10, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := types.NewMsgCreateAtomicSwap(
|
||||
from, to, recipientOtherChain, senderOtherChain, randomNumberHash,
|
||||
timestamp, coins, expectedIncome, heightSpan, crossChain,
|
||||
from, to, recipientOtherChain, senderOtherChain,
|
||||
randomNumberHash, timestamp, coins, heightSpan,
|
||||
)
|
||||
|
||||
err = msg.ValidateBasic()
|
||||
@ -130,7 +127,7 @@ func GetCmdClaimAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
||||
|
||||
from := cliCtx.GetFromAddress()
|
||||
|
||||
swapID, err := types.HexToBytes(args[0])
|
||||
swapID, err := hex.DecodeString(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -138,11 +135,7 @@ func GetCmdClaimAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
||||
if len(strings.TrimSpace(args[1])) == 0 {
|
||||
return fmt.Errorf("random-number cannot be empty")
|
||||
}
|
||||
|
||||
randomNumber, err := types.HexToBytes(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
randomNumber := []byte(args[1])
|
||||
|
||||
msg := types.NewMsgClaimAtomicSwap(from, swapID, randomNumber)
|
||||
|
||||
@ -170,7 +163,7 @@ func GetCmdRefundAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
||||
|
||||
from := cliCtx.GetFromAddress()
|
||||
|
||||
swapID, err := types.HexToBytes(args[0])
|
||||
swapID, err := hex.DecodeString(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -1,13 +1,15 @@
|
||||
package rest
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"strconv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
"github.com/kava-labs/kava/x/bep3/types"
|
||||
)
|
||||
@ -19,6 +21,7 @@ func registerQueryRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||
r.HandleFunc(fmt.Sprintf("/%s/swap/{%s}", types.ModuleName, restSwapID), queryAtomicSwapHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/%s/swaps", types.ModuleName), queryAtomicSwapsHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/%s/supply/{%s}", types.ModuleName, restDenom), queryAssetSupplyHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/%s/supplies", types.ModuleName), queryAssetSuppliesHandlerFn(cliCtx)).Methods("GET")
|
||||
r.HandleFunc(fmt.Sprintf("/%s/parameters", types.ModuleName), queryParamsHandlerFn(cliCtx)).Methods("GET")
|
||||
|
||||
}
|
||||
@ -38,7 +41,7 @@ func queryAtomicSwapHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
swapID, err := types.HexToBytes(vars[restSwapID])
|
||||
swapID, err := hex.DecodeString(vars[restSwapID])
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
@ -69,38 +72,75 @@ func queryAtomicSwapHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
// HTTP request handler to query list of atomic swaps filtered by optional params
|
||||
func queryAtomicSwapsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Parse the query height
|
||||
_, page, limit, err := rest.ParseHTTPArgsWithLimit(r, 0)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryGetAtomicSwaps)
|
||||
var (
|
||||
involveAddr sdk.AccAddress
|
||||
expiration uint64
|
||||
swapStatus types.SwapStatus
|
||||
swapDirection types.SwapDirection
|
||||
)
|
||||
|
||||
res, height, err := cliCtx.QueryWithData(route, nil)
|
||||
if x := r.URL.Query().Get(RestInvolve); len(x) != 0 {
|
||||
involveAddr, err = sdk.AccAddressFromBech32(x)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if x := r.URL.Query().Get(RestExpiration); len(x) != 0 {
|
||||
expiration, err = strconv.ParseUint(x, 10, 64)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if x := r.URL.Query().Get(RestStatus); len(x) != 0 {
|
||||
swapStatus = types.NewSwapStatusFromString(x)
|
||||
if !swapStatus.IsValid() {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("invalid swap status %s", swapStatus))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if x := r.URL.Query().Get(RestDirection); len(x) != 0 {
|
||||
swapDirection = types.NewSwapDirectionFromString(x)
|
||||
if !swapDirection.IsValid() {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("invalid swap direction %s", swapDirection))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
params := types.NewQueryAtomicSwaps(page, limit, involveAddr, expiration, swapStatus, swapDirection)
|
||||
bz, err := cliCtx.Codec.MarshalJSON(params)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s", types.QuerierRoute, types.QueryGetAtomicSwaps)
|
||||
res, height, err := cliCtx.QueryWithData(route, bz)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Decode and return results
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
|
||||
var swaps types.AtomicSwaps
|
||||
err = cliCtx.Codec.UnmarshalJSON(res, &swaps)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusNotFound, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// using empty slice so json returns [] instead of null when there's no swaps
|
||||
sliceSwaps := types.AtomicSwaps{}
|
||||
for _, s := range swaps {
|
||||
sliceSwaps = append(sliceSwaps, s)
|
||||
}
|
||||
rest.PostProcessResponse(w, cliCtx, cliCtx.Codec.MustMarshalJSON(sliceSwaps))
|
||||
rest.PostProcessResponse(w, cliCtx, res)
|
||||
}
|
||||
}
|
||||
|
||||
@ -143,6 +183,41 @@ func queryAssetSupplyHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func queryAssetSuppliesHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
// Parse the query height
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
route := fmt.Sprintf("custom/%s/%s", types.ModuleName, types.QueryGetAssetSupplies)
|
||||
|
||||
res, height, err := cliCtx.QueryWithData(route, nil)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// Decode and return results
|
||||
cliCtx = cliCtx.WithHeight(height)
|
||||
|
||||
var supplies types.AssetSupplies
|
||||
err = cliCtx.Codec.UnmarshalJSON(res, &supplies)
|
||||
if err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusNotFound, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// using empty slice so json returns [] instead of null when there's no swaps
|
||||
sliceSupplies := types.AssetSupplies{}
|
||||
for _, s := range supplies {
|
||||
sliceSupplies = append(sliceSupplies, s)
|
||||
}
|
||||
rest.PostProcessResponse(w, cliCtx, cliCtx.Codec.MustMarshalJSON(sliceSupplies))
|
||||
}
|
||||
}
|
||||
|
||||
func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||
|
@ -10,6 +10,15 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
)
|
||||
|
||||
// REST Variable names
|
||||
// nolint
|
||||
const (
|
||||
RestExpiration = "expiration"
|
||||
RestInvolve = "involve"
|
||||
RestStatus = "status"
|
||||
RestDirection = "direction"
|
||||
)
|
||||
|
||||
// RegisterRoutes registers bep3-related REST handlers to a router
|
||||
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||
registerQueryRoutes(cliCtx, r)
|
||||
@ -26,8 +35,7 @@ type PostCreateSwapReq struct {
|
||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
|
||||
HeightSpan int64 `json:"height_span" yaml:"height_span"`
|
||||
HeightSpan uint64 `json:"height_span" yaml:"height_span"`
|
||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||
}
|
||||
|
||||
|
@ -41,9 +41,7 @@ func postCreateHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||
req.RandomNumberHash,
|
||||
req.Timestamp,
|
||||
req.Amount,
|
||||
req.ExpectedIncome,
|
||||
req.HeightSpan,
|
||||
req.CrossChain,
|
||||
)
|
||||
if err := msg.ValidateBasic(); err != nil {
|
||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||
|
@ -37,8 +37,8 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper
|
||||
if !found {
|
||||
panic(fmt.Sprintf("invalid asset supply: %s is not a supported asset", coin.Denom))
|
||||
}
|
||||
if !coin.Limit.Equal(supply.Limit.Amount) {
|
||||
panic(fmt.Sprintf("supported asset limit %s does not equal asset supply %s", coin.Limit, supply.Limit.Amount))
|
||||
if !coin.Limit.Equal(supply.SupplyLimit.Amount) {
|
||||
panic(fmt.Sprintf("supported asset limit %s does not equal asset supply %s", coin.Limit, supply.SupplyLimit.Amount))
|
||||
}
|
||||
|
||||
// Increment current, incoming, and outgoing asset supplies
|
||||
|
@ -89,7 +89,7 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
||||
IncomingSupply: c("bnb", 0),
|
||||
OutgoingSupply: c("bnb", 0),
|
||||
CurrentSupply: c("bnb", assetParam.Limit.Add(i(1)).Int64()),
|
||||
Limit: c("bnb", assetParam.Limit.Int64()),
|
||||
SupplyLimit: c("bnb", assetParam.Limit.Int64()),
|
||||
},
|
||||
}
|
||||
return app.GenesisState{"bep3": bep3.ModuleCdc.MustMarshalJSON(gs)}
|
||||
@ -108,9 +108,9 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||
timestamp := ts(0)
|
||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
swap := bep3.NewAtomicSwap(cs(c("bnb", overLimitAmount.Int64())), randomNumberHash,
|
||||
int64(360), timestamp, suite.addrs[0], addrs[1], TestSenderOtherChain,
|
||||
uint64(360), timestamp, suite.addrs[0], addrs[1], TestSenderOtherChain,
|
||||
TestRecipientOtherChain, 0, bep3.Open, true, bep3.Incoming)
|
||||
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
||||
|
||||
@ -121,7 +121,7 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
||||
IncomingSupply: c("bnb", assetParam.Limit.Add(i(1)).Int64()),
|
||||
OutgoingSupply: c("bnb", 0),
|
||||
CurrentSupply: c("bnb", 0),
|
||||
Limit: c("bnb", assetParam.Limit.Int64()),
|
||||
SupplyLimit: c("bnb", assetParam.Limit.Int64()),
|
||||
},
|
||||
}
|
||||
return app.GenesisState{"bep3": bep3.ModuleCdc.MustMarshalJSON(gs)}
|
||||
@ -141,9 +141,9 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||
timestamp := ts(0)
|
||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
swap := bep3.NewAtomicSwap(cs(c("bnb", halfLimit)), randomNumberHash,
|
||||
int64(360), timestamp, suite.addrs[0], addrs[1], TestSenderOtherChain,
|
||||
uint64(360), timestamp, suite.addrs[0], addrs[1], TestSenderOtherChain,
|
||||
TestRecipientOtherChain, 0, bep3.Open, true, bep3.Incoming)
|
||||
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
||||
|
||||
@ -154,7 +154,7 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
||||
IncomingSupply: c("bnb", halfLimit),
|
||||
OutgoingSupply: c("bnb", 0),
|
||||
CurrentSupply: c("bnb", overHalfLimit),
|
||||
Limit: c("bnb", assetParam.Limit.Int64()),
|
||||
SupplyLimit: c("bnb", assetParam.Limit.Int64()),
|
||||
},
|
||||
}
|
||||
return app.GenesisState{"bep3": bep3.ModuleCdc.MustMarshalJSON(gs)}
|
||||
@ -171,7 +171,7 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
||||
IncomingSupply: c("fake", 0),
|
||||
OutgoingSupply: c("fake", 0),
|
||||
CurrentSupply: c("fake", 0),
|
||||
Limit: c("fake", StandardSupplyLimit.Int64()),
|
||||
SupplyLimit: c("fake", StandardSupplyLimit.Int64()),
|
||||
},
|
||||
}
|
||||
return app.GenesisState{"bep3": bep3.ModuleCdc.MustMarshalJSON(gs)}
|
||||
@ -185,9 +185,9 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||
timestamp := ts(0)
|
||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
swap := bep3.NewAtomicSwap(cs(c("fake", 500000)), randomNumberHash,
|
||||
int64(360), timestamp, suite.addrs[0], addrs[1], TestSenderOtherChain,
|
||||
uint64(360), timestamp, suite.addrs[0], addrs[1], TestSenderOtherChain,
|
||||
TestRecipientOtherChain, 0, bep3.Open, true, bep3.Incoming)
|
||||
|
||||
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
||||
@ -202,9 +202,9 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
||||
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||
timestamp := ts(0)
|
||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
swap := bep3.NewAtomicSwap(cs(c("bnb", 5000)), randomNumberHash,
|
||||
int64(360), timestamp, suite.addrs[0], addrs[1], TestSenderOtherChain,
|
||||
uint64(360), timestamp, suite.addrs[0], addrs[1], TestSenderOtherChain,
|
||||
TestRecipientOtherChain, 0, bep3.NULL, true, bep3.Incoming)
|
||||
|
||||
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
||||
|
@ -25,7 +25,7 @@ func NewHandler(k Keeper) sdk.Handler {
|
||||
// handleMsgCreateAtomicSwap handles requests to create a new AtomicSwap
|
||||
func handleMsgCreateAtomicSwap(ctx sdk.Context, k Keeper, msg MsgCreateAtomicSwap) (*sdk.Result, error) {
|
||||
err := k.CreateAtomicSwap(ctx, msg.RandomNumberHash, msg.Timestamp, msg.HeightSpan, msg.From, msg.To,
|
||||
msg.SenderOtherChain, msg.RecipientOtherChain, msg.Amount, msg.ExpectedIncome, msg.CrossChain)
|
||||
msg.SenderOtherChain, msg.RecipientOtherChain, msg.Amount, true)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -47,31 +47,32 @@ func (suite *HandlerTestSuite) SetupTest() {
|
||||
}
|
||||
|
||||
func (suite *HandlerTestSuite) AddAtomicSwap() (tmbytes.HexBytes, tmbytes.HexBytes) {
|
||||
expireHeight := int64(360)
|
||||
expireHeight := uint64(360)
|
||||
amount := cs(c("bnb", int64(50000)))
|
||||
timestamp := ts(0)
|
||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
// Create atomic swap and check err to confirm creation
|
||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, randomNumberHash, timestamp, expireHeight,
|
||||
suite.addrs[0], suite.addrs[1], TestSenderOtherChain, TestRecipientOtherChain,
|
||||
amount, amount.String(), true)
|
||||
amount, true)
|
||||
suite.Nil(err)
|
||||
|
||||
swapID := bep3.CalculateSwapID(randomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
||||
return swapID, randomNumber.Bytes()
|
||||
return swapID, randomNumber[:]
|
||||
}
|
||||
|
||||
func (suite *HandlerTestSuite) TestMsgCreateAtomicSwap() {
|
||||
amount := cs(c("bnb", int64(10000)))
|
||||
timestamp := ts(0)
|
||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
msg := bep3.NewMsgCreateAtomicSwap(
|
||||
suite.addrs[0], suite.addrs[2], TestRecipientOtherChain, TestSenderOtherChain,
|
||||
randomNumberHash, timestamp, amount, amount.String(), int64(300), true)
|
||||
suite.addrs[0], suite.addrs[2], TestRecipientOtherChain,
|
||||
TestSenderOtherChain, randomNumberHash, timestamp, amount,
|
||||
uint64(300))
|
||||
|
||||
res, err := suite.handler(suite.ctx, msg)
|
||||
suite.Require().NoError(err)
|
||||
@ -81,9 +82,9 @@ func (suite *HandlerTestSuite) TestMsgCreateAtomicSwap() {
|
||||
func (suite *HandlerTestSuite) TestMsgClaimAtomicSwap() {
|
||||
// Attempt claim msg on fake atomic swap
|
||||
badRandomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber.Bytes(), ts(0))
|
||||
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber[:], ts(0))
|
||||
badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
||||
badMsg := bep3.NewMsgClaimAtomicSwap(suite.addrs[0], badSwapID, badRandomNumber.Bytes())
|
||||
badMsg := bep3.NewMsgClaimAtomicSwap(suite.addrs[0], badSwapID, badRandomNumber[:])
|
||||
badRes, err := suite.handler(suite.ctx, badMsg)
|
||||
suite.Require().Error(err)
|
||||
suite.Require().Nil(badRes)
|
||||
@ -99,7 +100,7 @@ func (suite *HandlerTestSuite) TestMsgClaimAtomicSwap() {
|
||||
func (suite *HandlerTestSuite) TestMsgRefundAtomicSwap() {
|
||||
// Attempt refund msg on fake atomic swap
|
||||
badRandomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber.Bytes(), ts(0))
|
||||
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber[:], ts(0))
|
||||
badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
||||
badMsg := bep3.NewMsgRefundAtomicSwap(suite.addrs[0], badSwapID)
|
||||
badRes, err := suite.handler(suite.ctx, badMsg)
|
||||
|
@ -73,10 +73,10 @@ func baseGenState(deputy sdk.AccAddress) bep3.GenesisState {
|
||||
|
||||
func loadSwapAndSupply(addr sdk.AccAddress, index int) (bep3.AtomicSwap, bep3.AssetSupply) {
|
||||
coin := c(DenomMap[index], 50000)
|
||||
expireOffset := int64((index * 15) + 360) // Default expire height + offet to match timestamp
|
||||
expireOffset := uint64((index * 15) + 360) // Default expire height + offet to match timestamp
|
||||
timestamp := ts(index) // One minute apart
|
||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
swap := bep3.NewAtomicSwap(cs(coin), randomNumberHash,
|
||||
expireOffset, timestamp, addr, addr, TestSenderOtherChain,
|
||||
TestRecipientOtherChain, 1, bep3.Open, true, bep3.Incoming)
|
||||
|
@ -15,8 +15,8 @@ func (k Keeper) IncrementCurrentAssetSupply(ctx sdk.Context, coin sdk.Coin) erro
|
||||
}
|
||||
|
||||
// Resulting current supply must be under asset's limit
|
||||
if !supply.Limit.IsGTE(supply.CurrentSupply.Add(coin)) {
|
||||
return sdkerrors.Wrapf(types.ErrExceedsSupplyLimit, "increase %s, asset supply %s, limit %s", coin, supply.CurrentSupply, supply.Limit)
|
||||
if !supply.SupplyLimit.IsGTE(supply.CurrentSupply.Add(coin)) {
|
||||
return sdkerrors.Wrapf(types.ErrExceedsSupplyLimit, "increase %s, asset supply %s, limit %s", coin, supply.CurrentSupply, supply.SupplyLimit)
|
||||
}
|
||||
|
||||
supply.CurrentSupply = supply.CurrentSupply.Add(coin)
|
||||
@ -51,8 +51,8 @@ func (k Keeper) IncrementIncomingAssetSupply(ctx sdk.Context, coin sdk.Coin) err
|
||||
|
||||
// Result of (current + incoming + amount) must be under asset's limit
|
||||
totalSupply := supply.CurrentSupply.Add(supply.IncomingSupply)
|
||||
if !supply.Limit.IsGTE(totalSupply.Add(coin)) {
|
||||
return sdkerrors.Wrapf(types.ErrExceedsSupplyLimit, "increase %s, asset supply %s, limit %s", coin, totalSupply, supply.Limit)
|
||||
if !supply.SupplyLimit.IsGTE(totalSupply.Add(coin)) {
|
||||
return sdkerrors.Wrapf(types.ErrExceedsSupplyLimit, "increase %s, asset supply %s, limit %s", coin, totalSupply, supply.SupplyLimit)
|
||||
}
|
||||
|
||||
supply.IncomingSupply = supply.IncomingSupply.Add(coin)
|
||||
|
@ -43,7 +43,7 @@ func (suite *AssetTestSuite) SetupTest() {
|
||||
IncomingSupply: c("bnb", 5),
|
||||
OutgoingSupply: c("bnb", 5),
|
||||
CurrentSupply: c("bnb", 40),
|
||||
Limit: c("bnb", 50),
|
||||
SupplyLimit: c("bnb", 50),
|
||||
}
|
||||
keeper.SetAssetSupply(ctx, supply, []byte(supply.Denom))
|
||||
|
||||
|
@ -66,13 +66,13 @@ func atomicSwaps(ctx sdk.Context, count int) types.AtomicSwaps {
|
||||
}
|
||||
|
||||
func atomicSwap(ctx sdk.Context, index int) types.AtomicSwap {
|
||||
expireOffset := int64((index * 15) + 360) // Default expire height + offet to match timestamp
|
||||
expireOffset := uint64((index * 15) + 360) // Default expire height + offet to match timestamp
|
||||
timestamp := ts(index) // One minute apart
|
||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
return types.NewAtomicSwap(cs(c("bnb", 50000)), randomNumberHash,
|
||||
ctx.BlockHeight()+expireOffset, timestamp, TestUser1, TestUser2,
|
||||
uint64(ctx.BlockHeight())+expireOffset, timestamp, TestUser1, TestUser2,
|
||||
TestSenderOtherChain, TestRecipientOtherChain, 0, types.Open, true,
|
||||
types.Incoming)
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ func (k Keeper) IterateAtomicSwapsByBlock(ctx sdk.Context, inclusiveCutoffTime u
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapByBlockPrefix)
|
||||
iterator := store.Iterator(
|
||||
nil, // start at the very start of the prefix store
|
||||
sdk.PrefixEndBytes(types.Uint64ToBytes(inclusiveCutoffTime)), // end of range
|
||||
sdk.PrefixEndBytes(sdk.Uint64ToBigEndian(inclusiveCutoffTime)), // end of range
|
||||
)
|
||||
|
||||
defer iterator.Close()
|
||||
@ -146,15 +146,15 @@ func (k Keeper) IterateAtomicSwapsByBlock(ctx sdk.Context, inclusiveCutoffTime u
|
||||
// Completed swaps are stored for 1 week.
|
||||
func (k Keeper) InsertIntoLongtermStorage(ctx sdk.Context, atomicSwap types.AtomicSwap) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapLongtermStoragePrefix)
|
||||
store.Set(types.GetAtomicSwapByHeightKey(atomicSwap.ClosedBlock+types.DefaultLongtermStorageDuration,
|
||||
atomicSwap.GetSwapID()), atomicSwap.GetSwapID())
|
||||
deletionHeight := uint64(atomicSwap.ClosedBlock) + types.DefaultLongtermStorageDuration
|
||||
store.Set(types.GetAtomicSwapByHeightKey(deletionHeight, atomicSwap.GetSwapID()), atomicSwap.GetSwapID())
|
||||
}
|
||||
|
||||
// RemoveFromLongtermStorage removes a swap from the into the longterm storage index
|
||||
func (k Keeper) RemoveFromLongtermStorage(ctx sdk.Context, atomicSwap types.AtomicSwap) {
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapLongtermStoragePrefix)
|
||||
store.Delete(types.GetAtomicSwapByHeightKey(atomicSwap.ClosedBlock+types.DefaultLongtermStorageDuration,
|
||||
atomicSwap.GetSwapID()))
|
||||
deletionHeight := uint64(atomicSwap.ClosedBlock) + types.DefaultLongtermStorageDuration
|
||||
store.Delete(types.GetAtomicSwapByHeightKey(deletionHeight, atomicSwap.GetSwapID()))
|
||||
}
|
||||
|
||||
// IterateAtomicSwapsLongtermStorage provides an iterator over AtomicSwaps ordered by deletion height.
|
||||
@ -164,7 +164,7 @@ func (k Keeper) IterateAtomicSwapsLongtermStorage(ctx sdk.Context, inclusiveCuto
|
||||
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapLongtermStoragePrefix)
|
||||
iterator := store.Iterator(
|
||||
nil, // start at the very start of the prefix store
|
||||
sdk.PrefixEndBytes(types.Uint64ToBytes(inclusiveCutoffTime)), // end of range
|
||||
sdk.PrefixEndBytes(sdk.Uint64ToBigEndian(inclusiveCutoffTime)), // end of range
|
||||
)
|
||||
|
||||
defer iterator.Close()
|
||||
|
@ -122,7 +122,7 @@ func (suite *KeeperTestSuite) TestInsertIntoByBlockIndex() {
|
||||
|
||||
// Block index lacks getter methods, must use iteration to get count of swaps in store
|
||||
var swapIDs [][]byte
|
||||
suite.keeper.IterateAtomicSwapsByBlock(suite.ctx, uint64(atomicSwap.ExpireHeight+1), func(id []byte) bool {
|
||||
suite.keeper.IterateAtomicSwapsByBlock(suite.ctx, atomicSwap.ExpireHeight+1, func(id []byte) bool {
|
||||
swapIDs = append(swapIDs, id)
|
||||
return false
|
||||
})
|
||||
@ -145,7 +145,7 @@ func (suite *KeeperTestSuite) TestRemoveFromByBlockIndex() {
|
||||
|
||||
// Check stored data in block index
|
||||
var swapIDsPre [][]byte
|
||||
suite.keeper.IterateAtomicSwapsByBlock(suite.ctx, uint64(atomicSwap.ExpireHeight+1), func(id []byte) bool {
|
||||
suite.keeper.IterateAtomicSwapsByBlock(suite.ctx, atomicSwap.ExpireHeight+1, func(id []byte) bool {
|
||||
swapIDsPre = append(swapIDsPre, id)
|
||||
return false
|
||||
})
|
||||
@ -155,7 +155,7 @@ func (suite *KeeperTestSuite) TestRemoveFromByBlockIndex() {
|
||||
|
||||
// Check stored data not in block index
|
||||
var swapIDsPost [][]byte
|
||||
suite.keeper.IterateAtomicSwapsByBlock(suite.ctx, uint64(atomicSwap.ExpireHeight+1), func(id []byte) bool {
|
||||
suite.keeper.IterateAtomicSwapsByBlock(suite.ctx, atomicSwap.ExpireHeight+1, func(id []byte) bool {
|
||||
swapIDsPost = append(swapIDsPost, id)
|
||||
return false
|
||||
})
|
||||
@ -178,10 +178,10 @@ func (suite *KeeperTestSuite) TestIterateAtomicSwapsByBlock() {
|
||||
// Initialize a new atomic swap (different randomNumberHash = different swap IDs)
|
||||
timestamp := tmtime.Now().Add(time.Duration(i) * time.Minute).Unix()
|
||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
atomicSwap := types.NewAtomicSwap(cs(c("bnb", 50000)), randomNumberHash,
|
||||
blockCtx.BlockHeight(), timestamp, TestUser1, TestUser2,
|
||||
uint64(blockCtx.BlockHeight()), timestamp, TestUser1, TestUser2,
|
||||
TestSenderOtherChain, TestRecipientOtherChain, 0, types.Open,
|
||||
true, types.Incoming)
|
||||
|
||||
@ -269,10 +269,10 @@ func (suite *KeeperTestSuite) TestIterateAtomicSwapsLongtermStorage() {
|
||||
for i := 0; i < 8; i++ {
|
||||
timestamp := tmtime.Now().Unix()
|
||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
atomicSwap := types.NewAtomicSwap(cs(c("bnb", 50000)), randomNumberHash,
|
||||
suite.ctx.BlockHeight(), timestamp, TestUser1, TestUser2,
|
||||
uint64(suite.ctx.BlockHeight()), timestamp, TestUser1, TestUser2,
|
||||
TestSenderOtherChain, TestRecipientOtherChain, 100, types.Open,
|
||||
true, types.Incoming)
|
||||
|
||||
|
@ -25,13 +25,13 @@ func (k Keeper) GetBnbDeputyAddress(ctx sdk.Context) sdk.AccAddress {
|
||||
}
|
||||
|
||||
// GetMaxBlockLock returns the maximum block lock
|
||||
func (k Keeper) GetMaxBlockLock(ctx sdk.Context) int64 {
|
||||
func (k Keeper) GetMaxBlockLock(ctx sdk.Context) uint64 {
|
||||
params := k.GetParams(ctx)
|
||||
return params.MaxBlockLock
|
||||
}
|
||||
|
||||
// GetMinBlockLock returns the minimum block lock
|
||||
func (k Keeper) GetMinBlockLock(ctx sdk.Context) int64 {
|
||||
func (k Keeper) GetMinBlockLock(ctx sdk.Context) uint64 {
|
||||
params := k.GetParams(ctx)
|
||||
return params.MinBlockLock
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package keeper
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
@ -16,6 +17,8 @@ func NewQuerier(keeper Keeper) sdk.Querier {
|
||||
switch path[0] {
|
||||
case types.QueryGetAssetSupply:
|
||||
return queryAssetSupply(ctx, req, keeper)
|
||||
case types.QueryGetAssetSupplies:
|
||||
return queryAssetSupplies(ctx, req, keeper)
|
||||
case types.QueryGetAtomicSwap:
|
||||
return queryAtomicSwap(ctx, req, keeper)
|
||||
case types.QueryGetAtomicSwaps:
|
||||
@ -50,6 +53,20 @@ func queryAssetSupply(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]
|
||||
return bz, nil
|
||||
}
|
||||
|
||||
func queryAssetSupplies(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (res []byte, err error) {
|
||||
assets := keeper.GetAllAssetSupplies(ctx)
|
||||
if assets == nil {
|
||||
assets = types.AssetSupplies{}
|
||||
}
|
||||
|
||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, assets)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
|
||||
}
|
||||
|
||||
return bz, nil
|
||||
}
|
||||
|
||||
func queryAtomicSwap(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
|
||||
// Decode request
|
||||
var requestParams types.QueryAtomicSwapByID
|
||||
@ -73,16 +90,21 @@ func queryAtomicSwap(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]b
|
||||
return bz, nil
|
||||
}
|
||||
|
||||
func queryAtomicSwaps(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (res []byte, err error) {
|
||||
var swaps types.AtomicSwaps
|
||||
func queryAtomicSwaps(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
|
||||
var params types.QueryAtomicSwaps
|
||||
err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
|
||||
}
|
||||
|
||||
keeper.IterateAtomicSwaps(ctx, func(s types.AtomicSwap) bool {
|
||||
swaps = append(swaps, s)
|
||||
return false
|
||||
})
|
||||
unfilteredSwaps := keeper.GetAllAtomicSwaps(ctx)
|
||||
swaps := filterAtomicSwaps(ctx, unfilteredSwaps, params)
|
||||
if swaps == nil {
|
||||
swaps = types.AtomicSwaps{}
|
||||
}
|
||||
|
||||
bz, err2 := codec.MarshalJSONIndent(types.ModuleCdc, swaps)
|
||||
if err2 != nil {
|
||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, swaps)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
|
||||
}
|
||||
|
||||
@ -101,3 +123,46 @@ func queryGetParams(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]by
|
||||
}
|
||||
return bz, nil
|
||||
}
|
||||
|
||||
// getAtomicSwapsFiltered retrieves atomic swaps filtered by a given set of params.
|
||||
// If no filters are provided, all atomic swaps will be returned in paginated form.
|
||||
func filterAtomicSwaps(ctx sdk.Context, swaps types.AtomicSwaps, params types.QueryAtomicSwaps) types.AtomicSwaps {
|
||||
filteredSwaps := make(types.AtomicSwaps, 0, len(swaps))
|
||||
|
||||
for _, s := range swaps {
|
||||
matchInvolve, matchExpiration, matchStatus, matchDirection := true, true, true, true
|
||||
|
||||
// match involved address (if supplied)
|
||||
if len(params.Involve) > 0 {
|
||||
matchInvolve = s.Sender.Equals(params.Involve) || s.Recipient.Equals(params.Involve)
|
||||
}
|
||||
|
||||
// match expiration block limit (if supplied)
|
||||
if params.Expiration > 0 {
|
||||
matchExpiration = s.ExpireHeight <= params.Expiration
|
||||
}
|
||||
|
||||
// match status (if supplied/valid)
|
||||
if params.Status.IsValid() {
|
||||
matchStatus = s.Status == params.Status
|
||||
}
|
||||
|
||||
// match direction (if supplied/valid)
|
||||
if params.Direction.IsValid() {
|
||||
matchDirection = s.Direction == params.Direction
|
||||
}
|
||||
|
||||
if matchInvolve && matchExpiration && matchStatus && matchDirection {
|
||||
filteredSwaps = append(filteredSwaps, s)
|
||||
}
|
||||
}
|
||||
|
||||
start, end := client.Paginate(len(filteredSwaps), params.Page, params.Limit, 100)
|
||||
if start < 0 || end < 0 {
|
||||
filteredSwaps = types.AtomicSwaps{}
|
||||
} else {
|
||||
filteredSwaps = filteredSwaps[start:end]
|
||||
}
|
||||
|
||||
return filteredSwaps
|
||||
}
|
||||
|
@ -62,16 +62,15 @@ func (suite *QuerierTestSuite) SetupTest() {
|
||||
isSwapID := make(map[string]bool)
|
||||
for i := 0; i < 10; i++ {
|
||||
// Set up atomic swap variables
|
||||
expireHeight := int64(360)
|
||||
expireHeight := uint64(360)
|
||||
amount := cs(c("bnb", 100))
|
||||
timestamp := ts(0)
|
||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
// Create atomic swap and check err
|
||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, randomNumberHash, timestamp, expireHeight,
|
||||
addrs[0], suite.addrs[i], TestSenderOtherChain, TestRecipientOtherChain, amount,
|
||||
amount.String(), true)
|
||||
addrs[0], suite.addrs[i], TestSenderOtherChain, TestRecipientOtherChain, amount, true)
|
||||
suite.Nil(err)
|
||||
|
||||
// Calculate swap ID and save
|
||||
@ -129,12 +128,33 @@ func (suite *QuerierTestSuite) TestQueryAtomicSwap() {
|
||||
suite.True(suite.isSwapID[hex.EncodeToString(swap.GetSwapID())])
|
||||
}
|
||||
|
||||
func (suite *QuerierTestSuite) TestQueryAssetSupplies() {
|
||||
ctx := suite.ctx.WithIsCheckTx(false)
|
||||
// Set up request query
|
||||
query := abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetAssetSupplies}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryAssetSupplies(1, 100)),
|
||||
}
|
||||
|
||||
bz, err := suite.querier(ctx, []string{types.QueryGetAssetSupplies}, query)
|
||||
suite.Nil(err)
|
||||
suite.NotNil(bz)
|
||||
|
||||
var supplies types.AssetSupplies
|
||||
suite.Nil(types.ModuleCdc.UnmarshalJSON(bz, &supplies))
|
||||
|
||||
// Check that returned value matches asset supplies in state
|
||||
storeSupplies := suite.keeper.GetAllAssetSupplies(ctx)
|
||||
suite.Equal(len(storeSupplies), len(supplies))
|
||||
suite.Equal(supplies, storeSupplies)
|
||||
}
|
||||
|
||||
func (suite *QuerierTestSuite) TestQueryAtomicSwaps() {
|
||||
ctx := suite.ctx.WithIsCheckTx(false)
|
||||
// Set up request query
|
||||
query := abci.RequestQuery{
|
||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetAtomicSwaps}, "/"),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryAtomicSwaps(1, 100)),
|
||||
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryAtomicSwaps(1, 100, sdk.AccAddress{}, 0, types.Open, types.Incoming)),
|
||||
}
|
||||
|
||||
bz, err := suite.querier(ctx, []string{types.QueryGetAtomicSwaps}, query)
|
||||
|
@ -12,10 +12,10 @@ import (
|
||||
"github.com/kava-labs/kava/x/bep3/types"
|
||||
)
|
||||
|
||||
// CreateAtomicSwap creates a new AtomicSwap
|
||||
func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, timestamp int64, heightSpan int64,
|
||||
// CreateAtomicSwap creates a new atomic swap.
|
||||
func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, timestamp int64, heightSpan uint64,
|
||||
sender sdk.AccAddress, recipient sdk.AccAddress, senderOtherChain, recipientOtherChain string,
|
||||
amount sdk.Coins, expectedIncome string, crossChain bool) error {
|
||||
amount sdk.Coins, crossChain bool) error {
|
||||
// Confirm that this is not a duplicate swap
|
||||
swapID := types.CalculateSwapID(randomNumberHash, sender, senderOtherChain)
|
||||
_, found := k.GetAtomicSwap(ctx, swapID)
|
||||
@ -80,10 +80,11 @@ func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, times
|
||||
}
|
||||
|
||||
// Store the details of the swap
|
||||
atomicSwap := types.NewAtomicSwap(amount, randomNumberHash, ctx.BlockHeight()+heightSpan,
|
||||
timestamp, sender, recipient, senderOtherChain, recipientOtherChain, 0, types.Open,
|
||||
crossChain, direction)
|
||||
expireHeight := uint64(ctx.BlockHeight()) + heightSpan
|
||||
atomicSwap := types.NewAtomicSwap(amount, randomNumberHash, expireHeight, timestamp, sender,
|
||||
recipient, senderOtherChain, recipientOtherChain, 0, types.Open, crossChain, direction)
|
||||
|
||||
// Insert the atomic swap under both keys
|
||||
k.SetAtomicSwap(ctx, atomicSwap)
|
||||
k.InsertIntoByBlockIndex(ctx, atomicSwap)
|
||||
|
||||
@ -98,8 +99,7 @@ func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, times
|
||||
sdk.NewAttribute(types.AttributeKeyTimestamp, fmt.Sprintf("%d", atomicSwap.Timestamp)),
|
||||
sdk.NewAttribute(types.AttributeKeySenderOtherChain, atomicSwap.SenderOtherChain),
|
||||
sdk.NewAttribute(types.AttributeKeyExpireHeight, fmt.Sprintf("%d", atomicSwap.ExpireHeight)),
|
||||
sdk.NewAttribute(types.AttributeKeyAmount, atomicSwap.Amount[0].String()),
|
||||
sdk.NewAttribute(types.AttributeKeyExpectedIncome, expectedIncome),
|
||||
sdk.NewAttribute(types.AttributeKeyAmount, atomicSwap.Amount.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyDirection, atomicSwap.Direction.String()),
|
||||
),
|
||||
)
|
||||
@ -107,7 +107,7 @@ func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, times
|
||||
return nil
|
||||
}
|
||||
|
||||
// ClaimAtomicSwap validates a claim attempt, and if successful, sends the escrowed amount and closes the AtomicSwap
|
||||
// ClaimAtomicSwap validates a claim attempt, and if successful, sends the escrowed amount and closes the AtomicSwap.
|
||||
func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []byte, randomNumber []byte) error {
|
||||
atomicSwap, found := k.GetAtomicSwap(ctx, swapID)
|
||||
if !found {
|
||||
@ -116,7 +116,7 @@ func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []b
|
||||
|
||||
// Only open atomic swaps can be claimed
|
||||
if atomicSwap.Status != types.Open {
|
||||
return types.ErrSwapNotClaimable
|
||||
return sdkerrors.Wrapf(types.ErrSwapNotClaimable, "status %s", atomicSwap.Status.String())
|
||||
}
|
||||
|
||||
// Calculate hashed secret using submitted number
|
||||
@ -125,13 +125,13 @@ func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []b
|
||||
|
||||
// Confirm that secret unlocks the atomic swap
|
||||
if !bytes.Equal(hashedSecret, atomicSwap.GetSwapID()) {
|
||||
return sdkerrors.Wrapf(types.ErrInvalidClaimSecret, "%s ≠ %s", hex.EncodeToString(hashedSecret), hex.EncodeToString(atomicSwap.GetSwapID()))
|
||||
return sdkerrors.Wrapf(types.ErrInvalidClaimSecret, "the submitted random number is incorrect")
|
||||
}
|
||||
|
||||
var err error
|
||||
switch atomicSwap.Direction {
|
||||
case types.Incoming:
|
||||
err := k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
err = k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -175,14 +175,14 @@ func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []b
|
||||
sdk.NewAttribute(types.AttributeKeyRecipient, atomicSwap.Recipient.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, hex.EncodeToString(atomicSwap.GetSwapID())),
|
||||
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, hex.EncodeToString(atomicSwap.RandomNumberHash)),
|
||||
sdk.NewAttribute(types.AttributeKeyRandomNumber, hex.EncodeToString(randomNumber)),
|
||||
sdk.NewAttribute(types.AttributeKeyRandomNumber, string(randomNumber)),
|
||||
),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RefundAtomicSwap refunds an AtomicSwap, sending assets to the original sender and closing the AtomicSwap
|
||||
// RefundAtomicSwap refunds an AtomicSwap, sending assets to the original sender and closing the AtomicSwap.
|
||||
func (k Keeper) RefundAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []byte) error {
|
||||
atomicSwap, found := k.GetAtomicSwap(ctx, swapID)
|
||||
if !found {
|
||||
@ -190,7 +190,7 @@ func (k Keeper) RefundAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []
|
||||
}
|
||||
// Only expired swaps may be refunded
|
||||
if atomicSwap.Status != types.Expired {
|
||||
return types.ErrSwapNotRefundable
|
||||
return sdkerrors.Wrapf(types.ErrSwapNotRefundable, "status %s", atomicSwap.Status.String())
|
||||
}
|
||||
|
||||
var err error
|
||||
@ -225,10 +225,10 @@ func (k Keeper) RefundAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeRefundAtomicSwap,
|
||||
sdk.NewAttribute(types.AttributeKeyRefundSender, fmt.Sprintf("%s", from)),
|
||||
sdk.NewAttribute(types.AttributeKeySender, fmt.Sprintf("%s", atomicSwap.Sender)),
|
||||
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.GetSwapID()))),
|
||||
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.RandomNumberHash))),
|
||||
sdk.NewAttribute(types.AttributeKeyRefundSender, from.String()),
|
||||
sdk.NewAttribute(types.AttributeKeySender, atomicSwap.Sender.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, hex.EncodeToString(atomicSwap.GetSwapID())),
|
||||
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, hex.EncodeToString(atomicSwap.RandomNumberHash)),
|
||||
),
|
||||
)
|
||||
|
||||
@ -236,23 +236,23 @@ func (k Keeper) RefundAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []
|
||||
}
|
||||
|
||||
// UpdateExpiredAtomicSwaps finds all AtomicSwaps that are past (or at) their ending times and expires them.
|
||||
func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) error {
|
||||
var expiredSwaps [][]byte
|
||||
func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) {
|
||||
var expiredSwapIDs []string
|
||||
k.IterateAtomicSwapsByBlock(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
|
||||
expiredSwaps = append(expiredSwaps, id)
|
||||
atomicSwap, found := k.GetAtomicSwap(ctx, id)
|
||||
if !found {
|
||||
// NOTE: shouldn't happen. Continue to next item.
|
||||
return false
|
||||
}
|
||||
// Expire the uncompleted swap and update both indexes
|
||||
atomicSwap.Status = types.Expired
|
||||
// Note: claimed swaps have already been removed from byBlock index.
|
||||
k.RemoveFromByBlockIndex(ctx, atomicSwap)
|
||||
k.SetAtomicSwap(ctx, atomicSwap)
|
||||
expiredSwapIDs = append(expiredSwapIDs, hex.EncodeToString(atomicSwap.GetSwapID()))
|
||||
return false
|
||||
})
|
||||
|
||||
// Expire incomplete swaps (claimed swaps have already been removed from byBlock index)
|
||||
var expiredSwapIDs []string
|
||||
for _, id := range expiredSwaps {
|
||||
atomicSwap, _ := k.GetAtomicSwap(ctx, id)
|
||||
atomicSwap.Status = types.Expired
|
||||
k.SetAtomicSwap(ctx, atomicSwap)
|
||||
k.RemoveFromByBlockIndex(ctx, atomicSwap)
|
||||
expiredSwapIDs = append(expiredSwapIDs, hex.EncodeToString(atomicSwap.GetSwapID()))
|
||||
}
|
||||
|
||||
// Emit 'swaps_expired' event
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
@ -261,23 +261,18 @@ func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) error {
|
||||
sdk.NewAttribute(types.AttributeExpirationBlock, fmt.Sprintf("%d", ctx.BlockHeight())),
|
||||
),
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// DeleteClosedAtomicSwapsFromLongtermStorage removes swaps one week after completion
|
||||
func (k Keeper) DeleteClosedAtomicSwapsFromLongtermStorage(ctx sdk.Context) error {
|
||||
var swapsToDelete [][]byte
|
||||
// DeleteClosedAtomicSwapsFromLongtermStorage removes swaps one week after completion.
|
||||
func (k Keeper) DeleteClosedAtomicSwapsFromLongtermStorage(ctx sdk.Context) {
|
||||
k.IterateAtomicSwapsLongtermStorage(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
|
||||
swapsToDelete = append(swapsToDelete, id)
|
||||
swap, found := k.GetAtomicSwap(ctx, id)
|
||||
if !found {
|
||||
// NOTE: shouldn't happen. Continue to next item.
|
||||
return false
|
||||
})
|
||||
|
||||
// Delete closed atomic swaps
|
||||
for _, id := range swapsToDelete {
|
||||
swap, _ := k.GetAtomicSwap(ctx, id)
|
||||
}
|
||||
k.RemoveAtomicSwap(ctx, swap.GetSwapID())
|
||||
k.RemoveFromLongtermStorage(ctx, swap)
|
||||
}
|
||||
return nil
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -74,11 +73,11 @@ func (suite *AtomicSwapTestSuite) GenerateSwapDetails() {
|
||||
// Set up atomic swap details
|
||||
timestamp := ts(i)
|
||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
timestamps = append(timestamps, timestamp)
|
||||
randomNumberHashes = append(randomNumberHashes, randomNumberHash)
|
||||
randomNumbers = append(randomNumbers, randomNumber.Bytes())
|
||||
randomNumbers = append(randomNumbers, randomNumber[:])
|
||||
}
|
||||
suite.timestamps = timestamps
|
||||
suite.randomNumberHashes = randomNumberHashes
|
||||
@ -90,13 +89,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
type args struct {
|
||||
randomNumberHash []byte
|
||||
timestamp int64
|
||||
heightSpan int64
|
||||
heightSpan uint64
|
||||
sender sdk.AccAddress
|
||||
recipient sdk.AccAddress
|
||||
senderOtherChain string
|
||||
recipientOtherChain string
|
||||
coins sdk.Coins
|
||||
expectedIncome string
|
||||
crossChain bool
|
||||
direction types.SwapDirection
|
||||
}
|
||||
@ -113,13 +111,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
args{
|
||||
randomNumberHash: suite.randomNumberHashes[0],
|
||||
timestamp: suite.timestamps[0],
|
||||
heightSpan: int64(360),
|
||||
heightSpan: uint64(360),
|
||||
sender: suite.deputy,
|
||||
recipient: suite.addrs[1],
|
||||
senderOtherChain: TestSenderOtherChain,
|
||||
recipientOtherChain: TestRecipientOtherChain,
|
||||
coins: cs(c(BNB_DENOM, 50000)),
|
||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
||||
crossChain: true,
|
||||
direction: types.Incoming,
|
||||
},
|
||||
@ -132,13 +129,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
args{
|
||||
randomNumberHash: suite.randomNumberHashes[0],
|
||||
timestamp: suite.timestamps[0],
|
||||
heightSpan: int64(360),
|
||||
heightSpan: uint64(360),
|
||||
sender: suite.addrs[1],
|
||||
recipient: suite.addrs[2],
|
||||
senderOtherChain: TestSenderOtherChain,
|
||||
recipientOtherChain: TestRecipientOtherChain,
|
||||
coins: cs(c(BNB_DENOM, 50000)),
|
||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
||||
crossChain: true,
|
||||
direction: types.Outgoing,
|
||||
},
|
||||
@ -151,13 +147,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
args{
|
||||
randomNumberHash: suite.randomNumberHashes[1],
|
||||
timestamp: suite.timestamps[1],
|
||||
heightSpan: int64(360),
|
||||
heightSpan: uint64(360),
|
||||
sender: suite.deputy,
|
||||
recipient: suite.addrs[2],
|
||||
senderOtherChain: TestSenderOtherChain,
|
||||
recipientOtherChain: TestRecipientOtherChain,
|
||||
coins: cs(c("xyz", 50000)),
|
||||
expectedIncome: "50000xyz",
|
||||
crossChain: true,
|
||||
direction: types.Incoming,
|
||||
},
|
||||
@ -170,13 +165,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
args{
|
||||
randomNumberHash: suite.randomNumberHashes[2],
|
||||
timestamp: suite.timestamps[2] - 2000,
|
||||
heightSpan: int64(360),
|
||||
heightSpan: uint64(360),
|
||||
sender: suite.deputy,
|
||||
recipient: suite.addrs[3],
|
||||
senderOtherChain: TestSenderOtherChain,
|
||||
recipientOtherChain: TestRecipientOtherChain,
|
||||
coins: cs(c(BNB_DENOM, 50000)),
|
||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
||||
crossChain: true,
|
||||
direction: types.Incoming,
|
||||
},
|
||||
@ -189,13 +183,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
args{
|
||||
randomNumberHash: suite.randomNumberHashes[3],
|
||||
timestamp: suite.timestamps[3] + 5000,
|
||||
heightSpan: int64(360),
|
||||
heightSpan: uint64(360),
|
||||
sender: suite.deputy,
|
||||
recipient: suite.addrs[4],
|
||||
senderOtherChain: TestSenderOtherChain,
|
||||
recipientOtherChain: TestRecipientOtherChain,
|
||||
coins: cs(c(BNB_DENOM, 50000)),
|
||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
||||
crossChain: true,
|
||||
direction: types.Incoming,
|
||||
},
|
||||
@ -208,13 +201,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
args{
|
||||
randomNumberHash: suite.randomNumberHashes[4],
|
||||
timestamp: suite.timestamps[4],
|
||||
heightSpan: int64(5),
|
||||
heightSpan: uint64(5),
|
||||
sender: suite.deputy,
|
||||
recipient: suite.addrs[5],
|
||||
senderOtherChain: TestSenderOtherChain,
|
||||
recipientOtherChain: TestRecipientOtherChain,
|
||||
coins: cs(c(BNB_DENOM, 50000)),
|
||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
||||
crossChain: true,
|
||||
direction: types.Incoming,
|
||||
},
|
||||
@ -227,13 +219,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
args{
|
||||
randomNumberHash: suite.randomNumberHashes[5],
|
||||
timestamp: suite.timestamps[5],
|
||||
heightSpan: int64(1000000),
|
||||
heightSpan: uint64(1000000),
|
||||
sender: suite.deputy,
|
||||
recipient: suite.addrs[6],
|
||||
senderOtherChain: TestSenderOtherChain,
|
||||
recipientOtherChain: TestRecipientOtherChain,
|
||||
coins: cs(c(BNB_DENOM, 50000)),
|
||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
||||
crossChain: true,
|
||||
direction: types.Incoming,
|
||||
},
|
||||
@ -246,13 +237,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
args{
|
||||
randomNumberHash: suite.randomNumberHashes[6],
|
||||
timestamp: suite.timestamps[6],
|
||||
heightSpan: int64(360),
|
||||
heightSpan: uint64(360),
|
||||
sender: suite.deputy,
|
||||
recipient: suite.addrs[7],
|
||||
senderOtherChain: TestSenderOtherChain,
|
||||
recipientOtherChain: TestRecipientOtherChain,
|
||||
coins: cs(c(BNB_DENOM, 0)),
|
||||
expectedIncome: fmt.Sprintf("0%s", BNB_DENOM),
|
||||
crossChain: true,
|
||||
direction: types.Incoming,
|
||||
},
|
||||
@ -265,13 +255,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
args{
|
||||
randomNumberHash: suite.randomNumberHashes[0],
|
||||
timestamp: suite.timestamps[0],
|
||||
heightSpan: int64(360),
|
||||
heightSpan: uint64(360),
|
||||
sender: suite.deputy,
|
||||
recipient: suite.addrs[1],
|
||||
senderOtherChain: TestSenderOtherChain,
|
||||
recipientOtherChain: TestRecipientOtherChain,
|
||||
coins: cs(c(BNB_DENOM, 50000)),
|
||||
expectedIncome: "50000bnb",
|
||||
crossChain: true,
|
||||
direction: types.Incoming,
|
||||
},
|
||||
@ -305,7 +294,7 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
// Create atomic swap
|
||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, tc.args.randomNumberHash, tc.args.timestamp,
|
||||
tc.args.heightSpan, tc.args.sender, tc.args.recipient, tc.args.senderOtherChain,
|
||||
tc.args.recipientOtherChain, tc.args.coins, tc.args.expectedIncome, tc.args.crossChain)
|
||||
tc.args.recipientOtherChain, tc.args.coins, tc.args.crossChain)
|
||||
|
||||
// Load sender's account after swap creation
|
||||
senderAccPost := ak.GetAccount(suite.ctx, tc.args.sender)
|
||||
@ -341,7 +330,7 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
||||
types.AtomicSwap{
|
||||
Amount: tc.args.coins,
|
||||
RandomNumberHash: tc.args.randomNumberHash,
|
||||
ExpireHeight: suite.ctx.BlockHeight() + tc.args.heightSpan,
|
||||
ExpireHeight: uint64(suite.ctx.BlockHeight()) + tc.args.heightSpan,
|
||||
Timestamp: tc.args.timestamp,
|
||||
Sender: tc.args.sender,
|
||||
Recipient: tc.args.recipient,
|
||||
@ -419,7 +408,7 @@ func (suite *AtomicSwapTestSuite) TestClaimAtomicSwap() {
|
||||
suite.ctx,
|
||||
args{
|
||||
swapID: []byte{},
|
||||
randomNumber: invalidRandomNumber.Bytes(),
|
||||
randomNumber: invalidRandomNumber[:],
|
||||
direction: types.Incoming,
|
||||
},
|
||||
false,
|
||||
@ -462,8 +451,8 @@ func (suite *AtomicSwapTestSuite) TestClaimAtomicSwap() {
|
||||
|
||||
// Create atomic swap
|
||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, suite.randomNumberHashes[i], suite.timestamps[i],
|
||||
int64(360), sender, expectedRecipient, TestSenderOtherChain, TestRecipientOtherChain,
|
||||
expectedClaimAmount, expectedClaimAmount.String(), true)
|
||||
uint64(360), sender, expectedRecipient, TestSenderOtherChain, TestRecipientOtherChain,
|
||||
expectedClaimAmount, true)
|
||||
suite.NoError(err)
|
||||
|
||||
realSwapID := types.CalculateSwapID(suite.randomNumberHashes[i], sender, TestSenderOtherChain)
|
||||
@ -616,8 +605,8 @@ func (suite *AtomicSwapTestSuite) TestRefundAtomicSwap() {
|
||||
}
|
||||
|
||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, suite.randomNumberHashes[i], suite.timestamps[i],
|
||||
int64(360), sender, suite.addrs[8], TestSenderOtherChain, TestRecipientOtherChain,
|
||||
expectedRefundAmount, expectedRefundAmount.String(), true)
|
||||
uint64(360), sender, suite.addrs[8], TestSenderOtherChain, TestRecipientOtherChain,
|
||||
expectedRefundAmount, true)
|
||||
suite.NoError(err)
|
||||
|
||||
realSwapID := types.CalculateSwapID(suite.randomNumberHashes[i], sender, TestSenderOtherChain)
|
||||
|
@ -27,7 +27,7 @@ func TestDecodeDistributionStore(t *testing.T) {
|
||||
|
||||
oneCoin := sdk.NewCoin("coin", sdk.OneInt())
|
||||
swap := types.NewAtomicSwap(sdk.Coins{oneCoin}, nil, 10, 100, nil, nil, "otherChainSender", "otherChainRec", 200, types.Completed, true, types.Outgoing)
|
||||
supply := types.AssetSupply{Denom: "coin", IncomingSupply: oneCoin, OutgoingSupply: oneCoin, CurrentSupply: oneCoin, Limit: oneCoin}
|
||||
supply := types.AssetSupply{Denom: "coin", IncomingSupply: oneCoin, OutgoingSupply: oneCoin, CurrentSupply: oneCoin, SupplyLimit: oneCoin}
|
||||
bz := tmbytes.HexBytes([]byte{1, 2})
|
||||
|
||||
kvPairs := kv.Pairs{
|
||||
|
@ -37,17 +37,17 @@ func GenRandBnbDeputy(r *rand.Rand) simulation.Account {
|
||||
}
|
||||
|
||||
// GenMinBlockLock randomized MinBlockLock
|
||||
func GenMinBlockLock(r *rand.Rand) int64 {
|
||||
func GenMinBlockLock(r *rand.Rand) uint64 {
|
||||
min := int(types.AbsoluteMinimumBlockLock)
|
||||
max := int(types.AbsoluteMaximumBlockLock)
|
||||
return int64(r.Intn(max-min) + min)
|
||||
return uint64(r.Intn(max-min) + min)
|
||||
}
|
||||
|
||||
// GenMaxBlockLock randomized MaxBlockLock
|
||||
func GenMaxBlockLock(r *rand.Rand, minBlockLock int64) int64 {
|
||||
func GenMaxBlockLock(r *rand.Rand, minBlockLock uint64) uint64 {
|
||||
min := int(minBlockLock)
|
||||
max := int(types.AbsoluteMaximumBlockLock)
|
||||
return int64(r.Intn(max-min) + min)
|
||||
return uint64(r.Intn(max-min) + min)
|
||||
}
|
||||
|
||||
// GenSupportedAssets gets randomized SupportedAssets
|
||||
@ -101,7 +101,7 @@ func loadRandomBep3GenState(simState *module.SimulationState) types.GenesisState
|
||||
bnbDeputy := GenRandBnbDeputy(simState.Rand)
|
||||
|
||||
// min/max block lock are hardcoded to 50/100 for expected -NumBlocks=100
|
||||
minBlockLock := int64(types.AbsoluteMinimumBlockLock)
|
||||
minBlockLock := types.AbsoluteMinimumBlockLock
|
||||
maxBlockLock := minBlockLock * 2
|
||||
|
||||
var supportedAssets types.AssetParams
|
||||
|
@ -133,15 +133,13 @@ func SimulateMsgCreateAtomicSwap(ak types.AccountKeeper, k keeper.Keeper) simula
|
||||
return simulation.NewOperationMsgBasic(types.ModuleName, fmt.Sprintf("no-operation (all funds exhausted for asset %s)", denom), "", false, nil), nil, nil
|
||||
}
|
||||
coins := sdk.NewCoins(sdk.NewCoin(denom, amount))
|
||||
expectedIncome := coins.String()
|
||||
|
||||
// We're assuming that sims are run with -NumBlocks=100
|
||||
heightSpan := int64(55)
|
||||
crossChain := true
|
||||
heightSpan := uint64(55)
|
||||
|
||||
msg := types.NewMsgCreateAtomicSwap(
|
||||
sender.Address, recipient.Address, recipientOtherChain, senderOtherChain,
|
||||
randomNumberHash, timestamp, coins, expectedIncome, heightSpan, crossChain,
|
||||
randomNumberHash, timestamp, coins, heightSpan,
|
||||
)
|
||||
|
||||
tx := helpers.GenTx(
|
||||
@ -164,14 +162,14 @@ func SimulateMsgCreateAtomicSwap(ak types.AccountKeeper, k keeper.Keeper) simula
|
||||
swapID := types.CalculateSwapID(msg.RandomNumberHash, msg.From, msg.SenderOtherChain)
|
||||
if r.Intn(100) < 50 {
|
||||
// Claim future operation
|
||||
executionBlock := ctx.BlockHeight() + (msg.HeightSpan / 2)
|
||||
executionBlock := uint64(ctx.BlockHeight()) + msg.HeightSpan/2
|
||||
futureOp = simulation.FutureOperation{
|
||||
BlockHeight: int(executionBlock),
|
||||
Op: operationClaimAtomicSwap(ak, k, swapID, randomNumber.BigInt().Bytes()),
|
||||
}
|
||||
} else {
|
||||
// Refund future operation
|
||||
executionBlock := ctx.BlockHeight() + msg.HeightSpan
|
||||
executionBlock := uint64(ctx.BlockHeight()) + msg.HeightSpan
|
||||
futureOp = simulation.FutureOperation{
|
||||
BlockHeight: int(executionBlock),
|
||||
Op: operationRefundAtomicSwap(ak, k, swapID),
|
||||
|
@ -48,7 +48,6 @@ type AtomicSwap struct {
|
||||
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
|
||||
ClosedBlock int64 `json:"closed_block" yaml:"closed_block"`
|
||||
Status SwapStatus `json:"status" yaml:"status"`
|
||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||
Direction SwapDirection `json:"direction" yaml:"direction"`
|
||||
}
|
||||
|
||||
|
@ -14,9 +14,7 @@ type MsgCreateAtomicSwap struct {
|
||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
|
||||
HeightSpan int64 `json:"height_span" yaml:"height_span"`
|
||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -16,7 +16,6 @@ The `x/bep3` module emits the following events:
|
||||
| create_atomic_swap | sender_other_chain | {sender other chain} |
|
||||
| create_atomic_swap | expire_height | {swap expiration block} |
|
||||
| create_atomic_swap | amount | {coin amount} |
|
||||
| create_atomic_swap | expected_income | {expected value received}|
|
||||
| create_atomic_swap | direction | {incoming or outgoing} |
|
||||
| message | module | bep3 |
|
||||
| message | sender | {sender address} |
|
||||
|
@ -1,19 +1,46 @@
|
||||
# Begin Block
|
||||
|
||||
At the start of each block, atomic swaps that have reached `ExpireHeight` are expired. The logic to expire atomic swaps is as follows:
|
||||
At the start of each block, atomic swaps that meet certain criteria are expired or deleted.
|
||||
|
||||
```go
|
||||
var expiredSwaps [][]byte
|
||||
k.IterateAtomicSwapsByBlock(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
|
||||
expiredSwaps = append(expiredSwaps, id)
|
||||
return false
|
||||
})
|
||||
|
||||
// Expire incomplete swaps (claimed swaps have already been removed from byBlock index)
|
||||
for _, id := range expiredSwaps {
|
||||
atomicSwap, _ := k.GetAtomicSwap(ctx, id)
|
||||
atomicSwap.Status = types.Expired
|
||||
k.SetAtomicSwap(ctx, atomicSwap)
|
||||
k.RemoveFromByBlockIndex(ctx, atomicSwap)
|
||||
func BeginBlocker(ctx sdk.Context, k Keeper) {
|
||||
k.UpdateExpiredAtomicSwaps(ctx)
|
||||
k.DeleteClosedAtomicSwapsFromLongtermStorage(ctx)
|
||||
}
|
||||
```
|
||||
|
||||
## Expiration
|
||||
|
||||
If an atomic swap's `ExpireHeight` is greater than the current block height, it will be expired. The logic to expire atomic swaps is as follows:
|
||||
|
||||
```go
|
||||
var expiredSwapIDs []string
|
||||
k.IterateAtomicSwapsByBlock(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
|
||||
atomicSwap, found := k.GetAtomicSwap(ctx, id)
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
// Expire the uncompleted swap and update both indexes
|
||||
atomicSwap.Status = types.Expired
|
||||
k.RemoveFromByBlockIndex(ctx, atomicSwap)
|
||||
k.SetAtomicSwap(ctx, atomicSwap)
|
||||
expiredSwapIDs = append(expiredSwapIDs, hex.EncodeToString(atomicSwap.GetSwapID()))
|
||||
return false
|
||||
})
|
||||
```
|
||||
|
||||
## Deletion
|
||||
|
||||
Atomic swaps are deleted 86400 blocks (one week, assuming a block time of 7 seconds) after being completed. The logic to delete atomic swaps is as follows:
|
||||
|
||||
```go
|
||||
k.IterateAtomicSwapsLongtermStorage(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
|
||||
swap, found := k.GetAtomicSwap(ctx, id)
|
||||
if !found {
|
||||
return false
|
||||
}
|
||||
k.RemoveAtomicSwap(ctx, swap.GetSwapID())
|
||||
k.RemoveFromLongtermStorage(ctx, swap)
|
||||
return false
|
||||
})
|
||||
```
|
@ -13,17 +13,17 @@ type AssetSupply struct {
|
||||
IncomingSupply sdk.Coin `json:"incoming_supply" yaml:"incoming_supply"`
|
||||
OutgoingSupply sdk.Coin `json:"outgoing_supply" yaml:"outgoing_supply"`
|
||||
CurrentSupply sdk.Coin `json:"current_supply" yaml:"current_supply"`
|
||||
Limit sdk.Coin `json:"limit" yaml:"limit"`
|
||||
SupplyLimit sdk.Coin `json:"supply_limit" yaml:"supply_limit"`
|
||||
}
|
||||
|
||||
// NewAssetSupply initializes a new AssetSupply
|
||||
func NewAssetSupply(denom string, incomingSupply, outgoingSupply, currentSupply, limit sdk.Coin) AssetSupply {
|
||||
func NewAssetSupply(denom string, incomingSupply, outgoingSupply, currentSupply, supplyLimit sdk.Coin) AssetSupply {
|
||||
return AssetSupply{
|
||||
Denom: denom,
|
||||
IncomingSupply: incomingSupply,
|
||||
OutgoingSupply: outgoingSupply,
|
||||
CurrentSupply: currentSupply,
|
||||
Limit: limit,
|
||||
SupplyLimit: supplyLimit,
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,31 +38,23 @@ func (a AssetSupply) Validate() error {
|
||||
if !a.CurrentSupply.IsValid() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "current supply %s", a.CurrentSupply)
|
||||
}
|
||||
if !a.Limit.IsValid() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "limit %s", a.Limit)
|
||||
if !a.SupplyLimit.IsValid() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "supply limit %s", a.SupplyLimit)
|
||||
}
|
||||
return sdk.ValidateDenom(a.Denom)
|
||||
}
|
||||
|
||||
// String implements stringer
|
||||
func (a AssetSupply) String() string {
|
||||
return fmt.Sprintf("Asset Supply"+
|
||||
"\n Denom: %s"+
|
||||
"\n Incoming supply: %s"+
|
||||
"\n Outgoing supply: %s"+
|
||||
"\n Current supply: %s"+
|
||||
"\n Limit: %s"+
|
||||
a.Denom, a.IncomingSupply, a.OutgoingSupply, a.CurrentSupply, a.Limit)
|
||||
return fmt.Sprintf(`
|
||||
%s supply:
|
||||
Incoming supply: %s
|
||||
Outgoing supply: %s
|
||||
Current supply: %s
|
||||
Supply limit: %s
|
||||
`,
|
||||
a.Denom, a.IncomingSupply, a.OutgoingSupply, a.CurrentSupply, a.SupplyLimit)
|
||||
}
|
||||
|
||||
// AssetSupplies is a slice of AssetSupply
|
||||
type AssetSupplies []AssetSupply
|
||||
|
||||
// String implements stringer
|
||||
func (supplies AssetSupplies) String() string {
|
||||
out := ""
|
||||
for _, supply := range supplies {
|
||||
out += supply.String() + "\n"
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
@ -43,12 +43,12 @@ func TestAssetSupplyValidate(t *testing.T) {
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid limit",
|
||||
"invalid supply limit",
|
||||
AssetSupply{
|
||||
IncomingSupply: coin,
|
||||
OutgoingSupply: coin,
|
||||
CurrentSupply: coin,
|
||||
Limit: invalidCoin,
|
||||
SupplyLimit: invalidCoin,
|
||||
},
|
||||
false,
|
||||
},
|
||||
|
@ -25,10 +25,10 @@ func atomicSwaps(count int) types.AtomicSwaps {
|
||||
}
|
||||
|
||||
func atomicSwap(index int) types.AtomicSwap {
|
||||
expireOffset := int64((index * 15) + 360) // Default expire height + offet to match timestamp
|
||||
expireOffset := uint64((index * 15) + 360) // Default expire height + offet to match timestamp
|
||||
timestamp := ts(index) // One minute apart
|
||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
|
||||
swap := types.NewAtomicSwap(cs(c("bnb", 50000)), randomNumberHash, expireOffset, timestamp, kavaAddrs[0],
|
||||
kavaAddrs[1], binanceAddrs[0].String(), binanceAddrs[1].String(), 1, types.Open, true, types.Incoming)
|
||||
|
@ -16,7 +16,6 @@ const (
|
||||
AttributeKeySenderOtherChain = "sender_other_chain"
|
||||
AttributeKeyExpireHeight = "expire_height"
|
||||
AttributeKeyAmount = "amount"
|
||||
AttributeKeyExpectedIncome = "expected_income"
|
||||
AttributeKeyDirection = "direction"
|
||||
AttributeKeyClaimSender = "claim_sender"
|
||||
AttributeKeyRandomNumber = "random_number"
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
|
||||
@ -13,22 +14,21 @@ import (
|
||||
)
|
||||
|
||||
// GenerateSecureRandomNumber generates cryptographically strong pseudo-random number
|
||||
func GenerateSecureRandomNumber() (*big.Int, error) {
|
||||
func GenerateSecureRandomNumber() ([64]byte, error) {
|
||||
// Max is a 256-bits integer i.e. 2^256
|
||||
max := new(big.Int)
|
||||
max.Exp(big.NewInt(2), big.NewInt(256), nil) // 256-bits integer i.e. 2^256
|
||||
max.Exp(big.NewInt(2), big.NewInt(256), nil)
|
||||
|
||||
// Generate number between 0 - max
|
||||
// Generate number in the range [0, max]
|
||||
randomNumber, err := rand.Int(rand.Reader, max)
|
||||
if err != nil {
|
||||
return big.NewInt(0), errors.New("random number generation error")
|
||||
return [64]byte{}, errors.New("random number generation error")
|
||||
}
|
||||
|
||||
// Catch random numbers that encode to hexadecimal poorly
|
||||
if len(randomNumber.Text(16)) != 64 {
|
||||
return GenerateSecureRandomNumber()
|
||||
}
|
||||
|
||||
return randomNumber, nil
|
||||
// Ensure length of 64 for hexadecimal encoding by padding with 0s
|
||||
var paddedNumber [64]byte
|
||||
copy(paddedNumber[:], fmt.Sprintf("%064x", randomNumber))
|
||||
return paddedNumber, nil
|
||||
}
|
||||
|
||||
// CalculateRandomHash calculates the hash of a number and timestamp
|
||||
@ -43,7 +43,7 @@ func CalculateRandomHash(randomNumber []byte, timestamp int64) []byte {
|
||||
func CalculateSwapID(randomNumberHash []byte, sender sdk.AccAddress, senderOtherChain string) []byte {
|
||||
senderOtherChain = strings.ToLower(senderOtherChain)
|
||||
data := randomNumberHash
|
||||
data = append(data, []byte(sender)...)
|
||||
data = append(data, sender.Bytes()...)
|
||||
data = append(data, []byte(senderOtherChain)...)
|
||||
return tmhash.Sum(data)
|
||||
}
|
||||
|
@ -36,24 +36,24 @@ func (suite *HashTestSuite) TestGenerateSecureRandomNumber() {
|
||||
secureRandomNumber, err := types.GenerateSecureRandomNumber()
|
||||
suite.Nil(err)
|
||||
suite.NotNil(secureRandomNumber)
|
||||
suite.Equal(64, len(secureRandomNumber.Text(16)))
|
||||
suite.Equal(64, len(secureRandomNumber))
|
||||
}
|
||||
|
||||
func (suite *HashTestSuite) TestCalculateRandomHash() {
|
||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||
hash := types.CalculateRandomHash(randomNumber.Bytes(), suite.timestamps[0])
|
||||
hash := types.CalculateRandomHash(randomNumber[:], suite.timestamps[0])
|
||||
suite.NotNil(hash)
|
||||
suite.Equal(32, len(hash))
|
||||
}
|
||||
|
||||
func (suite *HashTestSuite) TestCalculateSwapID() {
|
||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||
hash := types.CalculateRandomHash(randomNumber.Bytes(), suite.timestamps[3])
|
||||
hash := types.CalculateRandomHash(randomNumber[:], suite.timestamps[3])
|
||||
swapID := types.CalculateSwapID(hash, suite.addrs[3], suite.addrs[5].String())
|
||||
suite.NotNil(swapID)
|
||||
suite.Equal(32, len(swapID))
|
||||
|
||||
diffHash := types.CalculateRandomHash(randomNumber.Bytes(), suite.timestamps[2])
|
||||
diffHash := types.CalculateRandomHash(randomNumber[:], suite.timestamps[2])
|
||||
diffSwapID := types.CalculateSwapID(diffHash, suite.addrs[3], suite.addrs[5].String())
|
||||
suite.NotEqual(swapID, diffSwapID)
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -23,7 +22,7 @@ const (
|
||||
)
|
||||
|
||||
// DefaultLongtermStorageDuration is 1 week (assuming a block time of 7 seconds)
|
||||
const DefaultLongtermStorageDuration int64 = 86400
|
||||
const DefaultLongtermStorageDuration uint64 = 86400
|
||||
|
||||
// Key prefixes
|
||||
var (
|
||||
@ -34,34 +33,6 @@ var (
|
||||
)
|
||||
|
||||
// GetAtomicSwapByHeightKey is used by the AtomicSwapByBlock index and AtomicSwapLongtermStorage index
|
||||
func GetAtomicSwapByHeightKey(height int64, swapID []byte) []byte {
|
||||
return append(Uint64ToBytes(uint64(height)), swapID...)
|
||||
}
|
||||
|
||||
// Uint64ToBytes converts a uint64 into fixed length bytes for use in store keys.
|
||||
func Uint64ToBytes(id uint64) []byte {
|
||||
bz := make([]byte, 8)
|
||||
binary.BigEndian.PutUint64(bz, uint64(id))
|
||||
return bz
|
||||
}
|
||||
|
||||
// Uint64FromBytes converts some fixed length bytes back into a uint64.
|
||||
func Uint64FromBytes(bz []byte) uint64 {
|
||||
return binary.BigEndian.Uint64(bz)
|
||||
}
|
||||
|
||||
// BytesToHex converts data from []byte to a hex-encoded string
|
||||
func BytesToHex(data []byte) string {
|
||||
encodedData := make([]byte, hex.EncodedLen(len(data)))
|
||||
hex.Encode(encodedData, data)
|
||||
return string(encodedData)
|
||||
}
|
||||
|
||||
// HexToBytes converts data from a hex-encoded string to []bytes
|
||||
func HexToBytes(data string) ([]byte, error) {
|
||||
decodedData, err := hex.DecodeString(data)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return decodedData, nil
|
||||
func GetAtomicSwapByHeightKey(height uint64, swapID []byte) []byte {
|
||||
return append(sdk.Uint64ToBigEndian(height), swapID...)
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
|
||||
const (
|
||||
CreateAtomicSwap = "createAtomicSwap"
|
||||
DepositAtomicSwap = "depositAtomicSwap"
|
||||
ClaimAtomicSwap = "claimAtomicSwap"
|
||||
RefundAtomicSwap = "refundAtomicSwap"
|
||||
CalcSwapID = "calcSwapID"
|
||||
@ -47,15 +46,13 @@ type MsgCreateAtomicSwap struct {
|
||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
|
||||
HeightSpan int64 `json:"height_span" yaml:"height_span"`
|
||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||
HeightSpan uint64 `json:"height_span" yaml:"height_span"`
|
||||
}
|
||||
|
||||
// NewMsgCreateAtomicSwap initializes a new MsgCreateAtomicSwap
|
||||
func NewMsgCreateAtomicSwap(from sdk.AccAddress, to sdk.AccAddress, recipientOtherChain,
|
||||
senderOtherChain string, randomNumberHash tmbytes.HexBytes, timestamp int64,
|
||||
amount sdk.Coins, expectedIncome string, heightSpan int64, crossChain bool) MsgCreateAtomicSwap {
|
||||
amount sdk.Coins, heightSpan uint64) MsgCreateAtomicSwap {
|
||||
return MsgCreateAtomicSwap{
|
||||
From: from,
|
||||
To: to,
|
||||
@ -64,9 +61,7 @@ func NewMsgCreateAtomicSwap(from sdk.AccAddress, to sdk.AccAddress, recipientOth
|
||||
RandomNumberHash: randomNumberHash,
|
||||
Timestamp: timestamp,
|
||||
Amount: amount,
|
||||
ExpectedIncome: expectedIncome,
|
||||
HeightSpan: heightSpan,
|
||||
CrossChain: crossChain,
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,10 +73,9 @@ func (msg MsgCreateAtomicSwap) Type() string { return CreateAtomicSwap }
|
||||
|
||||
// String prints the MsgCreateAtomicSwap
|
||||
func (msg MsgCreateAtomicSwap) String() string {
|
||||
return fmt.Sprintf("AtomicSwap{%v#%v#%v#%v#%v#%v#%v#%v#%v#%v}",
|
||||
return fmt.Sprintf("AtomicSwap{%v#%v#%v#%v#%v#%v#%v#%v}",
|
||||
msg.From, msg.To, msg.RecipientOtherChain, msg.SenderOtherChain,
|
||||
msg.RandomNumberHash, msg.Timestamp, msg.Amount, msg.ExpectedIncome,
|
||||
msg.HeightSpan, msg.CrossChain)
|
||||
msg.RandomNumberHash, msg.Timestamp, msg.Amount, msg.HeightSpan)
|
||||
}
|
||||
|
||||
// GetInvolvedAddresses gets the addresses involved in a MsgCreateAtomicSwap
|
||||
@ -108,14 +102,8 @@ func (msg MsgCreateAtomicSwap) ValidateBasic() error {
|
||||
if len(msg.To) != AddrByteCount {
|
||||
return fmt.Errorf("the expected address length is %d, actual length is %d", AddrByteCount, len(msg.To))
|
||||
}
|
||||
if !msg.CrossChain && msg.RecipientOtherChain != "" {
|
||||
return errors.New("must leave recipient address on other chain to empty for single chain swap")
|
||||
}
|
||||
if !msg.CrossChain && msg.SenderOtherChain != "" {
|
||||
return errors.New("must leave sender address on other chain to empty for single chain swap")
|
||||
}
|
||||
if msg.CrossChain && strings.TrimSpace(msg.RecipientOtherChain) == "" {
|
||||
return errors.New("missing recipient address on other chain for cross chain swap")
|
||||
if strings.TrimSpace(msg.RecipientOtherChain) == "" {
|
||||
return errors.New("missing recipient address on other chain")
|
||||
}
|
||||
if len(msg.RecipientOtherChain) > MaxOtherChainAddrLength {
|
||||
return fmt.Errorf("the length of recipient address on other chain should be less than %d", MaxOtherChainAddrLength)
|
||||
@ -135,16 +123,6 @@ func (msg MsgCreateAtomicSwap) ValidateBasic() error {
|
||||
if !msg.Amount.IsValid() {
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String())
|
||||
}
|
||||
if len(msg.ExpectedIncome) > MaxExpectedIncomeLength {
|
||||
return fmt.Errorf("the length of expected income should be less than %d", MaxExpectedIncomeLength)
|
||||
}
|
||||
expectedIncomeCoins, err := sdk.ParseCoins(msg.ExpectedIncome)
|
||||
if err != nil || expectedIncomeCoins == nil {
|
||||
return fmt.Errorf("expected income %s must be in valid format e.g. 10000ukava", msg.ExpectedIncome)
|
||||
}
|
||||
if expectedIncomeCoins.IsAnyGT(msg.Amount) {
|
||||
return fmt.Errorf("expected income %s cannot be greater than amount %s", msg.ExpectedIncome, msg.Amount.String())
|
||||
}
|
||||
if msg.HeightSpan <= 0 {
|
||||
return errors.New("height span must be positive")
|
||||
}
|
||||
|
@ -39,16 +39,12 @@ func TestMsgCreateAtomicSwap(t *testing.T) {
|
||||
randomNumberHash tmbytes.HexBytes
|
||||
timestamp int64
|
||||
amount sdk.Coins
|
||||
expectedIncome string
|
||||
heightSpan int64
|
||||
crossChain bool
|
||||
heightSpan uint64
|
||||
expectPass bool
|
||||
}{
|
||||
{"normal", binanceAddrs[0], kavaAddrs[0], "", "", randomNumberHash, timestampInt64, coinsSingle, "50000bnb", 500, false, true},
|
||||
{"cross-chain", binanceAddrs[0], kavaAddrs[0], kavaAddrs[0].String(), binanceAddrs[0].String(), randomNumberHash, timestampInt64, coinsSingle, "50000bnb", 80000, true, true},
|
||||
{"with other chain fields", binanceAddrs[0], kavaAddrs[0], kavaAddrs[0].String(), binanceAddrs[0].String(), randomNumberHash, timestampInt64, coinsSingle, "50000bnb", 500, false, false},
|
||||
{"cross-cross no other chain fields", binanceAddrs[0], kavaAddrs[0], "", "", randomNumberHash, timestampInt64, coinsSingle, "50000bnb", 500, true, false},
|
||||
{"zero coins", binanceAddrs[0], kavaAddrs[0], "", "", randomNumberHash, timestampInt64, coinsZero, "50000bnb", 500, true, false},
|
||||
{"normal cross-chain", binanceAddrs[0], kavaAddrs[0], kavaAddrs[0].String(), binanceAddrs[0].String(), randomNumberHash, timestampInt64, coinsSingle, 500, true},
|
||||
{"without other chain fields", binanceAddrs[0], kavaAddrs[0], "", "", randomNumberHash, timestampInt64, coinsSingle, 500, false},
|
||||
{"invalid amount", binanceAddrs[0], kavaAddrs[0], "", "", randomNumberHash, timestampInt64, coinsZero, 500, false},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
@ -60,9 +56,7 @@ func TestMsgCreateAtomicSwap(t *testing.T) {
|
||||
tc.randomNumberHash,
|
||||
tc.timestamp,
|
||||
tc.amount,
|
||||
tc.expectedIncome,
|
||||
tc.heightSpan,
|
||||
tc.crossChain,
|
||||
)
|
||||
if tc.expectPass {
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
|
||||
|
@ -20,10 +20,10 @@ var (
|
||||
KeyMaxBlockLock = []byte("MaxBlockLock")
|
||||
KeySupportedAssets = []byte("SupportedAssets")
|
||||
|
||||
AbsoluteMaximumBlockLock int64 = 10000
|
||||
AbsoluteMinimumBlockLock int64 = 50
|
||||
DefaultMinBlockLock int64 = 80
|
||||
DefaultMaxBlockLock int64 = 600
|
||||
AbsoluteMaximumBlockLock uint64 = 10000
|
||||
AbsoluteMinimumBlockLock uint64 = 50
|
||||
DefaultMinBlockLock uint64 = 80
|
||||
DefaultMaxBlockLock uint64 = 600
|
||||
DefaultSupportedAssets = AssetParams{
|
||||
AssetParam{
|
||||
Denom: "bnb",
|
||||
@ -37,8 +37,8 @@ var (
|
||||
// Params governance parameters for bep3 module
|
||||
type Params struct {
|
||||
BnbDeputyAddress sdk.AccAddress `json:"bnb_deputy_address" yaml:"bnb_deputy_address"` // Bnbchain deputy address
|
||||
MinBlockLock int64 `json:"min_block_lock" yaml:"min_block_lock"` // AtomicSwap minimum block lock
|
||||
MaxBlockLock int64 `json:"max_block_lock" yaml:"max_block_lock"` // AtomicSwap maximum block lock
|
||||
MinBlockLock uint64 `json:"min_block_lock" yaml:"min_block_lock"` // AtomicSwap minimum block lock
|
||||
MaxBlockLock uint64 `json:"max_block_lock" yaml:"max_block_lock"` // AtomicSwap maximum block lock
|
||||
SupportedAssets AssetParams `json:"supported_assets" yaml:"supported_assets"` // Supported assets
|
||||
}
|
||||
|
||||
@ -53,7 +53,7 @@ func (p Params) String() string {
|
||||
}
|
||||
|
||||
// NewParams returns a new params object
|
||||
func NewParams(bnbDeputyAddress sdk.AccAddress, minBlockLock, maxBlockLock int64, supportedAssets AssetParams,
|
||||
func NewParams(bnbDeputyAddress sdk.AccAddress, minBlockLock, maxBlockLock uint64, supportedAssets AssetParams,
|
||||
) Params {
|
||||
return Params{
|
||||
BnbDeputyAddress: bnbDeputyAddress,
|
||||
@ -159,7 +159,7 @@ func validateBnbDeputyAddressParam(i interface{}) error {
|
||||
}
|
||||
|
||||
func validateMinBlockLockParam(i interface{}) error {
|
||||
minBlockLock, ok := i.(int64)
|
||||
minBlockLock, ok := i.(uint64)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid parameter type: %T", i)
|
||||
}
|
||||
@ -172,7 +172,7 @@ func validateMinBlockLockParam(i interface{}) error {
|
||||
}
|
||||
|
||||
func validateMaxBlockLockParam(i interface{}) error {
|
||||
maxBlockLock, ok := i.(int64)
|
||||
maxBlockLock, ok := i.(uint64)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid parameter type: %T", i)
|
||||
}
|
||||
|
@ -29,8 +29,8 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
|
||||
type args struct {
|
||||
bnbDeputyAddress sdk.AccAddress
|
||||
minBlockLock int64
|
||||
maxBlockLock int64
|
||||
minBlockLock uint64
|
||||
maxBlockLock uint64
|
||||
supportedAssets types.AssetParams
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,15 @@
|
||||
package types
|
||||
|
||||
import tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
)
|
||||
|
||||
const (
|
||||
// QueryGetAssetSupply command for getting info about an asset's supply
|
||||
QueryGetAssetSupply = "supply"
|
||||
// QueryGetAssetSupplies command for getting a list of asset supplies
|
||||
QueryGetAssetSupplies = "supplies"
|
||||
// QueryGetAtomicSwap command for getting info about an atomic swap
|
||||
QueryGetAtomicSwap = "swap"
|
||||
// QueryGetAtomicSwaps command for getting a list of atomic swaps
|
||||
@ -25,6 +30,20 @@ func NewQueryAssetSupply(denom tmbytes.HexBytes) QueryAssetSupply {
|
||||
}
|
||||
}
|
||||
|
||||
// QueryAssetSupplies contains the params for an AssetSupplies query
|
||||
type QueryAssetSupplies struct {
|
||||
Page int `json:"page" yaml:"page"`
|
||||
Limit int `json:"limit" yaml:"limit"`
|
||||
}
|
||||
|
||||
// NewQueryAssetSupplies creates a new QueryAssetSupplies
|
||||
func NewQueryAssetSupplies(page int, limit int) QueryAssetSupplies {
|
||||
return QueryAssetSupplies{
|
||||
Page: page,
|
||||
Limit: limit,
|
||||
}
|
||||
}
|
||||
|
||||
// QueryAtomicSwapByID contains the params for query 'custom/bep3/swap'
|
||||
type QueryAtomicSwapByID struct {
|
||||
SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
|
||||
@ -41,12 +60,21 @@ func NewQueryAtomicSwapByID(swapBytes tmbytes.HexBytes) QueryAtomicSwapByID {
|
||||
type QueryAtomicSwaps struct {
|
||||
Page int `json:"page" yaml:"page"`
|
||||
Limit int `json:"limit" yaml:"limit"`
|
||||
Involve sdk.AccAddress `json:"involve" yaml:"involve"`
|
||||
Expiration uint64 `json:"expiration" yaml:"expiration"`
|
||||
Status SwapStatus `json:"status" yaml:"status"`
|
||||
Direction SwapDirection `json:"direction" yaml:"direction"`
|
||||
}
|
||||
|
||||
// NewQueryAtomicSwaps creates a new QueryAtomicSwaps
|
||||
func NewQueryAtomicSwaps(page int, limit int) QueryAtomicSwaps {
|
||||
// NewQueryAtomicSwaps creates a new instance of QueryAtomicSwaps
|
||||
func NewQueryAtomicSwaps(page, limit int, involve sdk.AccAddress, expiration uint64,
|
||||
status SwapStatus, direction SwapDirection) QueryAtomicSwaps {
|
||||
return QueryAtomicSwaps{
|
||||
Page: page,
|
||||
Limit: limit,
|
||||
Involve: involve,
|
||||
Expiration: expiration,
|
||||
Status: status,
|
||||
Direction: direction,
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ import (
|
||||
type AtomicSwap struct {
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||
ExpireHeight int64 `json:"expire_height" yaml:"expire_height"`
|
||||
ExpireHeight uint64 `json:"expire_height" yaml:"expire_height"`
|
||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Recipient sdk.AccAddress `json:"recipient" yaml:"recipient"`
|
||||
@ -30,8 +30,8 @@ type AtomicSwap struct {
|
||||
}
|
||||
|
||||
// NewAtomicSwap returns a new AtomicSwap
|
||||
func NewAtomicSwap(amount sdk.Coins, randomNumberHash tmbytes.HexBytes, expireHeight, timestamp int64, sender,
|
||||
recipient sdk.AccAddress, senderOtherChain string, recipientOtherChain string, closedBlock int64,
|
||||
func NewAtomicSwap(amount sdk.Coins, randomNumberHash tmbytes.HexBytes, expireHeight uint64, timestamp int64,
|
||||
sender, recipient sdk.AccAddress, senderOtherChain string, recipientOtherChain string, closedBlock int64,
|
||||
status SwapStatus, crossChain bool, direction SwapDirection) AtomicSwap {
|
||||
return AtomicSwap{
|
||||
Amount: amount,
|
||||
@ -197,6 +197,16 @@ func (status *SwapStatus) UnmarshalJSON(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid returns true if the swap status is valid and false otherwise.
|
||||
func (status SwapStatus) IsValid() bool {
|
||||
if status == Open ||
|
||||
status == Completed ||
|
||||
status == Expired {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// SwapDirection is the direction of an AtomicSwap
|
||||
type SwapDirection byte
|
||||
|
||||
@ -245,3 +255,12 @@ func (direction *SwapDirection) UnmarshalJSON(data []byte) error {
|
||||
*direction = NewSwapDirectionFromString(s)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsValid returns true if the swap direction is valid and false otherwise.
|
||||
func (direction SwapDirection) IsValid() bool {
|
||||
if direction == Incoming ||
|
||||
direction == Outgoing {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ func (suite *AtomicSwapTestSuite) SetupTest() {
|
||||
for i := 0; i < 10; i++ {
|
||||
timestamp := ts(i)
|
||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
||||
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||
timestamps = append(timestamps, timestamp)
|
||||
randomNumberHashes = append(randomNumberHashes, randomNumberHash)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user