Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem: external token mapping not manageable directly #128

Merged
merged 3 commits into from
Oct 7, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

- [cronos#110](https://github.com/crypto-org-chain/cronos/pull/110) embed swagger doc ui
- [cronos#113](https://github.com/crypto-org-chain/cronos/pull/113) export token mapping state to genesis
- [cronos#128](https://github.com/crypto-org-chain/cronos/pull/128) add native message to update token mapping

*September 22, 2021*
## v0.5.4
Expand Down
9 changes: 8 additions & 1 deletion app/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
cronostypes "github.com/crypto-org-chain/cronos/x/cronos/types"
)

const (
Expand Down Expand Up @@ -67,8 +68,14 @@ func setup(withGenesis bool, invCheckPeriod uint) (*App, GenesisState) {
}

// Setup initializes a new App. A Nop logger is set in App.
func Setup(isCheckTx bool) *App {
func Setup(isCheckTx bool, cronosAdmin string) *App {
app, genesisState := setup(!isCheckTx, 5)

// set cronos_admin for test
cronosGen := cronostypes.DefaultGenesis()
cronosGen.Params.CronosAdmin = cronosAdmin
genesisState["cronos"] = app.cdc.MustMarshalJSON(cronosGen)

if !isCheckTx {
// init chain must be called to stop deliverState from being nil
stateBytes, err := json.MarshalIndent(genesisState, "", " ")
Expand Down
31 changes: 30 additions & 1 deletion docs/api/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
- [MsgConvertVouchersResponse](#cronos.MsgConvertVouchersResponse)
- [MsgTransferTokens](#cronos.MsgTransferTokens)
- [MsgTransferTokensResponse](#cronos.MsgTransferTokensResponse)
- [MsgUpdateTokenMapping](#cronos.MsgUpdateTokenMapping)
- [MsgUpdateTokenMappingResponse](#cronos.MsgUpdateTokenMappingResponse)

- [Msg](#cronos.Msg)

Expand All @@ -49,6 +51,7 @@ Params defines the parameters for the cronos module.
| ----- | ---- | ----- | ----------- |
| `ibc_cro_denom` | [string](#string) | | |
| `ibc_timeout` | [uint64](#uint64) | | |
| `cronos_admin` | [string](#string) | | the admin address who can update token mapping |
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we want multiple admins?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, we can do that later if wanted.




Expand Down Expand Up @@ -274,7 +277,32 @@ MsgTransferTokens represents a message to transfer cronos evm coins through ibc.
### MsgTransferTokensResponse
MsgTransferTokensResponse defines the TransferTokens response type.

this line is used by starport scaffolding # proto/tx/message





<a name="cronos.MsgUpdateTokenMapping"></a>

### MsgUpdateTokenMapping
MsgUpdateTokenMapping defines the request type


| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `sender` | [string](#string) | | |
| `denom` | [string](#string) | | |
| `contract` | [string](#string) | | |






<a name="cronos.MsgUpdateTokenMappingResponse"></a>

### MsgUpdateTokenMappingResponse
MsgUpdateTokenMappingResponse defines the response type



Expand All @@ -296,6 +324,7 @@ Msg defines the Cronos Msg service
| ----------- | ------------ | ------------- | ------------| ------- | -------- |
| `ConvertVouchers` | [MsgConvertVouchers](#cronos.MsgConvertVouchers) | [MsgConvertVouchersResponse](#cronos.MsgConvertVouchersResponse) | ConvertVouchers defines a method for converting ibc voucher to cronos evm coins. | |
| `TransferTokens` | [MsgTransferTokens](#cronos.MsgTransferTokens) | [MsgTransferTokensResponse](#cronos.MsgTransferTokensResponse) | TransferTokens defines a method to transfer cronos evm coins to another chain through IBC | |
| `UpdateTokenMapping` | [MsgUpdateTokenMapping](#cronos.MsgUpdateTokenMapping) | [MsgUpdateTokenMappingResponse](#cronos.MsgUpdateTokenMappingResponse) | UpdateTokenMapping defines a method to update token mapping | |

<!-- end services -->

Expand Down
14 changes: 14 additions & 0 deletions integration_tests/cosmoscli.py
Original file line number Diff line number Diff line change
Expand Up @@ -983,3 +983,17 @@ def gov_propose_token_mapping_change(self, denom, contract, **kwargs):
**kwargs,
)
)

def update_token_mapping(self, denom, contract, **kwargs):
return json.loads(
self.raw(
"tx",
"cronos",
"update-token-mapping",
denom,
contract,
"-y",
home=self.data_dir,
**kwargs,
)
)
57 changes: 57 additions & 0 deletions integration_tests/test_gravity.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,60 @@ def check():
return balance == 10

wait_for_fn("check balance on cronos", check)


def test_direct_token_mapping(gravity):
"""
Test adding a token mapping directly
- deploy test erc20 contract on geth
- deploy corresponding contract on cronos
- add the token mapping on cronos using gov module
- do a gravity transfer, check the balances
"""
geth = gravity.geth
cli = gravity.cronos.cosmos_cli()
cronos_w3 = gravity.cronos.w3

# deploy test erc20 contract
erc20 = deploy_contract(
geth,
Path(__file__).parent
/ "contracts/artifacts/contracts/TestERC20A.sol/TestERC20A.json",
)
print("erc20 contract", erc20.address)
crc20 = deploy_contract(
cronos_w3,
Path(__file__).parent
/ "contracts/artifacts/contracts/TestERC20Utility.sol/TestERC20Utility.json",
)
print("crc20 contract", crc20.address)
denom = f"gravity{erc20.address}"

print("check the contract mapping not exists yet")
with pytest.raises(AssertionError):
cli.query_contract_by_denom(denom)

rsp = cli.update_token_mapping(denom, crc20.address, from_="community")
assert rsp["code"] != 0, "should not have the permission"

rsp = cli.update_token_mapping(denom, crc20.address, from_="validator")
assert rsp["code"] == 0, rsp["raw_log"]
wait_for_new_blocks(cli, 1)

print("check the contract mapping exists now")
rsp = cli.query_contract_by_denom(denom)
print("contract", rsp)
assert rsp["contract"] == crc20.address

print("try to send token from ethereum to cronos")
txreceipt = send_to_cosmos(
gravity.contract, erc20, ADDRS["community"], 10, KEYS["validator"]
)
assert txreceipt.status == 1

def check():
balance = crc20.caller.balanceOf(ADDRS["community"])
print("crc20 balance", balance)
return balance == 10

wait_for_fn("check balance on cronos", check)
2 changes: 2 additions & 0 deletions proto/cronos/cronos.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ message Params {
string ibc_cro_denom = 1
[ (gogoproto.moretags) = "yaml:\"ibc_cro_denom,omitempty\"" ];
uint64 ibc_timeout = 2;
// the admin address who can update token mapping
string cronos_admin = 3;
}

// TokenMappingChangeProposal defines a proposal to change one token mapping.
Expand Down
15 changes: 15 additions & 0 deletions proto/cronos/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ service Msg {

// TransferTokens defines a method to transfer cronos evm coins to another chain through IBC
rpc TransferTokens(MsgTransferTokens) returns (MsgTransferTokensResponse);

// UpdateTokenMapping defines a method to update token mapping
rpc UpdateTokenMapping(MsgUpdateTokenMapping) returns (MsgUpdateTokenMappingResponse);
}

// MsgConvertVouchers represents a message to convert ibc voucher coins to cronos evm coins.
Expand All @@ -39,4 +42,16 @@ message MsgConvertVouchersResponse {}

// MsgTransferTokensResponse defines the TransferTokens response type.
message MsgTransferTokensResponse {}

// MsgUpdateTokenMapping defines the request type
message MsgUpdateTokenMapping {
string sender = 1;
string denom = 2;
string contract = 3;
}

// MsgUpdateTokenMappingResponse defines the response type
message MsgUpdateTokenMappingResponse {
}

// this line is used by starport scaffolding # proto/tx/message
3 changes: 3 additions & 0 deletions scripts/cronos-devnet.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ cronos_777-1:
evm:
params:
evm_denom: basetcro
cronos:
params:
cronos_admin: crc12luku6uxehhak02py4rcz65zu0swh7wjsrw0pp
gov:
voting_params:
voting_period: "10s"
Expand Down
26 changes: 26 additions & 0 deletions x/cronos/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func GetTxCmd() *cobra.Command {

cmd.AddCommand(CmdConvertTokens())
cmd.AddCommand(CmdSendToCryptoOrg())
cmd.AddCommand(CmdUpdateTokenMapping())

return cmd
}
Expand Down Expand Up @@ -174,3 +175,28 @@ $ %s tx gov submit-proposal token-mapping-change gravity0x0000...0000 0x0000...0

return cmd
}

// CmdUpdateTokenMapping returns a CLI command handler for update token mapping
func CmdUpdateTokenMapping() *cobra.Command {
cmd := &cobra.Command{
Use: "update-token-mapping [denom] [contract]",
Short: "Update token mapping",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

msg := types.NewMsgUpdateTokenMapping(clientCtx.GetFromAddress().String(), args[0], args[1])
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}
3 changes: 3 additions & 0 deletions x/cronos/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ func NewHandler(k keeper.Keeper) sdk.Handler {
case *types.MsgTransferTokens:
res, err := msgServer.TransferTokens(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
case *types.MsgUpdateTokenMapping:
res, err := msgServer.UpdateTokenMapping(sdk.WrapSDKContext(ctx), msg)
return sdk.WrapServiceResult(ctx, res, err)
default:
errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg)
return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
Expand Down
31 changes: 24 additions & 7 deletions x/cronos/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package cronos_test

import (
"errors"
"strings"
"testing"
"time"

"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
Expand All @@ -11,9 +15,6 @@ import (
"github.com/stretchr/testify/suite"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"github.com/tharsis/ethermint/crypto/ethsecp256k1"
"strings"
"testing"
"time"
)

type CronosTestSuite struct {
Expand All @@ -31,13 +32,13 @@ func TestCronosTestSuite(t *testing.T) {

func (suite *CronosTestSuite) SetupTest() {
checkTx := false
suite.app = app.Setup(false)
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, ChainID: app.TestAppChainID, Time: time.Now().UTC()})
suite.handler = cronos.NewHandler(suite.app.CronosKeeper)

privKey, err := ethsecp256k1.GenerateKey()
suite.Require().NoError(err)
suite.address = sdk.AccAddress(privKey.PubKey().Address())
suite.app = app.Setup(false, suite.address.String())
suite.ctx = suite.app.BaseApp.NewContext(checkTx, tmproto.Header{Height: 1, ChainID: app.TestAppChainID, Time: time.Now().UTC()})
suite.handler = cronos.NewHandler(suite.app.CronosKeeper)

}

func (suite *CronosTestSuite) TestInvalidMsg() {
Expand Down Expand Up @@ -133,3 +134,19 @@ func (suite *CronosTestSuite) TestMsgTransferTokens() {
})
}
}

func (suite *CronosTestSuite) TestUpdateTokenMapping() {
suite.SetupTest()

denom := "gravity0x6E7eef2b30585B2A4D45Ba9312015d5354FDB067"
contract := "0x57f96e6B86CdeFdB3d412547816a82E3E0EbF9D2"

msg := types.NewMsgUpdateTokenMapping(suite.address.String(), denom, contract)
handler := cronos.NewHandler(suite.app.CronosKeeper)
_, err := handler(suite.ctx, msg)
suite.Require().NoError(err)

contractAddr, found := suite.app.CronosKeeper.GetContractByDenom(suite.ctx, denom)
suite.Require().True(found)
suite.Require().Equal(contract, contractAddr.Hex())
}
13 changes: 8 additions & 5 deletions x/cronos/keeper/keeper_test.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package keeper_test

import (
evmtypes "github.com/tharsis/ethermint/x/evm/types"
"math/big"
"testing"
"time"

evmtypes "github.com/tharsis/ethermint/x/evm/types"

sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
Expand Down Expand Up @@ -36,6 +37,8 @@ type KeeperTestSuite struct {

// EVM helpers
evmParam evmtypes.Params

address common.Address
}

func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
Expand All @@ -44,14 +47,14 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {
// account key
priv, err := ethsecp256k1.GenerateKey()
require.NoError(t, err)
address := common.BytesToAddress(priv.PubKey().Address().Bytes())
suite.address = common.BytesToAddress(priv.PubKey().Address().Bytes())

// consensus key
priv, err = ethsecp256k1.GenerateKey()
require.NoError(t, err)
consAddress := sdk.ConsAddress(priv.PubKey().Address())

suite.app = app.Setup(checkTx)
suite.app = app.Setup(checkTx, sdk.AccAddress(suite.address.Bytes()).String())
suite.ctx = suite.app.NewContext(checkTx, tmproto.Header{
Height: 1,
ChainID: app.TestAppChainID,
Expand Down Expand Up @@ -79,13 +82,13 @@ func (suite *KeeperTestSuite) DoSetupTest(t require.TestingT) {

// initialize the validator
acc := &ethermint.EthAccount{
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(address.Bytes()), nil, 0, 0),
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(suite.address.Bytes()), nil, 0, 0),
CodeHash: common.BytesToHash(ethcrypto.Keccak256(nil)).String(),
}

suite.app.AccountKeeper.SetAccount(suite.ctx, acc)

valAddr := sdk.ValAddress(address.Bytes())
valAddr := sdk.ValAddress(suite.address.Bytes())
validator, err := stakingtypes.NewValidator(valAddr, priv.PubKey(), stakingtypes.Description{})
err = suite.app.StakingKeeper.SetValidatorByConsAddr(suite.ctx, validator)
require.NoError(t, err)
Expand Down
Loading