Skip to content

Commit

Permalink
better handling erc20 metadata
Browse files Browse the repository at this point in the history
  • Loading branch information
expertdicer committed Jan 17, 2025
1 parent 849775a commit 1050f39
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 18 deletions.
40 changes: 30 additions & 10 deletions x/evm/keeper/erc20.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package keeper

import (
"bytes"
"fmt"
"math"
"math/big"
Expand Down Expand Up @@ -191,13 +192,23 @@ func (k Keeper) LoadERC20String(
}

erc20Val := new(ERC20String)
err = erc20Abi.UnpackIntoInterface(
if err := erc20Abi.UnpackIntoInterface(
erc20Val, methodName, res.Ret,
)
if err != nil {
return out, err
); err == nil {
return erc20Val.Value, err
}

erc20Bytes32Val := new(ERC20Bytes32)
if err := erc20Abi.UnpackIntoInterface(erc20Bytes32Val, methodName, res.Ret); err == nil {

return bytes32ToString(erc20Bytes32Val.Value), nil
}
return erc20Val.Value, err

return "", fmt.Errorf("failed to decode response for method %s; unable to unpack as string or bytes32", methodName)
}

func bytes32ToString(b [32]byte) string {
return string(bytes.Trim(b[:], "\x00"))
}

func (k Keeper) loadERC20Uint8(
Expand All @@ -219,13 +230,22 @@ func (k Keeper) loadERC20Uint8(
}

erc20Val := new(ERC20Uint8)
err = erc20Abi.UnpackIntoInterface(
if err := erc20Abi.UnpackIntoInterface(
erc20Val, methodName, res.Ret,
)
if err != nil {
return out, err
); err == nil {
return erc20Val.Value, err
}
return erc20Val.Value, err

erc20Uint256Val := new(ERC20BigInt)
if err := erc20Abi.UnpackIntoInterface(
erc20Uint256Val, methodName, res.Ret,
); err == nil {
// We can safely cast to uint8 because it's nonsense for decimals to be larger than 255
return uint8(erc20Uint256Val.Value.Uint64()), err
}

return 0, fmt.Errorf("failed to decode response for method %s; unable to unpack as uint8 or uint256", methodName)

}

func (k Keeper) LoadERC20BigInt(
Expand Down
4 changes: 2 additions & 2 deletions x/evm/keeper/funtoken_from_coin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func (s *FunTokenFromCoinSuite) TestCreateFunTokenFromCoin() {
// Compute contract address. FindERC20 should fail
nonce := deps.NewStateDB().GetNonce(deps.Sender.EthAddr)
contractAddress := crypto.CreateAddress(deps.Sender.EthAddr, nonce)
metadata, err := deps.EvmKeeper.FindERC20Metadata(deps.Ctx, contractAddress)
metadata, err := deps.EvmKeeper.FindERC20Metadata(deps.Ctx, contractAddress, nil)
s.Require().Error(err)
s.Require().Nil(metadata)

Expand Down Expand Up @@ -109,7 +109,7 @@ func (s *FunTokenFromCoinSuite) TestCreateFunTokenFromCoin() {
s.Require().NoError(err)

s.T().Log("Expect ERC20 metadata on contract")
info, err := deps.EvmKeeper.FindERC20Metadata(deps.Ctx, erc20Addr.Address)
info, err := deps.EvmKeeper.FindERC20Metadata(deps.Ctx, erc20Addr.Address, nil)
s.Require().NoError(err, info)
s.Equal(
keeper.ERC20Metadata{
Expand Down
17 changes: 13 additions & 4 deletions x/evm/keeper/funtoken_from_erc20.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
bank "github.com/cosmos/cosmos-sdk/x/bank/types"
gethcommon "github.com/ethereum/go-ethereum/common"
gethabi "github.com/ethereum/go-ethereum/accounts/abi"

"github.com/NibiruChain/nibiru/v2/eth"
"github.com/NibiruChain/nibiru/v2/x/evm"
Expand All @@ -26,19 +27,26 @@ import (
func (k Keeper) FindERC20Metadata(
ctx sdk.Context,
contract gethcommon.Address,
abi *gethabi.ABI,
) (info *ERC20Metadata, err error) {

effectiveAbi := embeds.SmartContract_ERC20Minter.ABI

if abi != nil {
effectiveAbi = abi
}
// Load name, symbol, decimals
name, err := k.LoadERC20Name(ctx, embeds.SmartContract_ERC20Minter.ABI, contract)
name, err := k.LoadERC20Name(ctx, effectiveAbi, contract)
if err != nil {
return nil, err
}

symbol, err := k.LoadERC20Symbol(ctx, embeds.SmartContract_ERC20Minter.ABI, contract)
symbol, err := k.LoadERC20Symbol(ctx, effectiveAbi, contract)
if err != nil {
return nil, err
}

decimals, err := k.LoadERC20Decimals(ctx, embeds.SmartContract_ERC20Minter.ABI, contract)
decimals, err := k.LoadERC20Decimals(ctx, effectiveAbi, contract)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -80,6 +88,7 @@ type (
ERC20Bool struct{ Value bool }
// ERC20BigInt: Unpacking type for "uint256" from Solidity.
ERC20BigInt struct{ Value *big.Int }
ERC20Bytes32 struct{ Value [32]byte }
)

// createFunTokenFromERC20 creates a new FunToken mapping from an existing ERC20 token.
Expand Down Expand Up @@ -114,7 +123,7 @@ func (k *Keeper) createFunTokenFromERC20(
}

// 2 | Get existing ERC20 metadata
erc20Info, err := k.FindERC20Metadata(ctx, erc20)
erc20Info, err := k.FindERC20Metadata(ctx, erc20, nil)
if err != nil {
return funtoken, err
}
Expand Down
60 changes: 58 additions & 2 deletions x/evm/keeper/funtoken_from_erc20_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
package keeper_test

import (
"encoding/hex"
"fmt"
"math/big"
"testing"
Expand All @@ -26,7 +27,7 @@ func (s *FunTokenFromErc20Suite) TestCreateFunTokenFromERC20() {

// assert that the ERC20 contract is not deployed
expectedERC20Addr := crypto.CreateAddress(deps.Sender.EthAddr, deps.NewStateDB().GetNonce(deps.Sender.EthAddr))
_, err := deps.EvmKeeper.FindERC20Metadata(deps.Ctx, expectedERC20Addr)
_, err := deps.EvmKeeper.FindERC20Metadata(deps.Ctx, expectedERC20Addr, nil)
s.Error(err)

s.T().Log("Deploy ERC20")
Expand All @@ -42,7 +43,7 @@ func (s *FunTokenFromErc20Suite) TestCreateFunTokenFromERC20() {
s.Require().NoError(err)
s.Require().Equal(expectedERC20Addr, deployResp.ContractAddr)

info, err := deps.EvmKeeper.FindERC20Metadata(deps.Ctx, deployResp.ContractAddr)
info, err := deps.EvmKeeper.FindERC20Metadata(deps.Ctx, deployResp.ContractAddr, nil)
s.Require().NoError(err)
s.Require().Equal(metadata, *info)

Expand Down Expand Up @@ -535,6 +536,61 @@ func (s *FunTokenFromErc20Suite) TestSendERC20WithFee() {
s.Require().True(deps.App.BankKeeper.GetBalance(deps.Ctx, evm.EVM_MODULE_ADDRESS_NIBI, bankDemon).Amount.Equal(sdk.NewInt(0)))
}

type MkrMetadata struct {
Symbol [32]byte
}

func (s *FunTokenFromErc20Suite) TestMuahaha() {
deps := evmtest.NewTestDeps()

s.T().Log("Deploy MKR")

byteSlice, err := hex.DecodeString("4d4b520000000000000000000000000000000000000000000000000000000000")
s.Require().NoError(err)
var byteArray [32]byte
copy(byteArray[:], byteSlice)

metadata := MkrMetadata{
Symbol: byteArray,
}
deployResp, err := evmtest.DeployContract(
&deps, embeds.SmartContract_TestBytes32Metadata,
metadata.Symbol,
)
s.Require().NoError(err)

s.T().Log("set name")

deps.ResetGasMeter()

byteSlice, err = hex.DecodeString("4d616b6572000000000000000000000000000000000000000000000000000000")
s.Require().NoError(err)
copy(byteArray[:], byteSlice)

_, err = deps.EvmKeeper.CallContract(
deps.Ctx,
embeds.SmartContract_TestBytes32Metadata.ABI,
deps.Sender.EthAddr,
&deployResp.ContractAddr,
true,
evmtest.FunTokenGasLimitSendToEvm,
"setName",
byteArray,
)

s.Require().NoError(err)

info, err := deps.EvmKeeper.FindERC20Metadata(deps.Ctx, deployResp.ContractAddr, embeds.SmartContract_TestBytes32Metadata.ABI)
s.Require().NoError(err)

actualMetadata := keeper.ERC20Metadata{
Name: "Maker",
Symbol: "MKR",
Decimals: 18,
}
s.Require().Equal(actualMetadata, *info)
}

type FunTokenFromErc20Suite struct {
suite.Suite
}
Expand Down

0 comments on commit 1050f39

Please sign in to comment.