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

fix(evm-keeper): better utilize ERC20 metadata during FunToken creation #2074

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 @@ -128,6 +128,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#2060](https://github.com/NibiruChain/nibiru/pull/2060) - fix(evm-precompiles): add assertNumArgs validation
- [#2056](https://github.com/NibiruChain/nibiru/pull/2056) - feat(evm): add oracle precompile
- [#2065](https://github.com/NibiruChain/nibiru/pull/2065) - refactor(evm)!: Refactor out dead code from the evm.Params
- [#2073](https://github.com/NibiruChain/nibiru/pull/2073) - fix(evm-keeper): better utilize ERC20 metadata during FunToken creation


#### Dapp modules: perp, spot, oracle, etc
Expand Down
5 changes: 3 additions & 2 deletions proto/buf.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
version: v1
name: buf.build/NibiruChain/nibiru
# Corresponds to Buf Schema Registry repo: https://buf.build/nibiru-chain/nibiru
name: buf.build/nibiru-chain/nibiru
deps:
- buf.build/cosmos/cosmos-proto
- buf.build/cosmos/cosmos-sdk:v0.47.3
Expand All @@ -22,4 +23,4 @@ lint:
- PACKAGE_DIRECTORY_MATCH

ignore:
- tendermint
- tendermint
84 changes: 68 additions & 16 deletions x/evm/keeper/funtoken_from_erc20.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,22 @@
}, nil
}

// ERC20Metadata: Optional metadata fields parsed from an ERC20 contract.
// The [Wrapped Ether contract] is a good example for reference.
//
// ```solidity
// constract WETH9 {
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Typo in Solidity keyword 'contract'

In the example code provided in the documentation, there is a typo in the keyword contract.

Apply this diff to fix the typo:

-//	constract WETH9 {
+//	contract WETH9 {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// constract WETH9 {
// contract WETH9 {

// string public name = "Wrapped Ether";
// string public symbol = "WETH"
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Missing semicolon in Solidity example

The line should end with a semicolon for correct Solidity syntax.

Apply this diff to fix the syntax:

-//	  string public symbol   = "WETH"
+//	  string public symbol   = "WETH";
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// string public symbol = "WETH"
// string public symbol = "WETH";

// uint8 public decimals = 18;
// }
// ```
//
// Note that the name and symbol fields may be empty, according to the [ERC20
// specification].
//
// [Wrapped Ether contract]: https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code
// [ERC20 specification]: https://eips.ethereum.org/EIPS/eip-20
type ERC20Metadata struct {
Name string
Symbol string
Expand Down Expand Up @@ -98,7 +114,7 @@
}

// 2 | Get existing ERC20 metadata
info, err := k.FindERC20Metadata(ctx, erc20)
erc20Info, err := k.FindERC20Metadata(ctx, erc20)
if err != nil {
return funtoken, err
}
Expand All @@ -115,21 +131,7 @@
}

// 4 | Set bank coin denom metadata in state
bankMetadata := bank.Metadata{
Description: fmt.Sprintf(
"ERC20 token \"%s\" represented as a bank coin with a corresponding FunToken mapping", erc20.String(),
),
DenomUnits: []*bank.DenomUnit{
{
Denom: bankDenom,
Exponent: 0, // TODO(k-yang): determine which exponent to use
},
},
Base: bankDenom,
Display: bankDenom,
Name: bankDenom,
Symbol: info.Symbol,
}
bankMetadata := erc20Info.ToBankMetadata(bankDenom, erc20)

err = bankMetadata.Validate()
if err != nil {
Expand All @@ -150,3 +152,53 @@
ctx, erc20, bankDenom, false,
)
}

// ToBankMetadata produces the "bank.Metadata" corresponding to a FunToken
// mapping created from an ERC20 token.
//
// The first argument of DenomUnits is required and the official base unit
// onchain, meaning the denom must be equivalent to bank.Metadata.Base.
//
// Decimals for an ERC20 are synonymous to "bank.DenomUnit.Exponent" in what
// they mean for external clients like wallets.
func (erc20Info ERC20Metadata) ToBankMetadata(
bankDenom string, erc20 gethcommon.Address,
) bank.Metadata {
var symbol string
if erc20Info.Symbol != "" {
symbol = erc20Info.Symbol
} else {
symbol = bankDenom

Check warning on line 171 in x/evm/keeper/funtoken_from_erc20.go

View check run for this annotation

Codecov / codecov/patch

x/evm/keeper/funtoken_from_erc20.go#L171

Added line #L171 was not covered by tests
}

var name string
if erc20Info.Name != "" {
name = erc20Info.Name
} else {
name = bankDenom

Check warning on line 178 in x/evm/keeper/funtoken_from_erc20.go

View check run for this annotation

Codecov / codecov/patch

x/evm/keeper/funtoken_from_erc20.go#L178

Added line #L178 was not covered by tests
}

denomUnits := []*bank.DenomUnit{
{
Denom: bankDenom,
Exponent: 0,
},
}
display := symbol
if erc20Info.Decimals > 0 {
denomUnits = append(denomUnits, &bank.DenomUnit{
Denom: display,
Exponent: uint32(erc20Info.Decimals),
})
}
return bank.Metadata{
Description: fmt.Sprintf(
"ERC20 token \"%s\" represented as a Bank Coin with a corresponding FunToken mapping", erc20.String(),
),
DenomUnits: denomUnits,
Base: bankDenom,
Display: display,
Name: name,
Symbol: symbol,
}
}
17 changes: 17 additions & 0 deletions x/evm/keeper/funtoken_from_erc20_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
bank "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/suite"

Expand Down Expand Up @@ -101,6 +102,22 @@ func (s *FunTokenFromErc20Suite) TestCreateFunTokenFromERC20() {
IsMadeFromCoin: false,
},
)
bankMetadata, _ := deps.App.BankKeeper.GetDenomMetaData(deps.Ctx, expectedBankDenom)
s.Require().Equal(bank.Metadata{
Description: fmt.Sprintf(
"ERC20 token \"%s\" represented as a Bank Coin with a corresponding FunToken mapping", erc20Addr.String(),
),
DenomUnits: []*bank.DenomUnit{
{Denom: expectedBankDenom, Exponent: 0},
{Denom: metadata.Symbol, Exponent: uint32(metadata.Decimals)},
},
Base: expectedBankDenom,
Display: metadata.Symbol,
Name: metadata.Name,
Symbol: metadata.Symbol,
URI: "",
URIHash: "",
}, bankMetadata)

s.T().Log("sad: CreateFunToken for the ERC20: already registered")
// Give the sender funds for the fee
Expand Down
Loading