Skip to content

Commit

Permalink
optional custom erc20 support
Browse files Browse the repository at this point in the history
  • Loading branch information
beer-1 committed May 7, 2024
1 parent b3c7369 commit 8cebacf
Show file tree
Hide file tree
Showing 30 changed files with 1,975 additions and 77 deletions.
1 change: 1 addition & 0 deletions app/ibc-hooks/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,7 @@ func _createTestInput(
)
evmParams := evmtypes.DefaultParams()
require.NoError(t, evmKeeper.Params.Set(ctx, evmParams))
require.NoError(t, evmKeeper.Initialize(ctx))

// set erc20 keeper
*erc20Keeper = *evmKeeper.ERC20Keeper().(*evmkeeper.ERC20Keeper)
Expand Down
10 changes: 10 additions & 0 deletions proto/minievm/evm/v1/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ message Params {
// and an empty list is interpreted as allowing anyone to distribute.
repeated string allowed_publishers = 2
[(gogoproto.moretags) = "yaml:\"allowed_publishers\"", (amino.dont_omitempty) = true];

// allow_custom_erc20 defines whether the chain allows custom erc20 tokens
// to be registered on cosmos bank interface.
bool allow_custom_erc20 = 3 [(gogoproto.customname) = "AllowCustomERC20"];
repeated string allowed_custom_erc20s = 4 [
(gogoproto.customname) = "AllowedCustomERC20s",
(gogoproto.moretags) = "yaml:\"allowed_custom_erc20s\"",
(amino.dont_omitempty) = true
];
;
}

// Log represents a contract log event. These events are generated by
Expand Down
1 change: 1 addition & 0 deletions x/bank/keeper/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ func _createTestInput(
)
evmParams := evmtypes.DefaultParams()
require.NoError(t, evmKeeper.Params.Set(ctx, evmParams))
require.NoError(t, evmKeeper.Initialize(ctx))

// set erc20 keeper
*erc20Keeper = *evmKeeper.ERC20Keeper().(*evmkeeper.ERC20Keeper)
Expand Down
1,007 changes: 1,007 additions & 0 deletions x/evm/contracts/custom_erc20/CustomERC20.go

Large diffs are not rendered by default.

76 changes: 76 additions & 0 deletions x/evm/contracts/custom_erc20/CustomERC20.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "../i_erc20/IERC20.sol";
import "../ownable/Ownable.sol";
import "../erc20_registry/ERC20Registry.sol";

