Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Apr 4, 2024. It is now read-only.

Call Native Modules From EVM #394

yihuang started this conversation in Ideas
Aug 4, 2021 · 3 comments · 9 replies
Discussion options

Call Native Modules From EVM

To improve interoperanility between EVM and native modules, and inspired by the cosmwasm messaging system, we can introduce a similar messaging system between EVM and native modules.

Call native modules

Logs can be used for evm contract to send and execute messages to native modules, for example:

emit CosmosNative("bank.send", recipient, 1, "denom");

This log can tell the host to do a native token transfer from the contract address to the recipient after the evm contract succesfully executed, if the native message execution failed, the whole tx is reverted.

Why not use precompiled contract to call native module synchronously

In current go-ethereum evm implementation, precompiled contract don't have access to the current caller, thus we can't do the authentication. https://github.com/ethereum/go-ethereum/blob/master/core/vm/contracts.go#L40

Tx post processing

We need to add tx post processing logic to execute the message, the new tx processing procedure would be like this:

k.ctx, commit = ctx.CacheContext()
err := k.ApplyMessage(ethMsg) # execute the evm transaction
if err != nil {
 // Could check the bloom filter first
 for log := range(k.GetLogs(txHash)) {
 if log.Topics.Contains(CosmosNative_Signature) {
 // log.Address is the address of calling contract
 err = execute_message(log.Address, log.Data)
 if err != nil {
 break
 }
 }
 }
}
if err == nil {
 commit()
}

Query native modules

might need to change the evm api in go-ethereum to support custom precompiled contract

State querying can be implemented by precompiled smart contract directly, since we don't need to do the authentication:

balance = cosmos_native_query("bank.balance", addr, "denom");

The precompiled contract would be something like this:

type NativeQueryContract struct{
 k EvmKeeper
}
func (c *NativeQueryContract) RequiredGas(input []byte) uint64 {
 return ...
}
func (c *NativeQueryContract) Run(input []byte) ([]byte, error) {
 (action, args) := parse_args(input)
 do the query on current context and return the result
}

Allow Sending Native Tokens to EVM Contract

By allow sending native tokens to EVM contract, it enables more interoperability between EVM contract and native modules.
Contract can query the native tokens sent to it by calling some precompiled contract.

type QueryTxTokensContract struct{
 tx Tx
}
func (c *QueryTxTokensContract) RequiredGas(input []byte) uint64 {
 return ...
}
func (c *QueryTxTokensContract) Run(input []byte) ([]byte, error) {
 if input == tx.To {
 return tx.ExtraTokens, nil
 }
 return nil, nil
}

So a erc20 contract that wrapping a native token would look like this:

contract ERC20 {
 string _denom;
 mapping(address => uint256) private _balances;
 function deposit() public payable {
 coin = query_tx_tokens(address(this));
 if coin.denom == _denom {
 // FIXME handle overflow
 _balances[msg.sender] += coin.amount;
 }
 }
 function withdraw(amount uint256) public {
 // FIXME handle underflow
 _balances[msg.sender] -= amount;
 emit CosmosNative("bank.send", msg.sender, amount, _denom);
 }
}

If gravity bridge module is embed, one can even call gravity message directly from the contract, and send the token to ethereum:

 function send_to_eth(amount uint256, eth_dest address) public {
 // FIXME handle underflow
 _balances[msg.sender] -= amount;
 emit CosmosNative("gravity.send", eth_dest, amount, _denom);
 }

https://gist.github.com/yihuang/f072e6d91d4845105b7698f52171053a
Some pseudocode to how how this could work together with gravity bridge to make transparent evm to evm bridge.

Mint Native Tokens from EVM Contract

For an exiting smart contract to convert to native token, it needs to have some native token minting ability. We can provide a call for contract to mint native token whose denomination is just the contract address prefixed with evm/.

contract ERC20 {
 mapping(address => uint256) private _balances;
 function withdraw(amount uint256) public {
 // FIXME handle underflow
 _balances[msg.sender] -= amount;
 emit CosmosNative("bank.mint", msg.sender, amount);
 }
}
You must be logged in to vote

Replies: 3 comments 9 replies

Comment options

I think there are potential drawback having the module listening to EVM logs

  1. Its an extra cost in term of operation for the chain.
  2. It is not secure. You are breaking the isolation layer between EVM and main chain execution.

For the second point , anyone can emit any kind of event within the smart contract. We need a strong mechanism to be sure it is a log emitted by a "contract" module wont break anything.

Overall even though I like the idea to have contract interacting with module in cosmos, there could be some security concern because SC has been designed to be run in an isolated context to prevent any wrong behavior that could break the main chain execution. Need to think carefully.

You must be logged in to vote
8 replies
Comment options

Ok got it, It guess is fine to use an arbitrary address for contract. But use case might be quite limited at the moment.

Comment options

Ok got it, It guess is fine to use an arbitrary address for contract. But use case might be quite limited at the moment.

This could be useful for cosmos users but not so much for Ethereum users.

one use case is to complete the bridge puzzle:

  • evm <-> local native token, this proposal
  • native token <-> native token, ibc
  • native token <-> ethereum, gravity bridge

Another use case could be contract controlled staking, something like:

emit CosmosNative("staking.delegate", validator_address, amount)
Comment options

evm <-> local native token, this proposal

I think this proposal would only support evm -> native token but not native token -> evm (you will need the other proposal?)

For evm <-> native token <-> ibc/gravity bridge etc, another level of complexity is interfacing as the coin denom is often dictated by the bridge and sometime the supply as well.

Chaining might not be that trivial

Comment options

evm <-> local native token, this proposal

I think this proposal would only support evm -> native token but not native token -> evm (you will need the other proposal?)

Yeah, with this proposal we can manage exiting native tokens in contract, to support contract minting new native tokens, we'll need something from the other proposal.

For evm <-> native token <-> ibc/gravity bridge etc, another level of complexity is interfacing as the coin denom is often dictated by the bridge and sometime the supply as well.

Chaining might not be that trivial

hmm, could you elaborate?

Comment options

Regarding the potential use cases, we can consult cosmwasm, what's done there could also done here:

  • bank module: send and burn native tokens
  • staking module: delegate/undelegate
  • distribution module: reward withdraw
  • ibc module: send ibc transfer message from contract
  • gov module: voting in smart contract, maybe some multisig contract?
  • if gravity bridge is used as a module, we could also execute gravity message from contract
Comment options

We need to add tx post processing logic to execute the message, the new tx processing procedure would be like this:

I think we can implement hooks (pre-post tx) to make more the implementation cleaner and with the same result. Then, we can create a separate module that implements this hooks and just unpacks the logs using the abi

You must be logged in to vote
1 reply
Comment options

(削除) How hard do you think it'll be to add a parameter like caller to this interface: https://github.com/ethereum/go-ethereum/blob/master/core/vm/contracts.go#L42? with that we could just implement a custom precompiled contract. (削除ここまで)

I guess we can't just add new precompiled contract with current evm api.

Comment options

https://gist.github.com/yihuang/f072e6d91d4845105b7698f52171053a
Some pseudocode to show how this could work together with gravity bridge to make transparent evm to evm bridge.

You must be logged in to vote
0 replies
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

AltStyle によって変換されたページ (->オリジナル) /