From 4bef84b932a8eb68385336b6fa6ff6ec7d98ab41 Mon Sep 17 00:00:00 2001 From: Christoph Otter Date: Thu, 1 Feb 2024 12:07:18 +0100 Subject: [PATCH] Use Array[Coin] instead of Coins --- ibc_test.go | 6 +++--- internal/api/api_test.go | 2 +- internal/api/iterator_test.go | 2 +- internal/api/lib_test.go | 28 ++++++++++++++-------------- internal/api/mocks.go | 14 +++++++------- lib_test.go | 6 +++--- types/env.go | 2 +- types/msg.go | 14 +++++++------- types/msg_test.go | 8 ++++---- types/queries.go | 12 ++++++------ types/types.go | 28 +--------------------------- 11 files changed, 48 insertions(+), 74 deletions(-) diff --git a/ibc_test.go b/ibc_test.go index 68851ee40..4212bc19e 100644 --- a/ibc_test.go +++ b/ibc_test.go @@ -96,7 +96,7 @@ func TestIBCHandshake(t *testing.T) { // instantiate it with this store store := api.NewLookup(gasMeter1) goapi := api.NewMockAPI() - balance := types.Coins{} + balance := types.Array[types.Coin]{} querier := api.DefaultQuerier(api.MOCK_CONTRACT_ADDR, balance) // instantiate @@ -169,7 +169,7 @@ func TestIBCPacketDispatch(t *testing.T) { // instantiate it with this store store := api.NewLookup(gasMeter1) goapi := api.NewMockAPI() - balance := types.Coins{} + balance := types.Array[types.Coin]{} querier := api.DefaultQuerier(api.MOCK_CONTRACT_ADDR, balance) // instantiate @@ -249,7 +249,7 @@ func TestIBCPacketDispatch(t *testing.T) { Msgs: []types.CosmosMsg{{ Bank: &types.BankMsg{Send: &types.SendMsg{ ToAddress: "my-friend", - Amount: types.Coins{types.NewCoin(12345678, "uatom")}, + Amount: types.Array[types.Coin]{types.NewCoin(12345678, "uatom")}, }}, }}, }, diff --git a/internal/api/api_test.go b/internal/api/api_test.go index dc0921b4c..cc3f25e5b 100644 --- a/internal/api/api_test.go +++ b/internal/api/api_test.go @@ -24,7 +24,7 @@ func TestValidateAddressFailure(t *testing.T) { // instantiate it with this store store := NewLookup(gasMeter) api := NewMockAPI() - querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Coins{types.NewCoin(100, "ATOM")}) + querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Array[types.Coin]{types.NewCoin(100, "ATOM")}) env := MockEnvBin(t) info := MockInfoBin(t, "creator") diff --git a/internal/api/iterator_test.go b/internal/api/iterator_test.go index 3585460fd..bf7a34635 100644 --- a/internal/api/iterator_test.go +++ b/internal/api/iterator_test.go @@ -31,7 +31,7 @@ func setupQueueContractWithData(t *testing.T, cache Cache, values ...int) queueD // instantiate it with this store store := NewLookup(gasMeter1) api := NewMockAPI() - querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Coins{types.NewCoin(100, "ATOM")}) + querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Array[types.Coin]{types.NewCoin(100, "ATOM")}) env := MockEnvBin(t) info := MockInfoBin(t, "creator") msg := []byte(`{}`) diff --git a/internal/api/lib_test.go b/internal/api/lib_test.go index 27e5e6bee..3d8725128 100644 --- a/internal/api/lib_test.go +++ b/internal/api/lib_test.go @@ -292,7 +292,7 @@ func TestGetMetrics(t *testing.T) { igasMeter := types.GasMeter(gasMeter) store := NewLookup(gasMeter) api := NewMockAPI() - querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Coins{types.NewCoin(100, "ATOM")}) + querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Array[types.Coin]{types.NewCoin(100, "ATOM")}) env := MockEnvBin(t) info := MockInfoBin(t, "creator") msg1 := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) @@ -397,7 +397,7 @@ func TestInstantiate(t *testing.T) { // instantiate it with this store store := NewLookup(gasMeter) api := NewMockAPI() - querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Coins{types.NewCoin(100, "ATOM")}) + querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Array[types.Coin]{types.NewCoin(100, "ATOM")}) env := MockEnvBin(t) info := MockInfoBin(t, "creator") msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) @@ -424,7 +424,7 @@ func TestExecute(t *testing.T) { // instantiate it with this store store := NewLookup(gasMeter1) api := NewMockAPI() - balance := types.Coins{types.NewCoin(250, "ATOM")} + balance := types.Array[types.Coin]{types.NewCoin(250, "ATOM")} querier := DefaultQuerier(MOCK_CONTRACT_ADDR, balance) env := MockEnvBin(t) info := MockInfoBin(t, "creator") @@ -489,7 +489,7 @@ func TestExecutePanic(t *testing.T) { // instantiate it with this store store := NewLookup(gasMeter1) api := NewMockAPI() - balance := types.Coins{types.NewCoin(250, "ATOM")} + balance := types.Array[types.Coin]{types.NewCoin(250, "ATOM")} querier := DefaultQuerier(MOCK_CONTRACT_ADDR, balance) env := MockEnvBin(t) info := MockInfoBin(t, "creator") @@ -518,7 +518,7 @@ func TestExecuteUnreachable(t *testing.T) { // instantiate it with this store store := NewLookup(gasMeter1) api := NewMockAPI() - balance := types.Coins{types.NewCoin(250, "ATOM")} + balance := types.Array[types.Coin]{types.NewCoin(250, "ATOM")} querier := DefaultQuerier(MOCK_CONTRACT_ADDR, balance) env := MockEnvBin(t) info := MockInfoBin(t, "creator") @@ -702,7 +702,7 @@ func TestExecuteUserErrorsInApiCalls(t *testing.T) { igasMeter1 := types.GasMeter(gasMeter1) // instantiate it with this store store := NewLookup(gasMeter1) - balance := types.Coins{types.NewCoin(250, "ATOM")} + balance := types.Array[types.Coin]{types.NewCoin(250, "ATOM")} querier := DefaultQuerier(MOCK_CONTRACT_ADDR, balance) env := MockEnvBin(t) info := MockInfoBin(t, "creator") @@ -733,7 +733,7 @@ func TestMigrate(t *testing.T) { // instantiate it with this store store := NewLookup(gasMeter) api := NewMockAPI() - balance := types.Coins{types.NewCoin(250, "ATOM")} + balance := types.Array[types.Coin]{types.NewCoin(250, "ATOM")} querier := DefaultQuerier(MOCK_CONTRACT_ADDR, balance) env := MockEnvBin(t) info := MockInfoBin(t, "creator") @@ -778,7 +778,7 @@ func TestMultipleInstances(t *testing.T) { igasMeter1 := types.GasMeter(gasMeter1) store1 := NewLookup(gasMeter1) api := NewMockAPI() - querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Coins{types.NewCoin(100, "ATOM")}) + querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Array[types.Coin]{types.NewCoin(100, "ATOM")}) env := MockEnvBin(t) info := MockInfoBin(t, "regen") msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) @@ -832,7 +832,7 @@ func TestSudo(t *testing.T) { // instantiate it with this store store := NewLookup(gasMeter1) api := NewMockAPI() - balance := types.Coins{types.NewCoin(250, "ATOM")} + balance := types.Array[types.Coin]{types.NewCoin(250, "ATOM")} querier := DefaultQuerier(MOCK_CONTRACT_ADDR, balance) env := MockEnvBin(t) info := MockInfoBin(t, "creator") @@ -862,7 +862,7 @@ func TestSudo(t *testing.T) { require.NotNil(t, dispatch.Bank.Send, "%#v", dispatch) send := dispatch.Bank.Send assert.Equal(t, "community-pool", send.ToAddress) - expectedPayout := types.Coins{types.NewCoin(700, "gold")} + expectedPayout := types.Array[types.Coin]{types.NewCoin(700, "gold")} assert.Equal(t, expectedPayout, send.Amount) } @@ -891,7 +891,7 @@ func TestDispatchSubmessage(t *testing.T) { ID: id, Msg: types.CosmosMsg{Bank: &types.BankMsg{Send: &types.SendMsg{ ToAddress: "friend", - Amount: types.Coins{types.NewCoin(1, "token")}, + Amount: types.Array[types.Coin]{types.NewCoin(1, "token")}, }}}, ReplyOn: types.ReplyAlways, } @@ -1067,7 +1067,7 @@ func TestQuery(t *testing.T) { igasMeter1 := types.GasMeter(gasMeter1) store := NewLookup(gasMeter1) api := NewMockAPI() - querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Coins{types.NewCoin(100, "ATOM")}) + querier := DefaultQuerier(MOCK_CONTRACT_ADDR, types.Array[types.Coin]{types.NewCoin(100, "ATOM")}) env := MockEnvBin(t) info := MockInfoBin(t, "creator") msg := []byte(`{"verifier": "fred", "beneficiary": "bob"}`) @@ -1110,7 +1110,7 @@ func TestHackatomQuerier(t *testing.T) { igasMeter := types.GasMeter(gasMeter) store := NewLookup(gasMeter) api := NewMockAPI() - initBalance := types.Coins{types.NewCoin(1234, "ATOM"), types.NewCoin(65432, "ETH")} + initBalance := types.Array[types.Coin]{types.NewCoin(1234, "ATOM"), types.NewCoin(65432, "ETH")} querier := DefaultQuerier("foobar", initBalance) // make a valid query to the other address @@ -1153,7 +1153,7 @@ func TestCustomReflectQuerier(t *testing.T) { igasMeter := types.GasMeter(gasMeter) store := NewLookup(gasMeter) api := NewMockAPI() - initBalance := types.Coins{types.NewCoin(1234, "ATOM")} + initBalance := types.Array[types.Coin]{types.NewCoin(1234, "ATOM")} querier := DefaultQuerier(MOCK_CONTRACT_ADDR, initBalance) // we need this to handle the custom requests from the reflect contract innerQuerier := querier.(*MockQuerier) diff --git a/internal/api/mocks.go b/internal/api/mocks.go index dbc5eecc4..84fcd7e65 100644 --- a/internal/api/mocks.go +++ b/internal/api/mocks.go @@ -412,8 +412,8 @@ type MockQuerier struct { var _ types.Querier = &MockQuerier{} -func DefaultQuerier(contractAddr string, coins types.Coins) types.Querier { - balances := map[string]types.Coins{ +func DefaultQuerier(contractAddr string, coins types.Array[types.Coin]) types.Querier { + balances := map[string]types.Array[types.Coin]{ contractAddr: coins, } return &MockQuerier{ @@ -449,11 +449,11 @@ func (q MockQuerier) GasConsumed() uint64 { } type BankQuerier struct { - Balances map[string]types.Coins + Balances map[string]types.Array[types.Coin] } -func NewBankQuerier(balances map[string]types.Coins) BankQuerier { - bal := make(map[string]types.Coins, len(balances)) +func NewBankQuerier(balances map[string]types.Array[types.Coin]) BankQuerier { + bal := make(map[string]types.Array[types.Coin], len(balances)) for k, v := range balances { dst := make([]types.Coin, len(v)) copy(dst, v) @@ -540,7 +540,7 @@ func (q ReflectCustom) Query(request json.RawMessage) ([]byte, error) { func TestBankQuerierAllBalances(t *testing.T) { addr := "foobar" - balance := types.Coins{types.NewCoin(12345678, "ATOM"), types.NewCoin(54321, "ETH")} + balance := types.Array[types.Coin]{types.NewCoin(12345678, "ATOM"), types.NewCoin(54321, "ETH")} q := DefaultQuerier(addr, balance) // query existing account @@ -576,7 +576,7 @@ func TestBankQuerierAllBalances(t *testing.T) { func TestBankQuerierBalance(t *testing.T) { addr := "foobar" - balance := types.Coins{types.NewCoin(12345678, "ATOM"), types.NewCoin(54321, "ETH")} + balance := types.Array[types.Coin]{types.NewCoin(12345678, "ATOM"), types.NewCoin(54321, "ETH")} q := DefaultQuerier(addr, balance) // query existing account with matching denom diff --git a/lib_test.go b/lib_test.go index 57572adcf..4d7a4c957 100644 --- a/lib_test.go +++ b/lib_test.go @@ -139,7 +139,7 @@ func TestHappyPath(t *testing.T) { // instantiate it with this store store := api.NewLookup(gasMeter1) goapi := api.NewMockAPI() - balance := types.Coins{types.NewCoin(250, "ATOM")} + balance := types.Array[types.Coin]{types.NewCoin(250, "ATOM")} querier := api.DefaultQuerier(api.MOCK_CONTRACT_ADDR, balance) // instantiate @@ -184,7 +184,7 @@ func TestEnv(t *testing.T) { // instantiate it with this store store := api.NewLookup(gasMeter1) goapi := api.NewMockAPI() - balance := types.Coins{types.NewCoin(250, "ATOM")} + balance := types.Array[types.Coin]{types.NewCoin(250, "ATOM")} querier := api.DefaultQuerier(api.MOCK_CONTRACT_ADDR, balance) // instantiate @@ -264,7 +264,7 @@ func TestGetMetrics(t *testing.T) { // instantiate it with this store store := api.NewLookup(gasMeter1) goapi := api.NewMockAPI() - balance := types.Coins{types.NewCoin(250, "ATOM")} + balance := types.Array[types.Coin]{types.NewCoin(250, "ATOM")} querier := api.DefaultQuerier(api.MOCK_CONTRACT_ADDR, balance) env := api.MockEnv() diff --git a/types/env.go b/types/env.go index 8ad0bbbe1..b175ab1e6 100644 --- a/types/env.go +++ b/types/env.go @@ -39,5 +39,5 @@ type MessageInfo struct { // Bech32 encoded sdk.AccAddress executing the contract Sender HumanAddress `json:"sender"` // Amount of funds send to the contract along with this message - Funds Coins `json:"funds"` + Funds Array[Coin] `json:"funds"` } diff --git a/types/msg.go b/types/msg.go index f43c0c2ad..016faaea0 100644 --- a/types/msg.go +++ b/types/msg.go @@ -102,15 +102,15 @@ type BankMsg struct { // SendMsg contains instructions for a Cosmos-SDK/SendMsg // It has a fixed interface here and should be converted into the proper SDK format before dispatching type SendMsg struct { - ToAddress string `json:"to_address"` - Amount Coins `json:"amount"` + ToAddress string `json:"to_address"` + Amount Array[Coin] `json:"amount"` } // BurnMsg will burn the given coins from the contract's account. // There is no Cosmos SDK message that performs this, but it can be done by calling the bank keeper. // Important if a contract controls significant token supply that must be retired. type BurnMsg struct { - Amount Coins `json:"amount"` + Amount Array[Coin] `json:"amount"` } type IBCMsg struct { @@ -284,7 +284,7 @@ type WithdrawDelegatorRewardMsg struct { // `depositor` is automatically filled with the current contract's address type FundCommunityPoolMsg struct { // Amount is the list of coins to be send to the community pool - Amount Coins `json:"amount"` + Amount Array[Coin] `json:"amount"` } // AnyMsg is encoded the same way as a protobof [Any](https://github.com/protocolbuffers/protobuf/blob/master/src/google/protobuf/any.proto). @@ -318,7 +318,7 @@ type ExecuteMsg struct { // as `userMsg` when calling `Handle` on the above-defined contract Msg []byte `json:"msg"` // Send is an optional amount of coins this contract sends to the called contract - Funds Coins `json:"funds"` + Funds Array[Coin] `json:"funds"` } // InstantiateMsg will create a new contract instance from a previously uploaded CodeID. @@ -330,7 +330,7 @@ type InstantiateMsg struct { // as `userMsg` when calling `Instantiate` on a new contract with the above-defined CodeID Msg []byte `json:"msg"` // Send is an optional amount of coins this contract sends to the called contract - Funds Coins `json:"funds"` + Funds Array[Coin] `json:"funds"` // Label is optional metadata to be stored with a contract instance. Label string `json:"label"` // Admin (optional) may be set here to allow future migrations from this address @@ -346,7 +346,7 @@ type Instantiate2Msg struct { // as `userMsg` when calling `Instantiate` on a new contract with the above-defined CodeID Msg []byte `json:"msg"` // Send is an optional amount of coins this contract sends to the called contract - Funds Coins `json:"funds"` + Funds Array[Coin] `json:"funds"` // Label is optional metadata to be stored with a contract instance. Label string `json:"label"` // Admin (optional) may be set here to allow future migrations from this address diff --git a/types/msg_test.go b/types/msg_test.go index cd8601505..c2ff5a3bf 100644 --- a/types/msg_test.go +++ b/types/msg_test.go @@ -26,7 +26,7 @@ func TestWasmMsgInstantiateSerialization(t *testing.T) { require.Equal(t, "", msg.Instantiate.Admin) require.Equal(t, uint64(7897), msg.Instantiate.CodeID) require.Equal(t, []byte(`{"claim":{}}`), msg.Instantiate.Msg) - require.Equal(t, Coins{ + require.Equal(t, Array[Coin]{ {"stones", "321"}, }, msg.Instantiate.Funds) require.Equal(t, "my instance", msg.Instantiate.Label) @@ -47,7 +47,7 @@ func TestWasmMsgInstantiateSerialization(t *testing.T) { require.Equal(t, "king", msg.Instantiate.Admin) require.Equal(t, uint64(7897), msg.Instantiate.CodeID) require.Equal(t, []byte(`{"claim":{}}`), msg.Instantiate.Msg) - require.Equal(t, Coins{ + require.Equal(t, Array[Coin]{ {"stones", "321"}, }, msg.Instantiate.Funds) require.Equal(t, "my instance", msg.Instantiate.Label) @@ -70,7 +70,7 @@ func TestWasmMsgInstantiate2Serialization(t *testing.T) { require.Equal(t, "", msg.Instantiate2.Admin) require.Equal(t, uint64(7897), msg.Instantiate2.CodeID) require.Equal(t, []byte(`{"claim":{}}`), msg.Instantiate2.Msg) - require.Equal(t, Coins{ + require.Equal(t, Array[Coin]{ {"stones", "321"}, }, msg.Instantiate2.Funds) require.Equal(t, "my instance", msg.Instantiate2.Label) @@ -161,5 +161,5 @@ func TestMsgFundCommunityPoolSerialization(t *testing.T) { err := json.Unmarshal(document, &msg) require.NoError(t, err) - require.Equal(t, Coins{{"adenom", "300"}, {"bdenom", "400"}}, msg.FundCommunityPool.Amount) + require.Equal(t, Array[Coin]{{"adenom", "300"}, {"bdenom", "400"}}, msg.FundCommunityPool.Amount) } diff --git a/types/queries.go b/types/queries.go index 2c39cc635..748003bee 100644 --- a/types/queries.go +++ b/types/queries.go @@ -143,7 +143,7 @@ type AllBalancesQuery struct { // AllBalancesResponse is the expected response to AllBalancesQuery type AllBalancesResponse struct { - Amount Coins `json:"amount"` + Amount Array[Coin] `json:"amount"` } type DenomMetadataQuery struct { @@ -320,11 +320,11 @@ type DelegationResponse struct { } type FullDelegation struct { - Delegator string `json:"delegator"` - Validator string `json:"validator"` - Amount Coin `json:"amount"` - AccumulatedRewards Coins `json:"accumulated_rewards"` - CanRedelegate Coin `json:"can_redelegate"` + Delegator string `json:"delegator"` + Validator string `json:"validator"` + Amount Coin `json:"amount"` + AccumulatedRewards Array[Coin] `json:"accumulated_rewards"` + CanRedelegate Coin `json:"can_redelegate"` } type BondedDenomResponse struct { diff --git a/types/types.go b/types/types.go index 04f2cddac..d82d7fc27 100644 --- a/types/types.go +++ b/types/types.go @@ -55,7 +55,7 @@ type CanonicalAddress = []byte // Coin is a string representation of the sdk.Coin type (more portable than sdk.Int) type Coin struct { Denom string `json:"denom"` // type, eg. "ATOM" - Amount string `json:"amount"` // string encoing of decimal value, eg. "12.3456" + Amount string `json:"amount"` // string encoding of decimal value, eg. "12.3456" } func NewCoin(amount uint64, denom string) Coin { @@ -65,32 +65,6 @@ func NewCoin(amount uint64, denom string) Coin { } } -// Coins handles properly serializing empty amounts -type Coins []Coin - -// MarshalJSON ensures that we get [] for empty arrays -func (c Coins) MarshalJSON() ([]byte, error) { - if len(c) == 0 { - return []byte("[]"), nil - } - var d []Coin = c - return json.Marshal(d) -} - -// UnmarshalJSON ensures that we get [] for empty arrays -func (c *Coins) UnmarshalJSON(data []byte) error { - // make sure we deserialize [] back to null - if string(data) == "[]" || string(data) == "null" { - return nil - } - var d []Coin - if err := json.Unmarshal(data, &d); err != nil { - return err - } - *c = d - return nil -} - // Replicating the cosmos-sdk bank module Metadata type type DenomMetadata struct { Description string `json:"description"`