contract CustomERC20 is IERC20, Ownable, ERC20Registry {
event Transfer(address indexed from, address indexed to, uint256 value);
event Approval(
address indexed owner,
address indexed spender,
uint256 value
);

mapping(address => uint256) public balanceOf;
mapping(address => mapping(address => uint256)) public allowance;
string public name;
string public symbol;
uint8 public decimals;
uint256 public totalSupply;

constructor(string memory _name, string memory _symbol, uint8 _decimals) register_erc20 {
name = _name;
symbol = _symbol;
decimals = _decimals;
}

function transfer(
address recipient,
uint256 amount
) external register_erc20_store(recipient) returns (bool) {
balanceOf[msg.sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(msg.sender, recipient, amount);
return true;
}

function approve(address spender, uint256 amount) external returns (bool) {
allowance[msg.sender][spender] = amount;
emit Approval(msg.sender, spender, amount);
return true;
}

function transferFrom(
address sender,
address recipient,
uint256 amount
) external register_erc20_store(recipient) returns (bool) {
allowance[sender][msg.sender] -= amount;
balanceOf[sender] -= amount;
balanceOf[recipient] += amount;
emit Transfer(sender, recipient, amount);
return true;
}

function _mint(address to, uint256 amount) internal register_erc20_store(to) {
balanceOf[to] += amount;
totalSupply += amount;
emit Transfer(address(0), to, amount);
}

function _burn(address from, uint256 amount) internal {
balanceOf[from] -= amount;
totalSupply -= amount;
emit Transfer(from, address(0), amount);
}

function mint(address to, uint256 amount) external onlyOwner{
_mint(to, amount);
}

function burn(address from, uint256 amount) external onlyOwner {
_burn(from, amount);
}
}
2 changes: 1 addition & 1 deletion x/evm/contracts/erc20/ERC20.go

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion x/evm/contracts/erc20/ERC20.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ contract ERC20 is IERC20, Ownable, ERC20Registry {
uint8 public decimals;
uint256 public totalSupply;

constructor(string memory _name, string memory _symbol, uint8 _decimals) register_erc20 {
// for custom erc20s, you should add `register_erc20` modifier to the constructor
constructor(string memory _name, string memory _symbol, uint8 _decimals) {
name = _name;
symbol = _symbol;
decimals = _decimals;
Expand Down
377 changes: 377 additions & 0 deletions x/evm/contracts/erc20_factory/ERC20Factory.go

Large diffs are not rendered by default.

26 changes: 26 additions & 0 deletions x/evm/contracts/erc20_factory/ERC20Factory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

import "../erc20/ERC20.sol";
import "../i_erc20_registry/IERC20Registry.sol";

contract ERC20Factory is ERC20Registry {
event ERC20Created(address indexed erc20, address indexed owner);

function createERC20(
string memory name,
string memory symbol,
uint8 decimals
) external returns (address) {
ERC20 erc20 = new ERC20(name, symbol, decimals);

// register the ERC20 contract with the ERC20 registry
ERC20_REGISTRY_CONTRACT.register_erc20_from_factory(address(erc20));

// transfer ownership of the ERC20 contract to the sender
erc20.transferOwnership(msg.sender);

emit ERC20Created(address(erc20), msg.sender);
return address(erc20);
}
}
2 changes: 1 addition & 1 deletion x/evm/contracts/erc20_registry/ERC20Registry.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 22 additions & 1 deletion x/evm/contracts/i_erc20_registry/IERC20Registry.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions x/evm/contracts/i_erc20_registry/IERC20Registry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ IERC20Registry constant ERC20_REGISTRY_CONTRACT = IERC20Registry(

interface IERC20Registry {
function register_erc20() external;
function register_erc20_from_factory(address erc20) external;
function register_erc20_store(address account) external;
function is_erc20_store_registered(
address account
Expand Down
16 changes: 11 additions & 5 deletions x/evm/keeper/common_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,13 +152,13 @@ type TestKeepers struct {

// createDefaultTestInput common settings for createTestInput
func createDefaultTestInput(t testing.TB) (sdk.Context, TestKeepers) {
return createTestInput(t, false)
return createTestInput(t, false, true)
}

// createTestInput encoders can be nil to accept the defaults, or set it to override some of the message handlers (like default)
func createTestInput(t testing.TB, isCheckTx bool) (sdk.Context, TestKeepers) {
func createTestInput(t testing.TB, isCheckTx, withInitialize bool) (sdk.Context, TestKeepers) {
// Load default move config
return _createTestInput(t, isCheckTx, dbm.NewMemDB())
return _createTestInput(t, isCheckTx, withInitialize, dbm.NewMemDB())
}

var keyCounter uint64
Expand All @@ -180,6 +180,7 @@ func keyPubAddr() (crypto.PrivKey, crypto.PubKey, sdk.AccAddress) {
func _createTestInput(
t testing.TB,
isCheckTx bool,
withInitialize bool,
db dbm.DB,
) (sdk.Context, TestKeepers) {
keys := storetypes.NewKVStoreKeys(
Expand Down Expand Up @@ -269,8 +270,13 @@ func _createTestInput(
},
},
)
evmParams := evmtypes.DefaultParams()
require.NoError(t, evmKeeper.Params.Set(ctx, evmParams))

if withInitialize {
evmParams := evmtypes.DefaultParams()
evmParams.AllowCustomERC20 = false
require.NoError(t, evmKeeper.Params.Set(ctx, evmParams))
require.NoError(t, evmKeeper.Initialize(ctx))
}

// set erc20 keeper
*erc20Keeper = *evmKeeper.ERC20Keeper().(*evmkeeper.ERC20Keeper)
Expand Down
Loading

0 comments on commit 8cebacf

Please sign in to comment.