mirror of
				https://github.com/0glabs/0g-chain.git
				synced 2025-11-04 14:57:27 +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",
 | 
			
		||||
		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{
 | 
			
		||||
		Use:     "swaps",
 | 
			
		||||
		Short:   "get a list of active atomic swaps",
 | 
			
		||||
		Example: "bep3 swaps",
 | 
			
		||||
	cmd := &cobra.Command{
 | 
			
		||||
		Use:   "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"
 | 
			
		||||
@ -25,8 +26,11 @@ import (
 | 
			
		||||
// GetTxCmd returns the transaction commands for this module
 | 
			
		||||
func GetTxCmd(cdc *codec.Codec) *cobra.Command {
 | 
			
		||||
	bep3TxCmd := &cobra.Command{
 | 
			
		||||
		Use:   "bep3",
 | 
			
		||||
		Short: "bep3 transactions subcommands",
 | 
			
		||||
		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
 | 
			
		||||
	timestamp := ts(index)                    // One minute apart
 | 
			
		||||
	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
 | 
			
		||||
	timestamp := ts(index)                    // One minute apart
 | 
			
		||||
	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)
 | 
			
		||||
		return false
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// Delete closed atomic swaps
 | 
			
		||||
	for _, id := range swapsToDelete {
 | 
			
		||||
		swap, _ := k.GetAtomicSwap(ctx, id)
 | 
			
		||||
		swap, found := k.GetAtomicSwap(ctx, id)
 | 
			
		||||
		if !found {
 | 
			
		||||
			// NOTE: shouldn't happen. Continue to next item.
 | 
			
		||||
			return false
 | 
			
		||||
		}
 | 
			
		||||
		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
 | 
			
		||||
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 {
 | 
			
		||||
		expiredSwaps = append(expiredSwaps, id)
 | 
			
		||||
		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
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// 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)
 | 
			
		||||
	}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
## 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
 | 
			
		||||
	timestamp := ts(index)                    // One minute apart
 | 
			
		||||
	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...)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -13,11 +13,10 @@ import (
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	CreateAtomicSwap  = "createAtomicSwap"
 | 
			
		||||
	DepositAtomicSwap = "depositAtomicSwap"
 | 
			
		||||
	ClaimAtomicSwap   = "claimAtomicSwap"
 | 
			
		||||
	RefundAtomicSwap  = "refundAtomicSwap"
 | 
			
		||||
	CalcSwapID        = "calcSwapID"
 | 
			
		||||
	CreateAtomicSwap = "createAtomicSwap"
 | 
			
		||||
	ClaimAtomicSwap  = "claimAtomicSwap"
 | 
			
		||||
	RefundAtomicSwap = "refundAtomicSwap"
 | 
			
		||||
	CalcSwapID       = "calcSwapID"
 | 
			
		||||
 | 
			
		||||
	Int64Size               = 8
 | 
			
		||||
	RandomNumberHashLength  = 32
 | 
			
		||||
@ -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,11 +20,11 @@ var (
 | 
			
		||||
	KeyMaxBlockLock     = []byte("MaxBlockLock")
 | 
			
		||||
	KeySupportedAssets  = []byte("SupportedAssets")
 | 
			
		||||
 | 
			
		||||
	AbsoluteMaximumBlockLock int64 = 10000
 | 
			
		||||
	AbsoluteMinimumBlockLock int64 = 50
 | 
			
		||||
	DefaultMinBlockLock      int64 = 80
 | 
			
		||||
	DefaultMaxBlockLock      int64 = 600
 | 
			
		||||
	DefaultSupportedAssets         = AssetParams{
 | 
			
		||||
	AbsoluteMaximumBlockLock uint64 = 10000
 | 
			
		||||
	AbsoluteMinimumBlockLock uint64 = 50
 | 
			
		||||
	DefaultMinBlockLock      uint64 = 80
 | 
			
		||||
	DefaultMaxBlockLock      uint64 = 600
 | 
			
		||||
	DefaultSupportedAssets          = AssetParams{
 | 
			
		||||
		AssetParam{
 | 
			
		||||
			Denom:  "bnb",
 | 
			
		||||
			CoinID: 714,
 | 
			
		||||
@ -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"`
 | 
			
		||||
@ -39,14 +58,23 @@ func NewQueryAtomicSwapByID(swapBytes tmbytes.HexBytes) QueryAtomicSwapByID {
 | 
			
		||||
 | 
			
		||||
// QueryAtomicSwaps contains the params for an AtomicSwaps query
 | 
			
		||||
type QueryAtomicSwaps struct {
 | 
			
		||||
	Page  int `json:"page" yaml:"page"`
 | 
			
		||||
	Limit int `json:"limit" yaml:"limit"`
 | 
			
		||||
	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,
 | 
			
		||||
		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