mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-12-24 23:35:19 +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"
|
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) {
|
func BeginBlocker(ctx sdk.Context, k Keeper) {
|
||||||
err := k.UpdateExpiredAtomicSwaps(ctx)
|
k.UpdateExpiredAtomicSwaps(ctx)
|
||||||
if err != nil {
|
k.DeleteClosedAtomicSwapsFromLongtermStorage(ctx)
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = k.DeleteClosedAtomicSwapsFromLongtermStorage(ctx)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -52,22 +52,22 @@ func (suite *ABCITestSuite) ResetKeeper() {
|
|||||||
var randomNumbers []tmbytes.HexBytes
|
var randomNumbers []tmbytes.HexBytes
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
// Set up atomic swap variables
|
// Set up atomic swap variables
|
||||||
expireHeight := int64(360)
|
expireHeight := uint64(360)
|
||||||
amount := cs(c("bnb", int64(100)))
|
amount := cs(c("bnb", int64(100)))
|
||||||
timestamp := ts(i)
|
timestamp := ts(i)
|
||||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
|
|
||||||
// Create atomic swap and check err to confirm creation
|
// Create atomic swap and check err to confirm creation
|
||||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, randomNumberHash, timestamp, expireHeight,
|
err := suite.keeper.CreateAtomicSwap(suite.ctx, randomNumberHash, timestamp, expireHeight,
|
||||||
suite.addrs[0], suite.addrs[i], TestSenderOtherChain, TestRecipientOtherChain,
|
suite.addrs[0], suite.addrs[i], TestSenderOtherChain, TestRecipientOtherChain,
|
||||||
amount, amount.String(), true)
|
amount, true)
|
||||||
suite.Nil(err)
|
suite.Nil(err)
|
||||||
|
|
||||||
// Store swap's calculated ID and secret random number
|
// Store swap's calculated ID and secret random number
|
||||||
swapID := bep3.CalculateSwapID(randomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
swapID := bep3.CalculateSwapID(randomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
||||||
swapIDs = append(swapIDs, swapID)
|
swapIDs = append(swapIDs, swapID)
|
||||||
randomNumbers = append(randomNumbers, randomNumber.Bytes())
|
randomNumbers = append(randomNumbers, randomNumber[:])
|
||||||
}
|
}
|
||||||
suite.swapIDs = swapIDs
|
suite.swapIDs = swapIDs
|
||||||
suite.randomNumbers = randomNumbers
|
suite.randomNumbers = randomNumbers
|
||||||
@ -105,7 +105,7 @@ func (suite *ABCITestSuite) TestBeginBlocker_UpdateExpiredAtomicSwaps() {
|
|||||||
{
|
{
|
||||||
name: "after deletion",
|
name: "after deletion",
|
||||||
firstCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 400),
|
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,
|
expectedStatus: bep3.NULL,
|
||||||
expectInStorage: false,
|
expectInStorage: false,
|
||||||
},
|
},
|
||||||
@ -166,7 +166,7 @@ func (suite *ABCITestSuite) TestBeginBlocker_DeleteClosedAtomicSwapsFromLongterm
|
|||||||
name: "no action with long storage duration",
|
name: "no action with long storage duration",
|
||||||
firstCtx: suite.ctx,
|
firstCtx: suite.ctx,
|
||||||
action: NULL,
|
action: NULL,
|
||||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + bep3.DefaultLongtermStorageDuration),
|
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + int64(bep3.DefaultLongtermStorageDuration)),
|
||||||
expectInStorage: true,
|
expectInStorage: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -180,7 +180,7 @@ func (suite *ABCITestSuite) TestBeginBlocker_DeleteClosedAtomicSwapsFromLongterm
|
|||||||
name: "claim with long storage duration",
|
name: "claim with long storage duration",
|
||||||
firstCtx: suite.ctx,
|
firstCtx: suite.ctx,
|
||||||
action: Claim,
|
action: Claim,
|
||||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + bep3.DefaultLongtermStorageDuration),
|
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + int64(bep3.DefaultLongtermStorageDuration)),
|
||||||
expectInStorage: false,
|
expectInStorage: false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -194,7 +194,7 @@ func (suite *ABCITestSuite) TestBeginBlocker_DeleteClosedAtomicSwapsFromLongterm
|
|||||||
name: "refund with long storage duration",
|
name: "refund with long storage duration",
|
||||||
firstCtx: suite.ctx,
|
firstCtx: suite.ctx,
|
||||||
action: Refund,
|
action: Refund,
|
||||||
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + bep3.DefaultLongtermStorageDuration),
|
secondCtx: suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + int64(bep3.DefaultLongtermStorageDuration)),
|
||||||
expectInStorage: false,
|
expectInStorage: false,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -214,12 +214,12 @@ func (suite *ABCITestSuite) TestBeginBlocker_DeleteClosedAtomicSwapsFromLongterm
|
|||||||
case Refund:
|
case Refund:
|
||||||
for _, swapID := range suite.swapIDs {
|
for _, swapID := range suite.swapIDs {
|
||||||
swap, _ := suite.keeper.GetAtomicSwap(tc.firstCtx, swapID)
|
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)
|
bep3.BeginBlocker(refundCtx, suite.keeper)
|
||||||
err := suite.keeper.RefundAtomicSwap(refundCtx, suite.addrs[5], swapID)
|
err := suite.keeper.RefundAtomicSwap(refundCtx, suite.addrs[5], swapID)
|
||||||
suite.Nil(err)
|
suite.Nil(err)
|
||||||
// Add expire height to second ctx block height
|
// 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
|
AttributeKeyAtomicSwapIDs = types.AttributeKeyAtomicSwapIDs
|
||||||
AttributeKeyClaimSender = types.AttributeKeyClaimSender
|
AttributeKeyClaimSender = types.AttributeKeyClaimSender
|
||||||
AttributeKeyDirection = types.AttributeKeyDirection
|
AttributeKeyDirection = types.AttributeKeyDirection
|
||||||
AttributeKeyExpectedIncome = types.AttributeKeyExpectedIncome
|
|
||||||
AttributeKeyExpireHeight = types.AttributeKeyExpireHeight
|
AttributeKeyExpireHeight = types.AttributeKeyExpireHeight
|
||||||
AttributeKeyRandomNumber = types.AttributeKeyRandomNumber
|
AttributeKeyRandomNumber = types.AttributeKeyRandomNumber
|
||||||
AttributeKeyRandomNumberHash = types.AttributeKeyRandomNumberHash
|
AttributeKeyRandomNumberHash = types.AttributeKeyRandomNumberHash
|
||||||
@ -29,7 +28,6 @@ const (
|
|||||||
CreateAtomicSwap = types.CreateAtomicSwap
|
CreateAtomicSwap = types.CreateAtomicSwap
|
||||||
DefaultLongtermStorageDuration = types.DefaultLongtermStorageDuration
|
DefaultLongtermStorageDuration = types.DefaultLongtermStorageDuration
|
||||||
DefaultParamspace = types.DefaultParamspace
|
DefaultParamspace = types.DefaultParamspace
|
||||||
DepositAtomicSwap = types.DepositAtomicSwap
|
|
||||||
EventTypeClaimAtomicSwap = types.EventTypeClaimAtomicSwap
|
EventTypeClaimAtomicSwap = types.EventTypeClaimAtomicSwap
|
||||||
EventTypeCreateAtomicSwap = types.EventTypeCreateAtomicSwap
|
EventTypeCreateAtomicSwap = types.EventTypeCreateAtomicSwap
|
||||||
EventTypeRefundAtomicSwap = types.EventTypeRefundAtomicSwap
|
EventTypeRefundAtomicSwap = types.EventTypeRefundAtomicSwap
|
||||||
@ -61,7 +59,6 @@ var (
|
|||||||
NewKeeper = keeper.NewKeeper
|
NewKeeper = keeper.NewKeeper
|
||||||
NewQuerier = keeper.NewQuerier
|
NewQuerier = keeper.NewQuerier
|
||||||
RegisterRoutes = rest.RegisterRoutes
|
RegisterRoutes = rest.RegisterRoutes
|
||||||
BytesToHex = types.BytesToHex
|
|
||||||
CalculateRandomHash = types.CalculateRandomHash
|
CalculateRandomHash = types.CalculateRandomHash
|
||||||
CalculateSwapID = types.CalculateSwapID
|
CalculateSwapID = types.CalculateSwapID
|
||||||
DefaultGenesisState = types.DefaultGenesisState
|
DefaultGenesisState = types.DefaultGenesisState
|
||||||
@ -83,7 +80,6 @@ var (
|
|||||||
ErrSwapNotRefundable = types.ErrSwapNotRefundable
|
ErrSwapNotRefundable = types.ErrSwapNotRefundable
|
||||||
GenerateSecureRandomNumber = types.GenerateSecureRandomNumber
|
GenerateSecureRandomNumber = types.GenerateSecureRandomNumber
|
||||||
GetAtomicSwapByHeightKey = types.GetAtomicSwapByHeightKey
|
GetAtomicSwapByHeightKey = types.GetAtomicSwapByHeightKey
|
||||||
HexToBytes = types.HexToBytes
|
|
||||||
NewAssetSupply = types.NewAssetSupply
|
NewAssetSupply = types.NewAssetSupply
|
||||||
NewAtomicSwap = types.NewAtomicSwap
|
NewAtomicSwap = types.NewAtomicSwap
|
||||||
NewGenesisState = types.NewGenesisState
|
NewGenesisState = types.NewGenesisState
|
||||||
@ -98,8 +94,6 @@ var (
|
|||||||
NewSwapStatusFromString = types.NewSwapStatusFromString
|
NewSwapStatusFromString = types.NewSwapStatusFromString
|
||||||
ParamKeyTable = types.ParamKeyTable
|
ParamKeyTable = types.ParamKeyTable
|
||||||
RegisterCodec = types.RegisterCodec
|
RegisterCodec = types.RegisterCodec
|
||||||
Uint64FromBytes = types.Uint64FromBytes
|
|
||||||
Uint64ToBytes = types.Uint64ToBytes
|
|
||||||
|
|
||||||
// variable aliases
|
// variable aliases
|
||||||
AbsoluteMaximumBlockLock = types.AbsoluteMaximumBlockLock
|
AbsoluteMaximumBlockLock = types.AbsoluteMaximumBlockLock
|
||||||
|
@ -6,31 +6,43 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
tmtime "github.com/tendermint/tendermint/types/time"
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
|
|
||||||
"github.com/kava-labs/kava/x/bep3/types"
|
"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
|
// GetQueryCmd returns the cli query commands for this module
|
||||||
func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||||
// Group bep3 queries under a subcommand
|
// Group bep3 queries under a subcommand
|
||||||
bep3QueryCmd := &cobra.Command{
|
bep3QueryCmd := &cobra.Command{
|
||||||
Use: "bep3",
|
Use: "bep3",
|
||||||
Short: "Querying commands for the bep3 module",
|
Short: "Querying commands for the bep3 module",
|
||||||
|
DisableFlagParsing: true,
|
||||||
|
SuggestionsMinimumDistance: 2,
|
||||||
|
RunE: client.ValidateCmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
bep3QueryCmd.AddCommand(flags.GetCommands(
|
bep3QueryCmd.AddCommand(flags.GetCommands(
|
||||||
QueryCalcSwapIDCmd(queryRoute, cdc),
|
QueryCalcSwapIDCmd(queryRoute, cdc),
|
||||||
QueryCalcRandomNumberHashCmd(queryRoute, cdc),
|
QueryCalcRandomNumberHashCmd(queryRoute, cdc),
|
||||||
QueryGetAtomicSwapCmd(queryRoute, cdc),
|
|
||||||
QueryGetAssetSupplyCmd(queryRoute, cdc),
|
QueryGetAssetSupplyCmd(queryRoute, cdc),
|
||||||
|
QueryGetAssetSuppliesCmd(queryRoute, cdc),
|
||||||
|
QueryGetAtomicSwapCmd(queryRoute, cdc),
|
||||||
QueryGetAtomicSwapsCmd(queryRoute, cdc),
|
QueryGetAtomicSwapsCmd(queryRoute, cdc),
|
||||||
QueryParamsCmd(queryRoute, cdc),
|
QueryParamsCmd(queryRoute, cdc),
|
||||||
)...)
|
)...)
|
||||||
@ -70,10 +82,10 @@ func QueryCalcRandomNumberHashCmd(queryRoute string, cdc *codec.Codec) *cobra.Co
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
|
|
||||||
// Prepare random number, timestamp, and hash for output
|
// 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)
|
timestampStr := fmt.Sprintf("Timestamp: %d\n", timestamp)
|
||||||
randomNumberHashStr := fmt.Sprintf("Random number hash: %s", hex.EncodeToString(randomNumberHash))
|
randomNumberHashStr := fmt.Sprintf("Random number hash: %s", hex.EncodeToString(randomNumberHash))
|
||||||
output := []string{randomNumberStr, timestampStr, randomNumberHashStr}
|
output := []string{randomNumberStr, timestampStr, randomNumberHashStr}
|
||||||
@ -87,13 +99,13 @@ func QueryCalcSwapIDCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
Use: "calc-swapid [random-number-hash] [sender] [sender-other-chain]",
|
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",
|
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),
|
Args: cobra.MinimumNArgs(3),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
|
|
||||||
// Parse query params
|
// Parse query params
|
||||||
randomNumberHash, err := types.HexToBytes(args[0])
|
randomNumberHash, err := hex.DecodeString(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// QueryGetAtomicSwapCmd queries an AtomicSwap by swapID
|
||||||
func QueryGetAtomicSwapCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
func QueryGetAtomicSwapCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||||
return &cobra.Command{
|
return &cobra.Command{
|
||||||
@ -148,7 +187,7 @@ func QueryGetAtomicSwapCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
|
|
||||||
// Decode swapID's hex encoded string to []byte
|
// Decode swapID's hex encoded string to []byte
|
||||||
swapID, err := types.HexToBytes(args[0])
|
swapID, err := hex.DecodeString(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -176,29 +215,97 @@ func QueryGetAtomicSwapCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
|||||||
|
|
||||||
// QueryGetAtomicSwapsCmd queries AtomicSwaps in the store
|
// QueryGetAtomicSwapsCmd queries AtomicSwaps in the store
|
||||||
func QueryGetAtomicSwapsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
func QueryGetAtomicSwapsCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||||
return &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "swaps",
|
Use: "swaps",
|
||||||
Short: "get a list of active atomic swaps",
|
Short: "query atomic swaps with optional filters",
|
||||||
Example: "bep3 swaps",
|
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 {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var atomicSwaps types.AtomicSwaps
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
cdc.MustUnmarshalJSON(res, &atomicSwaps)
|
|
||||||
|
|
||||||
if len(atomicSwaps) == 0 {
|
res, height, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/%s", queryRoute, types.QueryGetAtomicSwaps), bz)
|
||||||
return fmt.Errorf("There are currently no atomic swaps")
|
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)
|
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
|
// QueryParamsCmd queries the bep3 module parameters
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
@ -27,6 +28,9 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
|||||||
bep3TxCmd := &cobra.Command{
|
bep3TxCmd := &cobra.Command{
|
||||||
Use: "bep3",
|
Use: "bep3",
|
||||||
Short: "bep3 transactions subcommands",
|
Short: "bep3 transactions subcommands",
|
||||||
|
DisableFlagParsing: true,
|
||||||
|
SuggestionsMinimumDistance: 2,
|
||||||
|
RunE: client.ValidateCmd,
|
||||||
}
|
}
|
||||||
|
|
||||||
bep3TxCmd.AddCommand(flags.PostCommands(
|
bep3TxCmd.AddCommand(flags.PostCommands(
|
||||||
@ -41,23 +45,23 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
|||||||
// GetCmdCreateAtomicSwap cli command for creating atomic swaps
|
// GetCmdCreateAtomicSwap cli command for creating atomic swaps
|
||||||
func GetCmdCreateAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
func GetCmdCreateAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
||||||
return &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",
|
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),
|
version.ClientName, types.ModuleName),
|
||||||
Args: cobra.ExactArgs(8),
|
Args: cobra.ExactArgs(6),
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||||
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(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])
|
to, err := sdk.AccAddressFromBech32(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
recipientOtherChain := args[1] // same as OtherExecutor.DeputyAddress
|
recipientOtherChain := args[1] // same as the other executor's deputy address
|
||||||
senderOtherChain := args[2]
|
senderOtherChain := args[2]
|
||||||
|
|
||||||
// Timestamp defaults to time.Now() unless it's explicitly set
|
// Timestamp defaults to time.Now() unless it's explicitly set
|
||||||
@ -77,10 +81,10 @@ func GetCmdCreateAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
|
|
||||||
// Print random number, timestamp, and hash to user's console
|
// 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("Timestamp: %d\n", timestamp)
|
||||||
fmt.Printf("Random number hash: %s\n\n", hex.EncodeToString(randomNumberHash))
|
fmt.Printf("Random number hash: %s\n\n", hex.EncodeToString(randomNumberHash))
|
||||||
|
|
||||||
@ -89,21 +93,14 @@ func GetCmdCreateAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedIncome := args[5]
|
heightSpan, err := strconv.ParseUint(args[5], 10, 64)
|
||||||
|
|
||||||
heightSpan, err := strconv.ParseInt(args[6], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
crossChain, err := strconv.ParseBool(args[7])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
msg := types.NewMsgCreateAtomicSwap(
|
msg := types.NewMsgCreateAtomicSwap(
|
||||||
from, to, recipientOtherChain, senderOtherChain, randomNumberHash,
|
from, to, recipientOtherChain, senderOtherChain,
|
||||||
timestamp, coins, expectedIncome, heightSpan, crossChain,
|
randomNumberHash, timestamp, coins, heightSpan,
|
||||||
)
|
)
|
||||||
|
|
||||||
err = msg.ValidateBasic()
|
err = msg.ValidateBasic()
|
||||||
@ -130,7 +127,7 @@ func GetCmdClaimAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
|||||||
|
|
||||||
from := cliCtx.GetFromAddress()
|
from := cliCtx.GetFromAddress()
|
||||||
|
|
||||||
swapID, err := types.HexToBytes(args[0])
|
swapID, err := hex.DecodeString(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -138,11 +135,7 @@ func GetCmdClaimAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
|||||||
if len(strings.TrimSpace(args[1])) == 0 {
|
if len(strings.TrimSpace(args[1])) == 0 {
|
||||||
return fmt.Errorf("random-number cannot be empty")
|
return fmt.Errorf("random-number cannot be empty")
|
||||||
}
|
}
|
||||||
|
randomNumber := []byte(args[1])
|
||||||
randomNumber, err := types.HexToBytes(args[1])
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := types.NewMsgClaimAtomicSwap(from, swapID, randomNumber)
|
msg := types.NewMsgClaimAtomicSwap(from, swapID, randomNumber)
|
||||||
|
|
||||||
@ -170,7 +163,7 @@ func GetCmdRefundAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
|||||||
|
|
||||||
from := cliCtx.GetFromAddress()
|
from := cliCtx.GetFromAddress()
|
||||||
|
|
||||||
swapID, err := types.HexToBytes(args[0])
|
swapID, err := hex.DecodeString(args[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
package rest
|
package rest
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
"github.com/gorilla/mux"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
|
||||||
"github.com/kava-labs/kava/x/bep3/types"
|
"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/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/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/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")
|
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())
|
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
swapID, err := types.HexToBytes(vars[restSwapID])
|
swapID, err := hex.DecodeString(vars[restSwapID])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
return
|
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 {
|
func queryAtomicSwapsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
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)
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
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 {
|
if err != nil {
|
||||||
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decode and return results
|
|
||||||
cliCtx = cliCtx.WithHeight(height)
|
cliCtx = cliCtx.WithHeight(height)
|
||||||
|
rest.PostProcessResponse(w, cliCtx, res)
|
||||||
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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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 {
|
func queryParamsHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
||||||
return func(w http.ResponseWriter, r *http.Request) {
|
return func(w http.ResponseWriter, r *http.Request) {
|
||||||
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
cliCtx, ok := rest.ParseQueryHeightOrReturnBadRequest(w, cliCtx, r)
|
||||||
|
@ -10,6 +10,15 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
"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
|
// RegisterRoutes registers bep3-related REST handlers to a router
|
||||||
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||||
registerQueryRoutes(cliCtx, r)
|
registerQueryRoutes(cliCtx, r)
|
||||||
@ -26,8 +35,7 @@ type PostCreateSwapReq struct {
|
|||||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||||
ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
|
HeightSpan uint64 `json:"height_span" yaml:"height_span"`
|
||||||
HeightSpan int64 `json:"height_span" yaml:"height_span"`
|
|
||||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,9 +41,7 @@ func postCreateHandlerFn(cliCtx context.CLIContext) http.HandlerFunc {
|
|||||||
req.RandomNumberHash,
|
req.RandomNumberHash,
|
||||||
req.Timestamp,
|
req.Timestamp,
|
||||||
req.Amount,
|
req.Amount,
|
||||||
req.ExpectedIncome,
|
|
||||||
req.HeightSpan,
|
req.HeightSpan,
|
||||||
req.CrossChain,
|
|
||||||
)
|
)
|
||||||
if err := msg.ValidateBasic(); err != nil {
|
if err := msg.ValidateBasic(); err != nil {
|
||||||
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
rest.WriteErrorResponse(w, http.StatusBadRequest, err.Error())
|
||||||
|
@ -37,8 +37,8 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper
|
|||||||
if !found {
|
if !found {
|
||||||
panic(fmt.Sprintf("invalid asset supply: %s is not a supported asset", coin.Denom))
|
panic(fmt.Sprintf("invalid asset supply: %s is not a supported asset", coin.Denom))
|
||||||
}
|
}
|
||||||
if !coin.Limit.Equal(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.Limit.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
|
// Increment current, incoming, and outgoing asset supplies
|
||||||
|
@ -89,7 +89,7 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
|||||||
IncomingSupply: c("bnb", 0),
|
IncomingSupply: c("bnb", 0),
|
||||||
OutgoingSupply: c("bnb", 0),
|
OutgoingSupply: c("bnb", 0),
|
||||||
CurrentSupply: c("bnb", assetParam.Limit.Add(i(1)).Int64()),
|
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)}
|
return app.GenesisState{"bep3": bep3.ModuleCdc.MustMarshalJSON(gs)}
|
||||||
@ -108,9 +108,9 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
|||||||
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||||
timestamp := ts(0)
|
timestamp := ts(0)
|
||||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
swap := bep3.NewAtomicSwap(cs(c("bnb", overLimitAmount.Int64())), randomNumberHash,
|
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)
|
TestRecipientOtherChain, 0, bep3.Open, true, bep3.Incoming)
|
||||||
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
||||||
|
|
||||||
@ -121,7 +121,7 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
|||||||
IncomingSupply: c("bnb", assetParam.Limit.Add(i(1)).Int64()),
|
IncomingSupply: c("bnb", assetParam.Limit.Add(i(1)).Int64()),
|
||||||
OutgoingSupply: c("bnb", 0),
|
OutgoingSupply: c("bnb", 0),
|
||||||
CurrentSupply: 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)}
|
return app.GenesisState{"bep3": bep3.ModuleCdc.MustMarshalJSON(gs)}
|
||||||
@ -141,9 +141,9 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
|||||||
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||||
timestamp := ts(0)
|
timestamp := ts(0)
|
||||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
swap := bep3.NewAtomicSwap(cs(c("bnb", halfLimit)), randomNumberHash,
|
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)
|
TestRecipientOtherChain, 0, bep3.Open, true, bep3.Incoming)
|
||||||
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
||||||
|
|
||||||
@ -154,7 +154,7 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
|||||||
IncomingSupply: c("bnb", halfLimit),
|
IncomingSupply: c("bnb", halfLimit),
|
||||||
OutgoingSupply: c("bnb", 0),
|
OutgoingSupply: c("bnb", 0),
|
||||||
CurrentSupply: c("bnb", overHalfLimit),
|
CurrentSupply: c("bnb", overHalfLimit),
|
||||||
Limit: c("bnb", assetParam.Limit.Int64()),
|
SupplyLimit: c("bnb", assetParam.Limit.Int64()),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
return app.GenesisState{"bep3": bep3.ModuleCdc.MustMarshalJSON(gs)}
|
return app.GenesisState{"bep3": bep3.ModuleCdc.MustMarshalJSON(gs)}
|
||||||
@ -171,7 +171,7 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
|||||||
IncomingSupply: c("fake", 0),
|
IncomingSupply: c("fake", 0),
|
||||||
OutgoingSupply: c("fake", 0),
|
OutgoingSupply: c("fake", 0),
|
||||||
CurrentSupply: 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)}
|
return app.GenesisState{"bep3": bep3.ModuleCdc.MustMarshalJSON(gs)}
|
||||||
@ -185,9 +185,9 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
|||||||
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||||
timestamp := ts(0)
|
timestamp := ts(0)
|
||||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
swap := bep3.NewAtomicSwap(cs(c("fake", 500000)), randomNumberHash,
|
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)
|
TestRecipientOtherChain, 0, bep3.Open, true, bep3.Incoming)
|
||||||
|
|
||||||
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
||||||
@ -202,9 +202,9 @@ func (suite *GenesisTestSuite) TestGenesisState() {
|
|||||||
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
_, addrs := app.GeneratePrivKeyAddressPairs(2)
|
||||||
timestamp := ts(0)
|
timestamp := ts(0)
|
||||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
swap := bep3.NewAtomicSwap(cs(c("bnb", 5000)), randomNumberHash,
|
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)
|
TestRecipientOtherChain, 0, bep3.NULL, true, bep3.Incoming)
|
||||||
|
|
||||||
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
gs.AtomicSwaps = bep3.AtomicSwaps{swap}
|
||||||
|
@ -25,7 +25,7 @@ func NewHandler(k Keeper) sdk.Handler {
|
|||||||
// handleMsgCreateAtomicSwap handles requests to create a new AtomicSwap
|
// handleMsgCreateAtomicSwap handles requests to create a new AtomicSwap
|
||||||
func handleMsgCreateAtomicSwap(ctx sdk.Context, k Keeper, msg MsgCreateAtomicSwap) (*sdk.Result, error) {
|
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,
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -47,31 +47,32 @@ func (suite *HandlerTestSuite) SetupTest() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (suite *HandlerTestSuite) AddAtomicSwap() (tmbytes.HexBytes, tmbytes.HexBytes) {
|
func (suite *HandlerTestSuite) AddAtomicSwap() (tmbytes.HexBytes, tmbytes.HexBytes) {
|
||||||
expireHeight := int64(360)
|
expireHeight := uint64(360)
|
||||||
amount := cs(c("bnb", int64(50000)))
|
amount := cs(c("bnb", int64(50000)))
|
||||||
timestamp := ts(0)
|
timestamp := ts(0)
|
||||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
|
|
||||||
// Create atomic swap and check err to confirm creation
|
// Create atomic swap and check err to confirm creation
|
||||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, randomNumberHash, timestamp, expireHeight,
|
err := suite.keeper.CreateAtomicSwap(suite.ctx, randomNumberHash, timestamp, expireHeight,
|
||||||
suite.addrs[0], suite.addrs[1], TestSenderOtherChain, TestRecipientOtherChain,
|
suite.addrs[0], suite.addrs[1], TestSenderOtherChain, TestRecipientOtherChain,
|
||||||
amount, amount.String(), true)
|
amount, true)
|
||||||
suite.Nil(err)
|
suite.Nil(err)
|
||||||
|
|
||||||
swapID := bep3.CalculateSwapID(randomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
swapID := bep3.CalculateSwapID(randomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
||||||
return swapID, randomNumber.Bytes()
|
return swapID, randomNumber[:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *HandlerTestSuite) TestMsgCreateAtomicSwap() {
|
func (suite *HandlerTestSuite) TestMsgCreateAtomicSwap() {
|
||||||
amount := cs(c("bnb", int64(10000)))
|
amount := cs(c("bnb", int64(10000)))
|
||||||
timestamp := ts(0)
|
timestamp := ts(0)
|
||||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
|
|
||||||
msg := bep3.NewMsgCreateAtomicSwap(
|
msg := bep3.NewMsgCreateAtomicSwap(
|
||||||
suite.addrs[0], suite.addrs[2], TestRecipientOtherChain, TestSenderOtherChain,
|
suite.addrs[0], suite.addrs[2], TestRecipientOtherChain,
|
||||||
randomNumberHash, timestamp, amount, amount.String(), int64(300), true)
|
TestSenderOtherChain, randomNumberHash, timestamp, amount,
|
||||||
|
uint64(300))
|
||||||
|
|
||||||
res, err := suite.handler(suite.ctx, msg)
|
res, err := suite.handler(suite.ctx, msg)
|
||||||
suite.Require().NoError(err)
|
suite.Require().NoError(err)
|
||||||
@ -81,9 +82,9 @@ func (suite *HandlerTestSuite) TestMsgCreateAtomicSwap() {
|
|||||||
func (suite *HandlerTestSuite) TestMsgClaimAtomicSwap() {
|
func (suite *HandlerTestSuite) TestMsgClaimAtomicSwap() {
|
||||||
// Attempt claim msg on fake atomic swap
|
// Attempt claim msg on fake atomic swap
|
||||||
badRandomNumber, _ := bep3.GenerateSecureRandomNumber()
|
badRandomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||||
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber.Bytes(), ts(0))
|
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber[:], ts(0))
|
||||||
badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
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)
|
badRes, err := suite.handler(suite.ctx, badMsg)
|
||||||
suite.Require().Error(err)
|
suite.Require().Error(err)
|
||||||
suite.Require().Nil(badRes)
|
suite.Require().Nil(badRes)
|
||||||
@ -99,7 +100,7 @@ func (suite *HandlerTestSuite) TestMsgClaimAtomicSwap() {
|
|||||||
func (suite *HandlerTestSuite) TestMsgRefundAtomicSwap() {
|
func (suite *HandlerTestSuite) TestMsgRefundAtomicSwap() {
|
||||||
// Attempt refund msg on fake atomic swap
|
// Attempt refund msg on fake atomic swap
|
||||||
badRandomNumber, _ := bep3.GenerateSecureRandomNumber()
|
badRandomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||||
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber.Bytes(), ts(0))
|
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber[:], ts(0))
|
||||||
badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
||||||
badMsg := bep3.NewMsgRefundAtomicSwap(suite.addrs[0], badSwapID)
|
badMsg := bep3.NewMsgRefundAtomicSwap(suite.addrs[0], badSwapID)
|
||||||
badRes, err := suite.handler(suite.ctx, badMsg)
|
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) {
|
func loadSwapAndSupply(addr sdk.AccAddress, index int) (bep3.AtomicSwap, bep3.AssetSupply) {
|
||||||
coin := c(DenomMap[index], 50000)
|
coin := c(DenomMap[index], 50000)
|
||||||
expireOffset := int64((index * 15) + 360) // Default expire height + offet to match timestamp
|
expireOffset := uint64((index * 15) + 360) // Default expire height + offet to match timestamp
|
||||||
timestamp := ts(index) // One minute apart
|
timestamp := ts(index) // One minute apart
|
||||||
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
randomNumber, _ := bep3.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := bep3.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := bep3.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
swap := bep3.NewAtomicSwap(cs(coin), randomNumberHash,
|
swap := bep3.NewAtomicSwap(cs(coin), randomNumberHash,
|
||||||
expireOffset, timestamp, addr, addr, TestSenderOtherChain,
|
expireOffset, timestamp, addr, addr, TestSenderOtherChain,
|
||||||
TestRecipientOtherChain, 1, bep3.Open, true, bep3.Incoming)
|
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
|
// Resulting current supply must be under asset's limit
|
||||||
if !supply.Limit.IsGTE(supply.CurrentSupply.Add(coin)) {
|
if !supply.SupplyLimit.IsGTE(supply.CurrentSupply.Add(coin)) {
|
||||||
return sdkerrors.Wrapf(types.ErrExceedsSupplyLimit, "increase %s, asset supply %s, limit %s", coin, supply.CurrentSupply, supply.Limit)
|
return sdkerrors.Wrapf(types.ErrExceedsSupplyLimit, "increase %s, asset supply %s, limit %s", coin, supply.CurrentSupply, supply.SupplyLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
supply.CurrentSupply = supply.CurrentSupply.Add(coin)
|
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
|
// Result of (current + incoming + amount) must be under asset's limit
|
||||||
totalSupply := supply.CurrentSupply.Add(supply.IncomingSupply)
|
totalSupply := supply.CurrentSupply.Add(supply.IncomingSupply)
|
||||||
if !supply.Limit.IsGTE(totalSupply.Add(coin)) {
|
if !supply.SupplyLimit.IsGTE(totalSupply.Add(coin)) {
|
||||||
return sdkerrors.Wrapf(types.ErrExceedsSupplyLimit, "increase %s, asset supply %s, limit %s", coin, totalSupply, supply.Limit)
|
return sdkerrors.Wrapf(types.ErrExceedsSupplyLimit, "increase %s, asset supply %s, limit %s", coin, totalSupply, supply.SupplyLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
supply.IncomingSupply = supply.IncomingSupply.Add(coin)
|
supply.IncomingSupply = supply.IncomingSupply.Add(coin)
|
||||||
|
@ -43,7 +43,7 @@ func (suite *AssetTestSuite) SetupTest() {
|
|||||||
IncomingSupply: c("bnb", 5),
|
IncomingSupply: c("bnb", 5),
|
||||||
OutgoingSupply: c("bnb", 5),
|
OutgoingSupply: c("bnb", 5),
|
||||||
CurrentSupply: c("bnb", 40),
|
CurrentSupply: c("bnb", 40),
|
||||||
Limit: c("bnb", 50),
|
SupplyLimit: c("bnb", 50),
|
||||||
}
|
}
|
||||||
keeper.SetAssetSupply(ctx, supply, []byte(supply.Denom))
|
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 {
|
func atomicSwap(ctx sdk.Context, index int) types.AtomicSwap {
|
||||||
expireOffset := int64((index * 15) + 360) // Default expire height + offet to match timestamp
|
expireOffset := uint64((index * 15) + 360) // Default expire height + offet to match timestamp
|
||||||
timestamp := ts(index) // One minute apart
|
timestamp := ts(index) // One minute apart
|
||||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
|
|
||||||
return types.NewAtomicSwap(cs(c("bnb", 50000)), randomNumberHash,
|
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,
|
TestSenderOtherChain, TestRecipientOtherChain, 0, types.Open, true,
|
||||||
types.Incoming)
|
types.Incoming)
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ func (k Keeper) IterateAtomicSwapsByBlock(ctx sdk.Context, inclusiveCutoffTime u
|
|||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapByBlockPrefix)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapByBlockPrefix)
|
||||||
iterator := store.Iterator(
|
iterator := store.Iterator(
|
||||||
nil, // start at the very start of the prefix store
|
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()
|
defer iterator.Close()
|
||||||
@ -146,15 +146,15 @@ func (k Keeper) IterateAtomicSwapsByBlock(ctx sdk.Context, inclusiveCutoffTime u
|
|||||||
// Completed swaps are stored for 1 week.
|
// Completed swaps are stored for 1 week.
|
||||||
func (k Keeper) InsertIntoLongtermStorage(ctx sdk.Context, atomicSwap types.AtomicSwap) {
|
func (k Keeper) InsertIntoLongtermStorage(ctx sdk.Context, atomicSwap types.AtomicSwap) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapLongtermStoragePrefix)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapLongtermStoragePrefix)
|
||||||
store.Set(types.GetAtomicSwapByHeightKey(atomicSwap.ClosedBlock+types.DefaultLongtermStorageDuration,
|
deletionHeight := uint64(atomicSwap.ClosedBlock) + types.DefaultLongtermStorageDuration
|
||||||
atomicSwap.GetSwapID()), atomicSwap.GetSwapID())
|
store.Set(types.GetAtomicSwapByHeightKey(deletionHeight, atomicSwap.GetSwapID()), atomicSwap.GetSwapID())
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveFromLongtermStorage removes a swap from the into the longterm storage index
|
// RemoveFromLongtermStorage removes a swap from the into the longterm storage index
|
||||||
func (k Keeper) RemoveFromLongtermStorage(ctx sdk.Context, atomicSwap types.AtomicSwap) {
|
func (k Keeper) RemoveFromLongtermStorage(ctx sdk.Context, atomicSwap types.AtomicSwap) {
|
||||||
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapLongtermStoragePrefix)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapLongtermStoragePrefix)
|
||||||
store.Delete(types.GetAtomicSwapByHeightKey(atomicSwap.ClosedBlock+types.DefaultLongtermStorageDuration,
|
deletionHeight := uint64(atomicSwap.ClosedBlock) + types.DefaultLongtermStorageDuration
|
||||||
atomicSwap.GetSwapID()))
|
store.Delete(types.GetAtomicSwapByHeightKey(deletionHeight, atomicSwap.GetSwapID()))
|
||||||
}
|
}
|
||||||
|
|
||||||
// IterateAtomicSwapsLongtermStorage provides an iterator over AtomicSwaps ordered by deletion height.
|
// 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)
|
store := prefix.NewStore(ctx.KVStore(k.key), types.AtomicSwapLongtermStoragePrefix)
|
||||||
iterator := store.Iterator(
|
iterator := store.Iterator(
|
||||||
nil, // start at the very start of the prefix store
|
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()
|
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
|
// Block index lacks getter methods, must use iteration to get count of swaps in store
|
||||||
var swapIDs [][]byte
|
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)
|
swapIDs = append(swapIDs, id)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
@ -145,7 +145,7 @@ func (suite *KeeperTestSuite) TestRemoveFromByBlockIndex() {
|
|||||||
|
|
||||||
// Check stored data in block index
|
// Check stored data in block index
|
||||||
var swapIDsPre [][]byte
|
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)
|
swapIDsPre = append(swapIDsPre, id)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
@ -155,7 +155,7 @@ func (suite *KeeperTestSuite) TestRemoveFromByBlockIndex() {
|
|||||||
|
|
||||||
// Check stored data not in block index
|
// Check stored data not in block index
|
||||||
var swapIDsPost [][]byte
|
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)
|
swapIDsPost = append(swapIDsPost, id)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
@ -178,10 +178,10 @@ func (suite *KeeperTestSuite) TestIterateAtomicSwapsByBlock() {
|
|||||||
// Initialize a new atomic swap (different randomNumberHash = different swap IDs)
|
// Initialize a new atomic swap (different randomNumberHash = different swap IDs)
|
||||||
timestamp := tmtime.Now().Add(time.Duration(i) * time.Minute).Unix()
|
timestamp := tmtime.Now().Add(time.Duration(i) * time.Minute).Unix()
|
||||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
|
|
||||||
atomicSwap := types.NewAtomicSwap(cs(c("bnb", 50000)), randomNumberHash,
|
atomicSwap := types.NewAtomicSwap(cs(c("bnb", 50000)), randomNumberHash,
|
||||||
blockCtx.BlockHeight(), timestamp, TestUser1, TestUser2,
|
uint64(blockCtx.BlockHeight()), timestamp, TestUser1, TestUser2,
|
||||||
TestSenderOtherChain, TestRecipientOtherChain, 0, types.Open,
|
TestSenderOtherChain, TestRecipientOtherChain, 0, types.Open,
|
||||||
true, types.Incoming)
|
true, types.Incoming)
|
||||||
|
|
||||||
@ -269,10 +269,10 @@ func (suite *KeeperTestSuite) TestIterateAtomicSwapsLongtermStorage() {
|
|||||||
for i := 0; i < 8; i++ {
|
for i := 0; i < 8; i++ {
|
||||||
timestamp := tmtime.Now().Unix()
|
timestamp := tmtime.Now().Unix()
|
||||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
|
|
||||||
atomicSwap := types.NewAtomicSwap(cs(c("bnb", 50000)), randomNumberHash,
|
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,
|
TestSenderOtherChain, TestRecipientOtherChain, 100, types.Open,
|
||||||
true, types.Incoming)
|
true, types.Incoming)
|
||||||
|
|
||||||
|
@ -25,13 +25,13 @@ func (k Keeper) GetBnbDeputyAddress(ctx sdk.Context) sdk.AccAddress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetMaxBlockLock returns the maximum block lock
|
// 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)
|
params := k.GetParams(ctx)
|
||||||
return params.MaxBlockLock
|
return params.MaxBlockLock
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMinBlockLock returns the minimum block lock
|
// 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)
|
params := k.GetParams(ctx)
|
||||||
return params.MinBlockLock
|
return params.MinBlockLock
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package keeper
|
|||||||
import (
|
import (
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
@ -16,6 +17,8 @@ func NewQuerier(keeper Keeper) sdk.Querier {
|
|||||||
switch path[0] {
|
switch path[0] {
|
||||||
case types.QueryGetAssetSupply:
|
case types.QueryGetAssetSupply:
|
||||||
return queryAssetSupply(ctx, req, keeper)
|
return queryAssetSupply(ctx, req, keeper)
|
||||||
|
case types.QueryGetAssetSupplies:
|
||||||
|
return queryAssetSupplies(ctx, req, keeper)
|
||||||
case types.QueryGetAtomicSwap:
|
case types.QueryGetAtomicSwap:
|
||||||
return queryAtomicSwap(ctx, req, keeper)
|
return queryAtomicSwap(ctx, req, keeper)
|
||||||
case types.QueryGetAtomicSwaps:
|
case types.QueryGetAtomicSwaps:
|
||||||
@ -50,6 +53,20 @@ func queryAssetSupply(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]
|
|||||||
return bz, nil
|
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) {
|
func queryAtomicSwap(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
|
||||||
// Decode request
|
// Decode request
|
||||||
var requestParams types.QueryAtomicSwapByID
|
var requestParams types.QueryAtomicSwapByID
|
||||||
@ -73,16 +90,21 @@ func queryAtomicSwap(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]b
|
|||||||
return bz, nil
|
return bz, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func queryAtomicSwaps(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (res []byte, err error) {
|
func queryAtomicSwaps(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
|
||||||
var swaps types.AtomicSwaps
|
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 {
|
unfilteredSwaps := keeper.GetAllAtomicSwaps(ctx)
|
||||||
swaps = append(swaps, s)
|
swaps := filterAtomicSwaps(ctx, unfilteredSwaps, params)
|
||||||
return false
|
if swaps == nil {
|
||||||
})
|
swaps = types.AtomicSwaps{}
|
||||||
|
}
|
||||||
|
|
||||||
bz, err2 := codec.MarshalJSONIndent(types.ModuleCdc, swaps)
|
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, swaps)
|
||||||
if err2 != nil {
|
if err != nil {
|
||||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
|
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
|
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)
|
isSwapID := make(map[string]bool)
|
||||||
for i := 0; i < 10; i++ {
|
for i := 0; i < 10; i++ {
|
||||||
// Set up atomic swap variables
|
// Set up atomic swap variables
|
||||||
expireHeight := int64(360)
|
expireHeight := uint64(360)
|
||||||
amount := cs(c("bnb", 100))
|
amount := cs(c("bnb", 100))
|
||||||
timestamp := ts(0)
|
timestamp := ts(0)
|
||||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
|
|
||||||
// Create atomic swap and check err
|
// Create atomic swap and check err
|
||||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, randomNumberHash, timestamp, expireHeight,
|
err := suite.keeper.CreateAtomicSwap(suite.ctx, randomNumberHash, timestamp, expireHeight,
|
||||||
addrs[0], suite.addrs[i], TestSenderOtherChain, TestRecipientOtherChain, amount,
|
addrs[0], suite.addrs[i], TestSenderOtherChain, TestRecipientOtherChain, amount, true)
|
||||||
amount.String(), true)
|
|
||||||
suite.Nil(err)
|
suite.Nil(err)
|
||||||
|
|
||||||
// Calculate swap ID and save
|
// Calculate swap ID and save
|
||||||
@ -129,12 +128,33 @@ func (suite *QuerierTestSuite) TestQueryAtomicSwap() {
|
|||||||
suite.True(suite.isSwapID[hex.EncodeToString(swap.GetSwapID())])
|
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() {
|
func (suite *QuerierTestSuite) TestQueryAtomicSwaps() {
|
||||||
ctx := suite.ctx.WithIsCheckTx(false)
|
ctx := suite.ctx.WithIsCheckTx(false)
|
||||||
// Set up request query
|
// Set up request query
|
||||||
query := abci.RequestQuery{
|
query := abci.RequestQuery{
|
||||||
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetAtomicSwaps}, "/"),
|
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)
|
bz, err := suite.querier(ctx, []string{types.QueryGetAtomicSwaps}, query)
|
||||||
|
@ -12,10 +12,10 @@ import (
|
|||||||
"github.com/kava-labs/kava/x/bep3/types"
|
"github.com/kava-labs/kava/x/bep3/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CreateAtomicSwap creates a new AtomicSwap
|
// CreateAtomicSwap creates a new atomic swap.
|
||||||
func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, timestamp int64, heightSpan int64,
|
func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, timestamp int64, heightSpan uint64,
|
||||||
sender sdk.AccAddress, recipient sdk.AccAddress, senderOtherChain, recipientOtherChain string,
|
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
|
// Confirm that this is not a duplicate swap
|
||||||
swapID := types.CalculateSwapID(randomNumberHash, sender, senderOtherChain)
|
swapID := types.CalculateSwapID(randomNumberHash, sender, senderOtherChain)
|
||||||
_, found := k.GetAtomicSwap(ctx, swapID)
|
_, 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
|
// Store the details of the swap
|
||||||
atomicSwap := types.NewAtomicSwap(amount, randomNumberHash, ctx.BlockHeight()+heightSpan,
|
expireHeight := uint64(ctx.BlockHeight()) + heightSpan
|
||||||
timestamp, sender, recipient, senderOtherChain, recipientOtherChain, 0, types.Open,
|
atomicSwap := types.NewAtomicSwap(amount, randomNumberHash, expireHeight, timestamp, sender,
|
||||||
crossChain, direction)
|
recipient, senderOtherChain, recipientOtherChain, 0, types.Open, crossChain, direction)
|
||||||
|
|
||||||
|
// Insert the atomic swap under both keys
|
||||||
k.SetAtomicSwap(ctx, atomicSwap)
|
k.SetAtomicSwap(ctx, atomicSwap)
|
||||||
k.InsertIntoByBlockIndex(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.AttributeKeyTimestamp, fmt.Sprintf("%d", atomicSwap.Timestamp)),
|
||||||
sdk.NewAttribute(types.AttributeKeySenderOtherChain, atomicSwap.SenderOtherChain),
|
sdk.NewAttribute(types.AttributeKeySenderOtherChain, atomicSwap.SenderOtherChain),
|
||||||
sdk.NewAttribute(types.AttributeKeyExpireHeight, fmt.Sprintf("%d", atomicSwap.ExpireHeight)),
|
sdk.NewAttribute(types.AttributeKeyExpireHeight, fmt.Sprintf("%d", atomicSwap.ExpireHeight)),
|
||||||
sdk.NewAttribute(types.AttributeKeyAmount, atomicSwap.Amount[0].String()),
|
sdk.NewAttribute(types.AttributeKeyAmount, atomicSwap.Amount.String()),
|
||||||
sdk.NewAttribute(types.AttributeKeyExpectedIncome, expectedIncome),
|
|
||||||
sdk.NewAttribute(types.AttributeKeyDirection, atomicSwap.Direction.String()),
|
sdk.NewAttribute(types.AttributeKeyDirection, atomicSwap.Direction.String()),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
@ -107,7 +107,7 @@ func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, times
|
|||||||
return nil
|
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 {
|
func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []byte, randomNumber []byte) error {
|
||||||
atomicSwap, found := k.GetAtomicSwap(ctx, swapID)
|
atomicSwap, found := k.GetAtomicSwap(ctx, swapID)
|
||||||
if !found {
|
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
|
// Only open atomic swaps can be claimed
|
||||||
if atomicSwap.Status != types.Open {
|
if atomicSwap.Status != types.Open {
|
||||||
return types.ErrSwapNotClaimable
|
return sdkerrors.Wrapf(types.ErrSwapNotClaimable, "status %s", atomicSwap.Status.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate hashed secret using submitted number
|
// 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
|
// Confirm that secret unlocks the atomic swap
|
||||||
if !bytes.Equal(hashedSecret, atomicSwap.GetSwapID()) {
|
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
|
var err error
|
||||||
switch atomicSwap.Direction {
|
switch atomicSwap.Direction {
|
||||||
case types.Incoming:
|
case types.Incoming:
|
||||||
err := k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0])
|
err = k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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.AttributeKeyRecipient, atomicSwap.Recipient.String()),
|
||||||
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, hex.EncodeToString(atomicSwap.GetSwapID())),
|
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, hex.EncodeToString(atomicSwap.GetSwapID())),
|
||||||
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, hex.EncodeToString(atomicSwap.RandomNumberHash)),
|
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, hex.EncodeToString(atomicSwap.RandomNumberHash)),
|
||||||
sdk.NewAttribute(types.AttributeKeyRandomNumber, hex.EncodeToString(randomNumber)),
|
sdk.NewAttribute(types.AttributeKeyRandomNumber, string(randomNumber)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
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 {
|
func (k Keeper) RefundAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []byte) error {
|
||||||
atomicSwap, found := k.GetAtomicSwap(ctx, swapID)
|
atomicSwap, found := k.GetAtomicSwap(ctx, swapID)
|
||||||
if !found {
|
if !found {
|
||||||
@ -190,7 +190,7 @@ func (k Keeper) RefundAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []
|
|||||||
}
|
}
|
||||||
// Only expired swaps may be refunded
|
// Only expired swaps may be refunded
|
||||||
if atomicSwap.Status != types.Expired {
|
if atomicSwap.Status != types.Expired {
|
||||||
return types.ErrSwapNotRefundable
|
return sdkerrors.Wrapf(types.ErrSwapNotRefundable, "status %s", atomicSwap.Status.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -225,10 +225,10 @@ func (k Keeper) RefundAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []
|
|||||||
ctx.EventManager().EmitEvent(
|
ctx.EventManager().EmitEvent(
|
||||||
sdk.NewEvent(
|
sdk.NewEvent(
|
||||||
types.EventTypeRefundAtomicSwap,
|
types.EventTypeRefundAtomicSwap,
|
||||||
sdk.NewAttribute(types.AttributeKeyRefundSender, fmt.Sprintf("%s", from)),
|
sdk.NewAttribute(types.AttributeKeyRefundSender, from.String()),
|
||||||
sdk.NewAttribute(types.AttributeKeySender, fmt.Sprintf("%s", atomicSwap.Sender)),
|
sdk.NewAttribute(types.AttributeKeySender, atomicSwap.Sender.String()),
|
||||||
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.GetSwapID()))),
|
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, hex.EncodeToString(atomicSwap.GetSwapID())),
|
||||||
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.RandomNumberHash))),
|
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.
|
// UpdateExpiredAtomicSwaps finds all AtomicSwaps that are past (or at) their ending times and expires them.
|
||||||
func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) error {
|
func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) {
|
||||||
var expiredSwaps [][]byte
|
var expiredSwapIDs []string
|
||||||
k.IterateAtomicSwapsByBlock(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
|
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
|
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
|
// Emit 'swaps_expired' event
|
||||||
ctx.EventManager().EmitEvent(
|
ctx.EventManager().EmitEvent(
|
||||||
sdk.NewEvent(
|
sdk.NewEvent(
|
||||||
@ -261,23 +261,18 @@ func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) error {
|
|||||||
sdk.NewAttribute(types.AttributeExpirationBlock, fmt.Sprintf("%d", ctx.BlockHeight())),
|
sdk.NewAttribute(types.AttributeExpirationBlock, fmt.Sprintf("%d", ctx.BlockHeight())),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteClosedAtomicSwapsFromLongtermStorage removes swaps one week after completion
|
// DeleteClosedAtomicSwapsFromLongtermStorage removes swaps one week after completion.
|
||||||
func (k Keeper) DeleteClosedAtomicSwapsFromLongtermStorage(ctx sdk.Context) error {
|
func (k Keeper) DeleteClosedAtomicSwapsFromLongtermStorage(ctx sdk.Context) {
|
||||||
var swapsToDelete [][]byte
|
|
||||||
k.IterateAtomicSwapsLongtermStorage(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
|
k.IterateAtomicSwapsLongtermStorage(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
|
||||||
swapsToDelete = append(swapsToDelete, id)
|
swap, found := k.GetAtomicSwap(ctx, id)
|
||||||
|
if !found {
|
||||||
|
// NOTE: shouldn't happen. Continue to next item.
|
||||||
return false
|
return false
|
||||||
})
|
}
|
||||||
|
|
||||||
// Delete closed atomic swaps
|
|
||||||
for _, id := range swapsToDelete {
|
|
||||||
swap, _ := k.GetAtomicSwap(ctx, id)
|
|
||||||
k.RemoveAtomicSwap(ctx, swap.GetSwapID())
|
k.RemoveAtomicSwap(ctx, swap.GetSwapID())
|
||||||
k.RemoveFromLongtermStorage(ctx, swap)
|
k.RemoveFromLongtermStorage(ctx, swap)
|
||||||
}
|
return false
|
||||||
return nil
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package keeper_test
|
package keeper_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -74,11 +73,11 @@ func (suite *AtomicSwapTestSuite) GenerateSwapDetails() {
|
|||||||
// Set up atomic swap details
|
// Set up atomic swap details
|
||||||
timestamp := ts(i)
|
timestamp := ts(i)
|
||||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
|
|
||||||
timestamps = append(timestamps, timestamp)
|
timestamps = append(timestamps, timestamp)
|
||||||
randomNumberHashes = append(randomNumberHashes, randomNumberHash)
|
randomNumberHashes = append(randomNumberHashes, randomNumberHash)
|
||||||
randomNumbers = append(randomNumbers, randomNumber.Bytes())
|
randomNumbers = append(randomNumbers, randomNumber[:])
|
||||||
}
|
}
|
||||||
suite.timestamps = timestamps
|
suite.timestamps = timestamps
|
||||||
suite.randomNumberHashes = randomNumberHashes
|
suite.randomNumberHashes = randomNumberHashes
|
||||||
@ -90,13 +89,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
type args struct {
|
type args struct {
|
||||||
randomNumberHash []byte
|
randomNumberHash []byte
|
||||||
timestamp int64
|
timestamp int64
|
||||||
heightSpan int64
|
heightSpan uint64
|
||||||
sender sdk.AccAddress
|
sender sdk.AccAddress
|
||||||
recipient sdk.AccAddress
|
recipient sdk.AccAddress
|
||||||
senderOtherChain string
|
senderOtherChain string
|
||||||
recipientOtherChain string
|
recipientOtherChain string
|
||||||
coins sdk.Coins
|
coins sdk.Coins
|
||||||
expectedIncome string
|
|
||||||
crossChain bool
|
crossChain bool
|
||||||
direction types.SwapDirection
|
direction types.SwapDirection
|
||||||
}
|
}
|
||||||
@ -113,13 +111,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
args{
|
args{
|
||||||
randomNumberHash: suite.randomNumberHashes[0],
|
randomNumberHash: suite.randomNumberHashes[0],
|
||||||
timestamp: suite.timestamps[0],
|
timestamp: suite.timestamps[0],
|
||||||
heightSpan: int64(360),
|
heightSpan: uint64(360),
|
||||||
sender: suite.deputy,
|
sender: suite.deputy,
|
||||||
recipient: suite.addrs[1],
|
recipient: suite.addrs[1],
|
||||||
senderOtherChain: TestSenderOtherChain,
|
senderOtherChain: TestSenderOtherChain,
|
||||||
recipientOtherChain: TestRecipientOtherChain,
|
recipientOtherChain: TestRecipientOtherChain,
|
||||||
coins: cs(c(BNB_DENOM, 50000)),
|
coins: cs(c(BNB_DENOM, 50000)),
|
||||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
|
||||||
crossChain: true,
|
crossChain: true,
|
||||||
direction: types.Incoming,
|
direction: types.Incoming,
|
||||||
},
|
},
|
||||||
@ -132,13 +129,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
args{
|
args{
|
||||||
randomNumberHash: suite.randomNumberHashes[0],
|
randomNumberHash: suite.randomNumberHashes[0],
|
||||||
timestamp: suite.timestamps[0],
|
timestamp: suite.timestamps[0],
|
||||||
heightSpan: int64(360),
|
heightSpan: uint64(360),
|
||||||
sender: suite.addrs[1],
|
sender: suite.addrs[1],
|
||||||
recipient: suite.addrs[2],
|
recipient: suite.addrs[2],
|
||||||
senderOtherChain: TestSenderOtherChain,
|
senderOtherChain: TestSenderOtherChain,
|
||||||
recipientOtherChain: TestRecipientOtherChain,
|
recipientOtherChain: TestRecipientOtherChain,
|
||||||
coins: cs(c(BNB_DENOM, 50000)),
|
coins: cs(c(BNB_DENOM, 50000)),
|
||||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
|
||||||
crossChain: true,
|
crossChain: true,
|
||||||
direction: types.Outgoing,
|
direction: types.Outgoing,
|
||||||
},
|
},
|
||||||
@ -151,13 +147,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
args{
|
args{
|
||||||
randomNumberHash: suite.randomNumberHashes[1],
|
randomNumberHash: suite.randomNumberHashes[1],
|
||||||
timestamp: suite.timestamps[1],
|
timestamp: suite.timestamps[1],
|
||||||
heightSpan: int64(360),
|
heightSpan: uint64(360),
|
||||||
sender: suite.deputy,
|
sender: suite.deputy,
|
||||||
recipient: suite.addrs[2],
|
recipient: suite.addrs[2],
|
||||||
senderOtherChain: TestSenderOtherChain,
|
senderOtherChain: TestSenderOtherChain,
|
||||||
recipientOtherChain: TestRecipientOtherChain,
|
recipientOtherChain: TestRecipientOtherChain,
|
||||||
coins: cs(c("xyz", 50000)),
|
coins: cs(c("xyz", 50000)),
|
||||||
expectedIncome: "50000xyz",
|
|
||||||
crossChain: true,
|
crossChain: true,
|
||||||
direction: types.Incoming,
|
direction: types.Incoming,
|
||||||
},
|
},
|
||||||
@ -170,13 +165,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
args{
|
args{
|
||||||
randomNumberHash: suite.randomNumberHashes[2],
|
randomNumberHash: suite.randomNumberHashes[2],
|
||||||
timestamp: suite.timestamps[2] - 2000,
|
timestamp: suite.timestamps[2] - 2000,
|
||||||
heightSpan: int64(360),
|
heightSpan: uint64(360),
|
||||||
sender: suite.deputy,
|
sender: suite.deputy,
|
||||||
recipient: suite.addrs[3],
|
recipient: suite.addrs[3],
|
||||||
senderOtherChain: TestSenderOtherChain,
|
senderOtherChain: TestSenderOtherChain,
|
||||||
recipientOtherChain: TestRecipientOtherChain,
|
recipientOtherChain: TestRecipientOtherChain,
|
||||||
coins: cs(c(BNB_DENOM, 50000)),
|
coins: cs(c(BNB_DENOM, 50000)),
|
||||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
|
||||||
crossChain: true,
|
crossChain: true,
|
||||||
direction: types.Incoming,
|
direction: types.Incoming,
|
||||||
},
|
},
|
||||||
@ -189,13 +183,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
args{
|
args{
|
||||||
randomNumberHash: suite.randomNumberHashes[3],
|
randomNumberHash: suite.randomNumberHashes[3],
|
||||||
timestamp: suite.timestamps[3] + 5000,
|
timestamp: suite.timestamps[3] + 5000,
|
||||||
heightSpan: int64(360),
|
heightSpan: uint64(360),
|
||||||
sender: suite.deputy,
|
sender: suite.deputy,
|
||||||
recipient: suite.addrs[4],
|
recipient: suite.addrs[4],
|
||||||
senderOtherChain: TestSenderOtherChain,
|
senderOtherChain: TestSenderOtherChain,
|
||||||
recipientOtherChain: TestRecipientOtherChain,
|
recipientOtherChain: TestRecipientOtherChain,
|
||||||
coins: cs(c(BNB_DENOM, 50000)),
|
coins: cs(c(BNB_DENOM, 50000)),
|
||||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
|
||||||
crossChain: true,
|
crossChain: true,
|
||||||
direction: types.Incoming,
|
direction: types.Incoming,
|
||||||
},
|
},
|
||||||
@ -208,13 +201,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
args{
|
args{
|
||||||
randomNumberHash: suite.randomNumberHashes[4],
|
randomNumberHash: suite.randomNumberHashes[4],
|
||||||
timestamp: suite.timestamps[4],
|
timestamp: suite.timestamps[4],
|
||||||
heightSpan: int64(5),
|
heightSpan: uint64(5),
|
||||||
sender: suite.deputy,
|
sender: suite.deputy,
|
||||||
recipient: suite.addrs[5],
|
recipient: suite.addrs[5],
|
||||||
senderOtherChain: TestSenderOtherChain,
|
senderOtherChain: TestSenderOtherChain,
|
||||||
recipientOtherChain: TestRecipientOtherChain,
|
recipientOtherChain: TestRecipientOtherChain,
|
||||||
coins: cs(c(BNB_DENOM, 50000)),
|
coins: cs(c(BNB_DENOM, 50000)),
|
||||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
|
||||||
crossChain: true,
|
crossChain: true,
|
||||||
direction: types.Incoming,
|
direction: types.Incoming,
|
||||||
},
|
},
|
||||||
@ -227,13 +219,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
args{
|
args{
|
||||||
randomNumberHash: suite.randomNumberHashes[5],
|
randomNumberHash: suite.randomNumberHashes[5],
|
||||||
timestamp: suite.timestamps[5],
|
timestamp: suite.timestamps[5],
|
||||||
heightSpan: int64(1000000),
|
heightSpan: uint64(1000000),
|
||||||
sender: suite.deputy,
|
sender: suite.deputy,
|
||||||
recipient: suite.addrs[6],
|
recipient: suite.addrs[6],
|
||||||
senderOtherChain: TestSenderOtherChain,
|
senderOtherChain: TestSenderOtherChain,
|
||||||
recipientOtherChain: TestRecipientOtherChain,
|
recipientOtherChain: TestRecipientOtherChain,
|
||||||
coins: cs(c(BNB_DENOM, 50000)),
|
coins: cs(c(BNB_DENOM, 50000)),
|
||||||
expectedIncome: fmt.Sprintf("50000%s", BNB_DENOM),
|
|
||||||
crossChain: true,
|
crossChain: true,
|
||||||
direction: types.Incoming,
|
direction: types.Incoming,
|
||||||
},
|
},
|
||||||
@ -246,13 +237,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
args{
|
args{
|
||||||
randomNumberHash: suite.randomNumberHashes[6],
|
randomNumberHash: suite.randomNumberHashes[6],
|
||||||
timestamp: suite.timestamps[6],
|
timestamp: suite.timestamps[6],
|
||||||
heightSpan: int64(360),
|
heightSpan: uint64(360),
|
||||||
sender: suite.deputy,
|
sender: suite.deputy,
|
||||||
recipient: suite.addrs[7],
|
recipient: suite.addrs[7],
|
||||||
senderOtherChain: TestSenderOtherChain,
|
senderOtherChain: TestSenderOtherChain,
|
||||||
recipientOtherChain: TestRecipientOtherChain,
|
recipientOtherChain: TestRecipientOtherChain,
|
||||||
coins: cs(c(BNB_DENOM, 0)),
|
coins: cs(c(BNB_DENOM, 0)),
|
||||||
expectedIncome: fmt.Sprintf("0%s", BNB_DENOM),
|
|
||||||
crossChain: true,
|
crossChain: true,
|
||||||
direction: types.Incoming,
|
direction: types.Incoming,
|
||||||
},
|
},
|
||||||
@ -265,13 +255,12 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
args{
|
args{
|
||||||
randomNumberHash: suite.randomNumberHashes[0],
|
randomNumberHash: suite.randomNumberHashes[0],
|
||||||
timestamp: suite.timestamps[0],
|
timestamp: suite.timestamps[0],
|
||||||
heightSpan: int64(360),
|
heightSpan: uint64(360),
|
||||||
sender: suite.deputy,
|
sender: suite.deputy,
|
||||||
recipient: suite.addrs[1],
|
recipient: suite.addrs[1],
|
||||||
senderOtherChain: TestSenderOtherChain,
|
senderOtherChain: TestSenderOtherChain,
|
||||||
recipientOtherChain: TestRecipientOtherChain,
|
recipientOtherChain: TestRecipientOtherChain,
|
||||||
coins: cs(c(BNB_DENOM, 50000)),
|
coins: cs(c(BNB_DENOM, 50000)),
|
||||||
expectedIncome: "50000bnb",
|
|
||||||
crossChain: true,
|
crossChain: true,
|
||||||
direction: types.Incoming,
|
direction: types.Incoming,
|
||||||
},
|
},
|
||||||
@ -305,7 +294,7 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
// Create atomic swap
|
// Create atomic swap
|
||||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, tc.args.randomNumberHash, tc.args.timestamp,
|
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.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
|
// Load sender's account after swap creation
|
||||||
senderAccPost := ak.GetAccount(suite.ctx, tc.args.sender)
|
senderAccPost := ak.GetAccount(suite.ctx, tc.args.sender)
|
||||||
@ -341,7 +330,7 @@ func (suite *AtomicSwapTestSuite) TestCreateAtomicSwap() {
|
|||||||
types.AtomicSwap{
|
types.AtomicSwap{
|
||||||
Amount: tc.args.coins,
|
Amount: tc.args.coins,
|
||||||
RandomNumberHash: tc.args.randomNumberHash,
|
RandomNumberHash: tc.args.randomNumberHash,
|
||||||
ExpireHeight: suite.ctx.BlockHeight() + tc.args.heightSpan,
|
ExpireHeight: uint64(suite.ctx.BlockHeight()) + tc.args.heightSpan,
|
||||||
Timestamp: tc.args.timestamp,
|
Timestamp: tc.args.timestamp,
|
||||||
Sender: tc.args.sender,
|
Sender: tc.args.sender,
|
||||||
Recipient: tc.args.recipient,
|
Recipient: tc.args.recipient,
|
||||||
@ -419,7 +408,7 @@ func (suite *AtomicSwapTestSuite) TestClaimAtomicSwap() {
|
|||||||
suite.ctx,
|
suite.ctx,
|
||||||
args{
|
args{
|
||||||
swapID: []byte{},
|
swapID: []byte{},
|
||||||
randomNumber: invalidRandomNumber.Bytes(),
|
randomNumber: invalidRandomNumber[:],
|
||||||
direction: types.Incoming,
|
direction: types.Incoming,
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
@ -462,8 +451,8 @@ func (suite *AtomicSwapTestSuite) TestClaimAtomicSwap() {
|
|||||||
|
|
||||||
// Create atomic swap
|
// Create atomic swap
|
||||||
err := suite.keeper.CreateAtomicSwap(suite.ctx, suite.randomNumberHashes[i], suite.timestamps[i],
|
err := suite.keeper.CreateAtomicSwap(suite.ctx, suite.randomNumberHashes[i], suite.timestamps[i],
|
||||||
int64(360), sender, expectedRecipient, TestSenderOtherChain, TestRecipientOtherChain,
|
uint64(360), sender, expectedRecipient, TestSenderOtherChain, TestRecipientOtherChain,
|
||||||
expectedClaimAmount, expectedClaimAmount.String(), true)
|
expectedClaimAmount, true)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
realSwapID := types.CalculateSwapID(suite.randomNumberHashes[i], sender, TestSenderOtherChain)
|
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],
|
err := suite.keeper.CreateAtomicSwap(suite.ctx, suite.randomNumberHashes[i], suite.timestamps[i],
|
||||||
int64(360), sender, suite.addrs[8], TestSenderOtherChain, TestRecipientOtherChain,
|
uint64(360), sender, suite.addrs[8], TestSenderOtherChain, TestRecipientOtherChain,
|
||||||
expectedRefundAmount, expectedRefundAmount.String(), true)
|
expectedRefundAmount, true)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
|
||||||
realSwapID := types.CalculateSwapID(suite.randomNumberHashes[i], sender, TestSenderOtherChain)
|
realSwapID := types.CalculateSwapID(suite.randomNumberHashes[i], sender, TestSenderOtherChain)
|
||||||
|
@ -27,7 +27,7 @@ func TestDecodeDistributionStore(t *testing.T) {
|
|||||||
|
|
||||||
oneCoin := sdk.NewCoin("coin", sdk.OneInt())
|
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)
|
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})
|
bz := tmbytes.HexBytes([]byte{1, 2})
|
||||||
|
|
||||||
kvPairs := kv.Pairs{
|
kvPairs := kv.Pairs{
|
||||||
|
@ -37,17 +37,17 @@ func GenRandBnbDeputy(r *rand.Rand) simulation.Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GenMinBlockLock randomized MinBlockLock
|
// GenMinBlockLock randomized MinBlockLock
|
||||||
func GenMinBlockLock(r *rand.Rand) int64 {
|
func GenMinBlockLock(r *rand.Rand) uint64 {
|
||||||
min := int(types.AbsoluteMinimumBlockLock)
|
min := int(types.AbsoluteMinimumBlockLock)
|
||||||
max := int(types.AbsoluteMaximumBlockLock)
|
max := int(types.AbsoluteMaximumBlockLock)
|
||||||
return int64(r.Intn(max-min) + min)
|
return uint64(r.Intn(max-min) + min)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenMaxBlockLock randomized MaxBlockLock
|
// GenMaxBlockLock randomized MaxBlockLock
|
||||||
func GenMaxBlockLock(r *rand.Rand, minBlockLock int64) int64 {
|
func GenMaxBlockLock(r *rand.Rand, minBlockLock uint64) uint64 {
|
||||||
min := int(minBlockLock)
|
min := int(minBlockLock)
|
||||||
max := int(types.AbsoluteMaximumBlockLock)
|
max := int(types.AbsoluteMaximumBlockLock)
|
||||||
return int64(r.Intn(max-min) + min)
|
return uint64(r.Intn(max-min) + min)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenSupportedAssets gets randomized SupportedAssets
|
// GenSupportedAssets gets randomized SupportedAssets
|
||||||
@ -101,7 +101,7 @@ func loadRandomBep3GenState(simState *module.SimulationState) types.GenesisState
|
|||||||
bnbDeputy := GenRandBnbDeputy(simState.Rand)
|
bnbDeputy := GenRandBnbDeputy(simState.Rand)
|
||||||
|
|
||||||
// min/max block lock are hardcoded to 50/100 for expected -NumBlocks=100
|
// min/max block lock are hardcoded to 50/100 for expected -NumBlocks=100
|
||||||
minBlockLock := int64(types.AbsoluteMinimumBlockLock)
|
minBlockLock := types.AbsoluteMinimumBlockLock
|
||||||
maxBlockLock := minBlockLock * 2
|
maxBlockLock := minBlockLock * 2
|
||||||
|
|
||||||
var supportedAssets types.AssetParams
|
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
|
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))
|
coins := sdk.NewCoins(sdk.NewCoin(denom, amount))
|
||||||
expectedIncome := coins.String()
|
|
||||||
|
|
||||||
// We're assuming that sims are run with -NumBlocks=100
|
// We're assuming that sims are run with -NumBlocks=100
|
||||||
heightSpan := int64(55)
|
heightSpan := uint64(55)
|
||||||
crossChain := true
|
|
||||||
|
|
||||||
msg := types.NewMsgCreateAtomicSwap(
|
msg := types.NewMsgCreateAtomicSwap(
|
||||||
sender.Address, recipient.Address, recipientOtherChain, senderOtherChain,
|
sender.Address, recipient.Address, recipientOtherChain, senderOtherChain,
|
||||||
randomNumberHash, timestamp, coins, expectedIncome, heightSpan, crossChain,
|
randomNumberHash, timestamp, coins, heightSpan,
|
||||||
)
|
)
|
||||||
|
|
||||||
tx := helpers.GenTx(
|
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)
|
swapID := types.CalculateSwapID(msg.RandomNumberHash, msg.From, msg.SenderOtherChain)
|
||||||
if r.Intn(100) < 50 {
|
if r.Intn(100) < 50 {
|
||||||
// Claim future operation
|
// Claim future operation
|
||||||
executionBlock := ctx.BlockHeight() + (msg.HeightSpan / 2)
|
executionBlock := uint64(ctx.BlockHeight()) + msg.HeightSpan/2
|
||||||
futureOp = simulation.FutureOperation{
|
futureOp = simulation.FutureOperation{
|
||||||
BlockHeight: int(executionBlock),
|
BlockHeight: int(executionBlock),
|
||||||
Op: operationClaimAtomicSwap(ak, k, swapID, randomNumber.BigInt().Bytes()),
|
Op: operationClaimAtomicSwap(ak, k, swapID, randomNumber.BigInt().Bytes()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Refund future operation
|
// Refund future operation
|
||||||
executionBlock := ctx.BlockHeight() + msg.HeightSpan
|
executionBlock := uint64(ctx.BlockHeight()) + msg.HeightSpan
|
||||||
futureOp = simulation.FutureOperation{
|
futureOp = simulation.FutureOperation{
|
||||||
BlockHeight: int(executionBlock),
|
BlockHeight: int(executionBlock),
|
||||||
Op: operationRefundAtomicSwap(ak, k, swapID),
|
Op: operationRefundAtomicSwap(ak, k, swapID),
|
||||||
|
@ -48,7 +48,6 @@ type AtomicSwap struct {
|
|||||||
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
|
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
|
||||||
ClosedBlock int64 `json:"closed_block" yaml:"closed_block"`
|
ClosedBlock int64 `json:"closed_block" yaml:"closed_block"`
|
||||||
Status SwapStatus `json:"status" yaml:"status"`
|
Status SwapStatus `json:"status" yaml:"status"`
|
||||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
|
||||||
Direction SwapDirection `json:"direction" yaml:"direction"`
|
Direction SwapDirection `json:"direction" yaml:"direction"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,9 +14,7 @@ type MsgCreateAtomicSwap struct {
|
|||||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||||
ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
|
|
||||||
HeightSpan int64 `json:"height_span" yaml:"height_span"`
|
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 | sender_other_chain | {sender other chain} |
|
||||||
| create_atomic_swap | expire_height | {swap expiration block} |
|
| create_atomic_swap | expire_height | {swap expiration block} |
|
||||||
| create_atomic_swap | amount | {coin amount} |
|
| create_atomic_swap | amount | {coin amount} |
|
||||||
| create_atomic_swap | expected_income | {expected value received}|
|
|
||||||
| create_atomic_swap | direction | {incoming or outgoing} |
|
| create_atomic_swap | direction | {incoming or outgoing} |
|
||||||
| message | module | bep3 |
|
| message | module | bep3 |
|
||||||
| message | sender | {sender address} |
|
| message | sender | {sender address} |
|
||||||
|
@ -1,19 +1,46 @@
|
|||||||
# Begin Block
|
# 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
|
```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 {
|
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
|
return false
|
||||||
})
|
})
|
||||||
|
```
|
||||||
// Expire incomplete swaps (claimed swaps have already been removed from byBlock index)
|
|
||||||
for _, id := range expiredSwaps {
|
## Deletion
|
||||||
atomicSwap, _ := k.GetAtomicSwap(ctx, id)
|
|
||||||
atomicSwap.Status = types.Expired
|
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:
|
||||||
k.SetAtomicSwap(ctx, atomicSwap)
|
|
||||||
k.RemoveFromByBlockIndex(ctx, atomicSwap)
|
```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"`
|
IncomingSupply sdk.Coin `json:"incoming_supply" yaml:"incoming_supply"`
|
||||||
OutgoingSupply sdk.Coin `json:"outgoing_supply" yaml:"outgoing_supply"`
|
OutgoingSupply sdk.Coin `json:"outgoing_supply" yaml:"outgoing_supply"`
|
||||||
CurrentSupply sdk.Coin `json:"current_supply" yaml:"current_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
|
// 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{
|
return AssetSupply{
|
||||||
Denom: denom,
|
Denom: denom,
|
||||||
IncomingSupply: incomingSupply,
|
IncomingSupply: incomingSupply,
|
||||||
OutgoingSupply: outgoingSupply,
|
OutgoingSupply: outgoingSupply,
|
||||||
CurrentSupply: currentSupply,
|
CurrentSupply: currentSupply,
|
||||||
Limit: limit,
|
SupplyLimit: supplyLimit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,31 +38,23 @@ func (a AssetSupply) Validate() error {
|
|||||||
if !a.CurrentSupply.IsValid() {
|
if !a.CurrentSupply.IsValid() {
|
||||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "current supply %s", a.CurrentSupply)
|
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "current supply %s", a.CurrentSupply)
|
||||||
}
|
}
|
||||||
if !a.Limit.IsValid() {
|
if !a.SupplyLimit.IsValid() {
|
||||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "limit %s", a.Limit)
|
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "supply limit %s", a.SupplyLimit)
|
||||||
}
|
}
|
||||||
return sdk.ValidateDenom(a.Denom)
|
return sdk.ValidateDenom(a.Denom)
|
||||||
}
|
}
|
||||||
|
|
||||||
// String implements stringer
|
// String implements stringer
|
||||||
func (a AssetSupply) String() string {
|
func (a AssetSupply) String() string {
|
||||||
return fmt.Sprintf("Asset Supply"+
|
return fmt.Sprintf(`
|
||||||
"\n Denom: %s"+
|
%s supply:
|
||||||
"\n Incoming supply: %s"+
|
Incoming supply: %s
|
||||||
"\n Outgoing supply: %s"+
|
Outgoing supply: %s
|
||||||
"\n Current supply: %s"+
|
Current supply: %s
|
||||||
"\n Limit: %s"+
|
Supply limit: %s
|
||||||
a.Denom, a.IncomingSupply, a.OutgoingSupply, a.CurrentSupply, a.Limit)
|
`,
|
||||||
|
a.Denom, a.IncomingSupply, a.OutgoingSupply, a.CurrentSupply, a.SupplyLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// AssetSupplies is a slice of AssetSupply
|
// AssetSupplies is a slice of AssetSupply
|
||||||
type AssetSupplies []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,
|
false,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"invalid limit",
|
"invalid supply limit",
|
||||||
AssetSupply{
|
AssetSupply{
|
||||||
IncomingSupply: coin,
|
IncomingSupply: coin,
|
||||||
OutgoingSupply: coin,
|
OutgoingSupply: coin,
|
||||||
CurrentSupply: coin,
|
CurrentSupply: coin,
|
||||||
Limit: invalidCoin,
|
SupplyLimit: invalidCoin,
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
@ -25,10 +25,10 @@ func atomicSwaps(count int) types.AtomicSwaps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func atomicSwap(index int) types.AtomicSwap {
|
func atomicSwap(index int) types.AtomicSwap {
|
||||||
expireOffset := int64((index * 15) + 360) // Default expire height + offet to match timestamp
|
expireOffset := uint64((index * 15) + 360) // Default expire height + offet to match timestamp
|
||||||
timestamp := ts(index) // One minute apart
|
timestamp := ts(index) // One minute apart
|
||||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
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],
|
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)
|
kavaAddrs[1], binanceAddrs[0].String(), binanceAddrs[1].String(), 1, types.Open, true, types.Incoming)
|
||||||
|
@ -16,7 +16,6 @@ const (
|
|||||||
AttributeKeySenderOtherChain = "sender_other_chain"
|
AttributeKeySenderOtherChain = "sender_other_chain"
|
||||||
AttributeKeyExpireHeight = "expire_height"
|
AttributeKeyExpireHeight = "expire_height"
|
||||||
AttributeKeyAmount = "amount"
|
AttributeKeyAmount = "amount"
|
||||||
AttributeKeyExpectedIncome = "expected_income"
|
|
||||||
AttributeKeyDirection = "direction"
|
AttributeKeyDirection = "direction"
|
||||||
AttributeKeyClaimSender = "claim_sender"
|
AttributeKeyClaimSender = "claim_sender"
|
||||||
AttributeKeyRandomNumber = "random_number"
|
AttributeKeyRandomNumber = "random_number"
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@ -13,22 +14,21 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GenerateSecureRandomNumber generates cryptographically strong pseudo-random number
|
// 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 := 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)
|
randomNumber, err := rand.Int(rand.Reader, max)
|
||||||
if err != nil {
|
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
|
// Ensure length of 64 for hexadecimal encoding by padding with 0s
|
||||||
if len(randomNumber.Text(16)) != 64 {
|
var paddedNumber [64]byte
|
||||||
return GenerateSecureRandomNumber()
|
copy(paddedNumber[:], fmt.Sprintf("%064x", randomNumber))
|
||||||
}
|
return paddedNumber, nil
|
||||||
|
|
||||||
return randomNumber, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CalculateRandomHash calculates the hash of a number and timestamp
|
// 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 {
|
func CalculateSwapID(randomNumberHash []byte, sender sdk.AccAddress, senderOtherChain string) []byte {
|
||||||
senderOtherChain = strings.ToLower(senderOtherChain)
|
senderOtherChain = strings.ToLower(senderOtherChain)
|
||||||
data := randomNumberHash
|
data := randomNumberHash
|
||||||
data = append(data, []byte(sender)...)
|
data = append(data, sender.Bytes()...)
|
||||||
data = append(data, []byte(senderOtherChain)...)
|
data = append(data, []byte(senderOtherChain)...)
|
||||||
return tmhash.Sum(data)
|
return tmhash.Sum(data)
|
||||||
}
|
}
|
||||||
|
@ -36,24 +36,24 @@ func (suite *HashTestSuite) TestGenerateSecureRandomNumber() {
|
|||||||
secureRandomNumber, err := types.GenerateSecureRandomNumber()
|
secureRandomNumber, err := types.GenerateSecureRandomNumber()
|
||||||
suite.Nil(err)
|
suite.Nil(err)
|
||||||
suite.NotNil(secureRandomNumber)
|
suite.NotNil(secureRandomNumber)
|
||||||
suite.Equal(64, len(secureRandomNumber.Text(16)))
|
suite.Equal(64, len(secureRandomNumber))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *HashTestSuite) TestCalculateRandomHash() {
|
func (suite *HashTestSuite) TestCalculateRandomHash() {
|
||||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||||
hash := types.CalculateRandomHash(randomNumber.Bytes(), suite.timestamps[0])
|
hash := types.CalculateRandomHash(randomNumber[:], suite.timestamps[0])
|
||||||
suite.NotNil(hash)
|
suite.NotNil(hash)
|
||||||
suite.Equal(32, len(hash))
|
suite.Equal(32, len(hash))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *HashTestSuite) TestCalculateSwapID() {
|
func (suite *HashTestSuite) TestCalculateSwapID() {
|
||||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
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())
|
swapID := types.CalculateSwapID(hash, suite.addrs[3], suite.addrs[5].String())
|
||||||
suite.NotNil(swapID)
|
suite.NotNil(swapID)
|
||||||
suite.Equal(32, len(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())
|
diffSwapID := types.CalculateSwapID(diffHash, suite.addrs[3], suite.addrs[5].String())
|
||||||
suite.NotEqual(swapID, diffSwapID)
|
suite.NotEqual(swapID, diffSwapID)
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
package types
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"encoding/hex"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -23,7 +22,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// DefaultLongtermStorageDuration is 1 week (assuming a block time of 7 seconds)
|
// DefaultLongtermStorageDuration is 1 week (assuming a block time of 7 seconds)
|
||||||
const DefaultLongtermStorageDuration int64 = 86400
|
const DefaultLongtermStorageDuration uint64 = 86400
|
||||||
|
|
||||||
// Key prefixes
|
// Key prefixes
|
||||||
var (
|
var (
|
||||||
@ -34,34 +33,6 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// GetAtomicSwapByHeightKey is used by the AtomicSwapByBlock index and AtomicSwapLongtermStorage index
|
// GetAtomicSwapByHeightKey is used by the AtomicSwapByBlock index and AtomicSwapLongtermStorage index
|
||||||
func GetAtomicSwapByHeightKey(height int64, swapID []byte) []byte {
|
func GetAtomicSwapByHeightKey(height uint64, swapID []byte) []byte {
|
||||||
return append(Uint64ToBytes(uint64(height)), swapID...)
|
return append(sdk.Uint64ToBigEndian(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
|
|
||||||
}
|
}
|
||||||
|
@ -14,7 +14,6 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
CreateAtomicSwap = "createAtomicSwap"
|
CreateAtomicSwap = "createAtomicSwap"
|
||||||
DepositAtomicSwap = "depositAtomicSwap"
|
|
||||||
ClaimAtomicSwap = "claimAtomicSwap"
|
ClaimAtomicSwap = "claimAtomicSwap"
|
||||||
RefundAtomicSwap = "refundAtomicSwap"
|
RefundAtomicSwap = "refundAtomicSwap"
|
||||||
CalcSwapID = "calcSwapID"
|
CalcSwapID = "calcSwapID"
|
||||||
@ -47,15 +46,13 @@ type MsgCreateAtomicSwap struct {
|
|||||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||||
ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
|
HeightSpan uint64 `json:"height_span" yaml:"height_span"`
|
||||||
HeightSpan int64 `json:"height_span" yaml:"height_span"`
|
|
||||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewMsgCreateAtomicSwap initializes a new MsgCreateAtomicSwap
|
// NewMsgCreateAtomicSwap initializes a new MsgCreateAtomicSwap
|
||||||
func NewMsgCreateAtomicSwap(from sdk.AccAddress, to sdk.AccAddress, recipientOtherChain,
|
func NewMsgCreateAtomicSwap(from sdk.AccAddress, to sdk.AccAddress, recipientOtherChain,
|
||||||
senderOtherChain string, randomNumberHash tmbytes.HexBytes, timestamp int64,
|
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{
|
return MsgCreateAtomicSwap{
|
||||||
From: from,
|
From: from,
|
||||||
To: to,
|
To: to,
|
||||||
@ -64,9 +61,7 @@ func NewMsgCreateAtomicSwap(from sdk.AccAddress, to sdk.AccAddress, recipientOth
|
|||||||
RandomNumberHash: randomNumberHash,
|
RandomNumberHash: randomNumberHash,
|
||||||
Timestamp: timestamp,
|
Timestamp: timestamp,
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
ExpectedIncome: expectedIncome,
|
|
||||||
HeightSpan: heightSpan,
|
HeightSpan: heightSpan,
|
||||||
CrossChain: crossChain,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,10 +73,9 @@ func (msg MsgCreateAtomicSwap) Type() string { return CreateAtomicSwap }
|
|||||||
|
|
||||||
// String prints the MsgCreateAtomicSwap
|
// String prints the MsgCreateAtomicSwap
|
||||||
func (msg MsgCreateAtomicSwap) String() string {
|
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.From, msg.To, msg.RecipientOtherChain, msg.SenderOtherChain,
|
||||||
msg.RandomNumberHash, msg.Timestamp, msg.Amount, msg.ExpectedIncome,
|
msg.RandomNumberHash, msg.Timestamp, msg.Amount, msg.HeightSpan)
|
||||||
msg.HeightSpan, msg.CrossChain)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInvolvedAddresses gets the addresses involved in a MsgCreateAtomicSwap
|
// GetInvolvedAddresses gets the addresses involved in a MsgCreateAtomicSwap
|
||||||
@ -108,14 +102,8 @@ func (msg MsgCreateAtomicSwap) ValidateBasic() error {
|
|||||||
if len(msg.To) != AddrByteCount {
|
if len(msg.To) != AddrByteCount {
|
||||||
return fmt.Errorf("the expected address length is %d, actual length is %d", AddrByteCount, len(msg.To))
|
return fmt.Errorf("the expected address length is %d, actual length is %d", AddrByteCount, len(msg.To))
|
||||||
}
|
}
|
||||||
if !msg.CrossChain && msg.RecipientOtherChain != "" {
|
if strings.TrimSpace(msg.RecipientOtherChain) == "" {
|
||||||
return errors.New("must leave recipient address on other chain to empty for single chain swap")
|
return errors.New("missing recipient address on other chain")
|
||||||
}
|
|
||||||
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 len(msg.RecipientOtherChain) > MaxOtherChainAddrLength {
|
if len(msg.RecipientOtherChain) > MaxOtherChainAddrLength {
|
||||||
return fmt.Errorf("the length of recipient address on other chain should be less than %d", 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() {
|
if !msg.Amount.IsValid() {
|
||||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String())
|
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 {
|
if msg.HeightSpan <= 0 {
|
||||||
return errors.New("height span must be positive")
|
return errors.New("height span must be positive")
|
||||||
}
|
}
|
||||||
|
@ -39,16 +39,12 @@ func TestMsgCreateAtomicSwap(t *testing.T) {
|
|||||||
randomNumberHash tmbytes.HexBytes
|
randomNumberHash tmbytes.HexBytes
|
||||||
timestamp int64
|
timestamp int64
|
||||||
amount sdk.Coins
|
amount sdk.Coins
|
||||||
expectedIncome string
|
heightSpan uint64
|
||||||
heightSpan int64
|
|
||||||
crossChain bool
|
|
||||||
expectPass bool
|
expectPass bool
|
||||||
}{
|
}{
|
||||||
{"normal", binanceAddrs[0], kavaAddrs[0], "", "", randomNumberHash, timestampInt64, coinsSingle, "50000bnb", 500, false, true},
|
{"normal cross-chain", binanceAddrs[0], kavaAddrs[0], kavaAddrs[0].String(), binanceAddrs[0].String(), randomNumberHash, timestampInt64, coinsSingle, 500, true},
|
||||||
{"cross-chain", binanceAddrs[0], kavaAddrs[0], kavaAddrs[0].String(), binanceAddrs[0].String(), randomNumberHash, timestampInt64, coinsSingle, "50000bnb", 80000, true, true},
|
{"without other chain fields", binanceAddrs[0], kavaAddrs[0], "", "", randomNumberHash, timestampInt64, coinsSingle, 500, false},
|
||||||
{"with other chain fields", binanceAddrs[0], kavaAddrs[0], kavaAddrs[0].String(), binanceAddrs[0].String(), randomNumberHash, timestampInt64, coinsSingle, "50000bnb", 500, false, false},
|
{"invalid amount", binanceAddrs[0], kavaAddrs[0], "", "", randomNumberHash, timestampInt64, coinsZero, 500, 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},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range tests {
|
for i, tc := range tests {
|
||||||
@ -60,9 +56,7 @@ func TestMsgCreateAtomicSwap(t *testing.T) {
|
|||||||
tc.randomNumberHash,
|
tc.randomNumberHash,
|
||||||
tc.timestamp,
|
tc.timestamp,
|
||||||
tc.amount,
|
tc.amount,
|
||||||
tc.expectedIncome,
|
|
||||||
tc.heightSpan,
|
tc.heightSpan,
|
||||||
tc.crossChain,
|
|
||||||
)
|
)
|
||||||
if tc.expectPass {
|
if tc.expectPass {
|
||||||
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
|
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
|
||||||
|
@ -20,10 +20,10 @@ var (
|
|||||||
KeyMaxBlockLock = []byte("MaxBlockLock")
|
KeyMaxBlockLock = []byte("MaxBlockLock")
|
||||||
KeySupportedAssets = []byte("SupportedAssets")
|
KeySupportedAssets = []byte("SupportedAssets")
|
||||||
|
|
||||||
AbsoluteMaximumBlockLock int64 = 10000
|
AbsoluteMaximumBlockLock uint64 = 10000
|
||||||
AbsoluteMinimumBlockLock int64 = 50
|
AbsoluteMinimumBlockLock uint64 = 50
|
||||||
DefaultMinBlockLock int64 = 80
|
DefaultMinBlockLock uint64 = 80
|
||||||
DefaultMaxBlockLock int64 = 600
|
DefaultMaxBlockLock uint64 = 600
|
||||||
DefaultSupportedAssets = AssetParams{
|
DefaultSupportedAssets = AssetParams{
|
||||||
AssetParam{
|
AssetParam{
|
||||||
Denom: "bnb",
|
Denom: "bnb",
|
||||||
@ -37,8 +37,8 @@ var (
|
|||||||
// Params governance parameters for bep3 module
|
// Params governance parameters for bep3 module
|
||||||
type Params struct {
|
type Params struct {
|
||||||
BnbDeputyAddress sdk.AccAddress `json:"bnb_deputy_address" yaml:"bnb_deputy_address"` // Bnbchain deputy address
|
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
|
MinBlockLock uint64 `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
|
MaxBlockLock uint64 `json:"max_block_lock" yaml:"max_block_lock"` // AtomicSwap maximum block lock
|
||||||
SupportedAssets AssetParams `json:"supported_assets" yaml:"supported_assets"` // Supported assets
|
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
|
// 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 {
|
) Params {
|
||||||
return Params{
|
return Params{
|
||||||
BnbDeputyAddress: bnbDeputyAddress,
|
BnbDeputyAddress: bnbDeputyAddress,
|
||||||
@ -159,7 +159,7 @@ func validateBnbDeputyAddressParam(i interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateMinBlockLockParam(i interface{}) error {
|
func validateMinBlockLockParam(i interface{}) error {
|
||||||
minBlockLock, ok := i.(int64)
|
minBlockLock, ok := i.(uint64)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid parameter type: %T", i)
|
return fmt.Errorf("invalid parameter type: %T", i)
|
||||||
}
|
}
|
||||||
@ -172,7 +172,7 @@ func validateMinBlockLockParam(i interface{}) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateMaxBlockLockParam(i interface{}) error {
|
func validateMaxBlockLockParam(i interface{}) error {
|
||||||
maxBlockLock, ok := i.(int64)
|
maxBlockLock, ok := i.(uint64)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("invalid parameter type: %T", i)
|
return fmt.Errorf("invalid parameter type: %T", i)
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,8 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
|||||||
|
|
||||||
type args struct {
|
type args struct {
|
||||||
bnbDeputyAddress sdk.AccAddress
|
bnbDeputyAddress sdk.AccAddress
|
||||||
minBlockLock int64
|
minBlockLock uint64
|
||||||
maxBlockLock int64
|
maxBlockLock uint64
|
||||||
supportedAssets types.AssetParams
|
supportedAssets types.AssetParams
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
package types
|
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 (
|
const (
|
||||||
// QueryGetAssetSupply command for getting info about an asset's supply
|
// QueryGetAssetSupply command for getting info about an asset's supply
|
||||||
QueryGetAssetSupply = "supply"
|
QueryGetAssetSupply = "supply"
|
||||||
|
// QueryGetAssetSupplies command for getting a list of asset supplies
|
||||||
|
QueryGetAssetSupplies = "supplies"
|
||||||
// QueryGetAtomicSwap command for getting info about an atomic swap
|
// QueryGetAtomicSwap command for getting info about an atomic swap
|
||||||
QueryGetAtomicSwap = "swap"
|
QueryGetAtomicSwap = "swap"
|
||||||
// QueryGetAtomicSwaps command for getting a list of atomic swaps
|
// 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'
|
// QueryAtomicSwapByID contains the params for query 'custom/bep3/swap'
|
||||||
type QueryAtomicSwapByID struct {
|
type QueryAtomicSwapByID struct {
|
||||||
SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
|
SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
|
||||||
@ -41,12 +60,21 @@ func NewQueryAtomicSwapByID(swapBytes tmbytes.HexBytes) QueryAtomicSwapByID {
|
|||||||
type QueryAtomicSwaps struct {
|
type QueryAtomicSwaps struct {
|
||||||
Page int `json:"page" yaml:"page"`
|
Page int `json:"page" yaml:"page"`
|
||||||
Limit int `json:"limit" yaml:"limit"`
|
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
|
// NewQueryAtomicSwaps creates a new instance of QueryAtomicSwaps
|
||||||
func NewQueryAtomicSwaps(page int, limit int) QueryAtomicSwaps {
|
func NewQueryAtomicSwaps(page, limit int, involve sdk.AccAddress, expiration uint64,
|
||||||
|
status SwapStatus, direction SwapDirection) QueryAtomicSwaps {
|
||||||
return QueryAtomicSwaps{
|
return QueryAtomicSwaps{
|
||||||
Page: page,
|
Page: page,
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
|
Involve: involve,
|
||||||
|
Expiration: expiration,
|
||||||
|
Status: status,
|
||||||
|
Direction: direction,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ import (
|
|||||||
type AtomicSwap struct {
|
type AtomicSwap struct {
|
||||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
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"`
|
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||||
Recipient sdk.AccAddress `json:"recipient" yaml:"recipient"`
|
Recipient sdk.AccAddress `json:"recipient" yaml:"recipient"`
|
||||||
@ -30,8 +30,8 @@ type AtomicSwap struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewAtomicSwap returns a new AtomicSwap
|
// NewAtomicSwap returns a new AtomicSwap
|
||||||
func NewAtomicSwap(amount sdk.Coins, randomNumberHash tmbytes.HexBytes, expireHeight, timestamp int64, sender,
|
func NewAtomicSwap(amount sdk.Coins, randomNumberHash tmbytes.HexBytes, expireHeight uint64, timestamp int64,
|
||||||
recipient sdk.AccAddress, senderOtherChain string, recipientOtherChain string, closedBlock int64,
|
sender, recipient sdk.AccAddress, senderOtherChain string, recipientOtherChain string, closedBlock int64,
|
||||||
status SwapStatus, crossChain bool, direction SwapDirection) AtomicSwap {
|
status SwapStatus, crossChain bool, direction SwapDirection) AtomicSwap {
|
||||||
return AtomicSwap{
|
return AtomicSwap{
|
||||||
Amount: amount,
|
Amount: amount,
|
||||||
@ -197,6 +197,16 @@ func (status *SwapStatus) UnmarshalJSON(data []byte) error {
|
|||||||
return nil
|
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
|
// SwapDirection is the direction of an AtomicSwap
|
||||||
type SwapDirection byte
|
type SwapDirection byte
|
||||||
|
|
||||||
@ -245,3 +255,12 @@ func (direction *SwapDirection) UnmarshalJSON(data []byte) error {
|
|||||||
*direction = NewSwapDirectionFromString(s)
|
*direction = NewSwapDirectionFromString(s)
|
||||||
return nil
|
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++ {
|
for i := 0; i < 10; i++ {
|
||||||
timestamp := ts(i)
|
timestamp := ts(i)
|
||||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||||
randomNumberHash := types.CalculateRandomHash(randomNumber.Bytes(), timestamp)
|
randomNumberHash := types.CalculateRandomHash(randomNumber[:], timestamp)
|
||||||
timestamps = append(timestamps, timestamp)
|
timestamps = append(timestamps, timestamp)
|
||||||
randomNumberHashes = append(randomNumberHashes, randomNumberHash)
|
randomNumberHashes = append(randomNumberHashes, randomNumberHash)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user