-
Notifications
You must be signed in to change notification settings - Fork 31
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: implement token module encoder (#5)
* feat: implement token module encoder * fix: the wasm module does not depend on the encoder
- Loading branch information
Showing
19 changed files
with
999 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package keeper | ||
|
||
import ( | ||
"encoding/json" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/line/link-modules/x/token/internal/types" | ||
) | ||
|
||
func NewMsgEncodeHandler(tokenKeeper Keeper) types.EncodeHandler { | ||
return func(jsonMsg json.RawMessage) ([]sdk.Msg, error) { | ||
var wasmCustomMsg types.WasmCustomMsg | ||
err := json.Unmarshal(jsonMsg, &wasmCustomMsg) | ||
if err != nil { | ||
return nil, err | ||
} | ||
switch types.MsgRoute(wasmCustomMsg.Route) { | ||
case types.RIssue: | ||
return handleMsgIssue(wasmCustomMsg.Data) | ||
case types.RTransfer: | ||
return handleMsgTransfer(wasmCustomMsg.Data) | ||
case types.RMint: | ||
return handleMsgMint(wasmCustomMsg.Data) | ||
case types.RBurn: | ||
return handleMsgBurn(wasmCustomMsg.Data) | ||
case types.RGrantPerm: | ||
return handleMsgGrantPerm(wasmCustomMsg.Data) | ||
case types.RRevokePerm: | ||
return handleMsgRevokePerm(wasmCustomMsg.Data) | ||
case types.RModify: | ||
return handleMsgModify(wasmCustomMsg.Data) | ||
default: | ||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized Msg route: %T", wasmCustomMsg.Route) | ||
} | ||
} | ||
} | ||
|
||
func handleMsgIssue(msgData json.RawMessage) ([]sdk.Msg, error) { | ||
var wrapper types.IssueMsgWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) | ||
} | ||
return []sdk.Msg{wrapper.MsgIssue}, nil | ||
} | ||
|
||
func handleMsgTransfer(msgData json.RawMessage) ([]sdk.Msg, error) { | ||
var wrapper types.TransferMsgWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) | ||
} | ||
return []sdk.Msg{wrapper.MsgTransfer}, nil | ||
} | ||
|
||
func handleMsgMint(msgData json.RawMessage) ([]sdk.Msg, error) { | ||
var wrapper types.MintMsgWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) | ||
} | ||
return []sdk.Msg{wrapper.MsgMint}, nil | ||
} | ||
|
||
func handleMsgBurn(msgData json.RawMessage) ([]sdk.Msg, error) { | ||
var wrapper types.BurnMsgWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) | ||
} | ||
return []sdk.Msg{wrapper.MsgBurn}, nil | ||
} | ||
|
||
func handleMsgGrantPerm(msgData json.RawMessage) ([]sdk.Msg, error) { | ||
var wrapper types.GrantPermMsgWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) | ||
} | ||
return []sdk.Msg{wrapper.MsgGrantPermission}, nil | ||
} | ||
|
||
func handleMsgRevokePerm(msgData json.RawMessage) ([]sdk.Msg, error) { | ||
var wrapper types.RevokePermMsgWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) | ||
} | ||
return []sdk.Msg{wrapper.MsgRevokePermission}, nil | ||
} | ||
|
||
func handleMsgModify(msgData json.RawMessage) ([]sdk.Msg, error) { | ||
var wrapper types.ModifyMsgWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error()) | ||
} | ||
return []sdk.Msg{wrapper.MsgModify}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
package keeper | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"testing" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/line/link-modules/x/token/internal/types" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func Test_Encode(t *testing.T) { | ||
encodeHandler := NewMsgEncodeHandler(keeper) | ||
jsonMsg := json.RawMessage(`{"foo": 123}`) | ||
|
||
testContractID := "test_contract_id" | ||
issue := fmt.Sprintf(`{"route":"issue", "data":{"issue":{"owner":"%s","to":"%s","name":"TestToken1","symbol":"TT1","img_uri":"","meta":"","amount":"1000","mintable":true,"decimals":"18"}}}`, addr1.String(), addr2.String()) | ||
issueMsg := json.RawMessage(issue) | ||
transfer := fmt.Sprintf(`{"route":"transfer", "data":{"transfer":{"from":"%s", "contract_id":"%s", "to":"%s", "amount":"100"}}}`, addr1.String(), testContractID, addr2.String()) | ||
transferMsg := json.RawMessage(transfer) | ||
mint := fmt.Sprintf(`{"route":"mint", "data":{"mint":{"from":"%s", "contract_id":"%s", "to":"%s", "amount":"100"}}}`, addr1.String(), testContractID, addr2.String()) | ||
mintMsg := json.RawMessage(mint) | ||
burn := fmt.Sprintf(`{"route":"burn", "data":{"burn":{"from":"%s", "contract_id":"%s", "amount":"5"}}}`, addr1.String(), testContractID) | ||
burnMsg := json.RawMessage(burn) | ||
grantPermission := fmt.Sprintf(`{"route":"grant_perm", "data":{"grant_perm":{"from":"%s", "contract_id":"%s", "to":"%s", "permission":"mint"}}}`, addr1.String(), testContractID, addr2.String()) | ||
grantPermissionMsg := json.RawMessage(grantPermission) | ||
revokePermission := fmt.Sprintf(`{"route":"revoke_perm", "data":{"revoke_perm":{"from":"%s", "contract_id":"%s", "permission":"mint"}}}`, addr1.String(), testContractID) | ||
revokePermissionMsg := json.RawMessage(revokePermission) | ||
modify := fmt.Sprintf(`{"route":"modify","data":{"modify":{"owner":"%s","contract_id":"%s","changes":[{"field":"meta","value":"update_meta"}]}}}`, addr1.String(), testContractID) | ||
modifyMsg := json.RawMessage(modify) | ||
|
||
changes := types.NewChanges(types.NewChange("meta", "update_meta")) | ||
|
||
cases := map[string]struct { | ||
input json.RawMessage | ||
// set if valid | ||
output []sdk.Msg | ||
// set if invalid | ||
isError bool | ||
}{ | ||
"issue token": { | ||
input: issueMsg, | ||
output: []sdk.Msg{ | ||
types.MsgIssue{ | ||
Owner: addr1, | ||
To: addr2, | ||
Name: "TestToken1", | ||
Symbol: "TT1", | ||
ImageURI: "", | ||
Meta: "", | ||
Amount: sdk.NewInt(1000), | ||
Mintable: true, | ||
Decimals: sdk.NewInt(18), | ||
}, | ||
}, | ||
}, | ||
"transfer token": { | ||
input: transferMsg, | ||
output: []sdk.Msg{ | ||
types.MsgTransfer{ | ||
From: addr1, | ||
ContractID: testContractID, | ||
To: addr2, | ||
Amount: sdk.NewInt(100), | ||
}, | ||
}, | ||
}, | ||
"mint token": { | ||
input: mintMsg, | ||
output: []sdk.Msg{ | ||
types.MsgMint{ | ||
From: addr1, | ||
ContractID: testContractID, | ||
To: addr2, | ||
Amount: sdk.NewInt(100), | ||
}, | ||
}, | ||
}, | ||
"burn token": { | ||
input: burnMsg, | ||
output: []sdk.Msg{ | ||
types.NewMsgBurn(addr1, testContractID, sdk.NewInt(5)), | ||
}, | ||
}, | ||
"grant permission": { | ||
input: grantPermissionMsg, | ||
output: []sdk.Msg{ | ||
types.NewMsgGrantPermission(addr1, testContractID, addr2, types.Permission("mint")), | ||
}, | ||
}, | ||
"revoke permission": { | ||
input: revokePermissionMsg, | ||
output: []sdk.Msg{ | ||
types.NewMsgRevokePermission(addr1, testContractID, types.Permission("mint")), | ||
}, | ||
}, | ||
"modify token": { | ||
input: modifyMsg, | ||
output: []sdk.Msg{ | ||
types.NewMsgModify(addr1, testContractID, changes), | ||
}, | ||
}, | ||
"unknown custom msg": { | ||
input: jsonMsg, | ||
isError: true, | ||
}, | ||
} | ||
|
||
for name, tc := range cases { | ||
tc := tc | ||
t.Run(name, func(t *testing.T) { | ||
res, err := encodeHandler(tc.input) | ||
if tc.isError { | ||
require.Error(t, err) | ||
} else { | ||
require.NoError(t, err) | ||
assert.Equal(t, tc.output, res) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
package querier | ||
|
||
import ( | ||
"encoding/json" | ||
|
||
"github.com/cosmos/cosmos-sdk/codec" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/line/link-modules/x/token/internal/types" | ||
abci "github.com/tendermint/tendermint/abci/types" | ||
) | ||
|
||
func NewQueryEncoder(tokenQuerier sdk.Querier) types.EncodeQuerier { | ||
return func(ctx sdk.Context, jsonQuerier json.RawMessage) ([]byte, error) { | ||
var customQuerier types.WasmCustomQuerier | ||
err := json.Unmarshal(jsonQuerier, &customQuerier) | ||
if err != nil { | ||
return nil, err | ||
} | ||
switch customQuerier.Route { | ||
case types.QueryTokens: | ||
return handleQueryToken(ctx, tokenQuerier, []string{customQuerier.Route}, customQuerier.Data) | ||
case types.QueryBalance: | ||
return handleQueryBalance(ctx, tokenQuerier, []string{customQuerier.Route}, customQuerier.Data) | ||
case types.QuerySupply: | ||
return handleQueryTotal(ctx, tokenQuerier, customQuerier.Data) | ||
case types.QueryPerms: | ||
return handleQueryPerms(ctx, tokenQuerier, []string{customQuerier.Route}, customQuerier.Data) | ||
default: | ||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized Msg route: %T", customQuerier.Route) | ||
} | ||
} | ||
} | ||
|
||
func handleQueryToken(ctx sdk.Context, tokenQuerier sdk.Querier, path []string, msgData json.RawMessage) ([]byte, error) { | ||
var wrapper types.QueryTokenWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, err | ||
} | ||
req := makeRequestQuery(nil) | ||
|
||
contractID := wrapper.QueryTokenParam.ContractID | ||
if contractID != "" { | ||
path = append(path, contractID) | ||
} | ||
return tokenQuerier(ctx, path, req) | ||
} | ||
|
||
func handleQueryBalance(ctx sdk.Context, tokenQuerier sdk.Querier, path []string, msgData json.RawMessage) ([]byte, error) { | ||
var wrapper types.QueryBalanceWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
req := makeRequestQuery(types.QueryContractIDAccAddressParams{ | ||
Addr: wrapper.QueryBalanceParam.Address, | ||
}) | ||
|
||
contractID := wrapper.QueryBalanceParam.ContractID | ||
if contractID != "" { | ||
path = append(path, contractID) | ||
} | ||
return tokenQuerier(ctx, path, req) | ||
} | ||
|
||
func handleQueryTotal(ctx sdk.Context, tokenQuerier sdk.Querier, msgData json.RawMessage) ([]byte, error) { | ||
var wrapper types.QueryTotalWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, err | ||
} | ||
req := makeRequestQuery(nil) | ||
|
||
path := []string{wrapper.QueryTotalParam.Target} | ||
contractID := wrapper.QueryTotalParam.ContractID | ||
if contractID != "" { | ||
path = append(path, contractID) | ||
} | ||
return tokenQuerier(ctx, path, req) | ||
} | ||
|
||
func handleQueryPerms(ctx sdk.Context, tokenQuerier sdk.Querier, path []string, msgData json.RawMessage) ([]byte, error) { | ||
var wrapper types.QueryPermWrapper | ||
err := json.Unmarshal(msgData, &wrapper) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
req := makeRequestQuery(types.QueryContractIDAccAddressParams{ | ||
Addr: wrapper.QueryPermParam.Address, | ||
}) | ||
|
||
contractID := wrapper.QueryPermParam.ContractID | ||
if contractID != "" { | ||
path = append(path, contractID) | ||
} | ||
return tokenQuerier(ctx, path, req) | ||
} | ||
|
||
func makeRequestQuery(params interface{}) abci.RequestQuery { | ||
req := abci.RequestQuery{ | ||
Path: "", | ||
Data: []byte(string(codec.MustMarshalJSONIndent(types.ModuleCdc, params))), | ||
} | ||
return req | ||
} |
Oops, something went wrong.