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

feat(token-registry): Implement strongly typed Nibiru Token Registry and generation command #2144

Merged
merged 11 commits into from
Jan 8, 2025
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [#2140](https://github.com/NibiruChain/nibiru/pull/2140) - fix(bank): bank keeper extension now charges gas for the bank operations
- [#2141](https://github.com/NibiruChain/nibiru/pull/2141) - refactor: simplify account retrieval operation in `nibid q evm account`.
- [#2142](https://github.com/NibiruChain/nibiru/pull/2142) - fix(bank): add additional missing methods to the NibiruBankKeeper
- [#2144](https://github.com/NibiruChain/nibiru/pull/2144) - feat(token-registry): Implement strongly typed Nibiru Token Registry and generation command

#### Nibiru EVM | Before Audit 2 - 2024-12-06

Expand Down
4 changes: 4 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ gen-embeds:

alias gen-proto := proto-gen

# Generate the Nibiru Token Registry files
gen-token-registry:
go run token-registry/main/main.go

# Generate protobuf-based types in Rust
gen-proto-rs:
bash proto/buf.gen.rs.sh
Expand Down
5 changes: 5 additions & 0 deletions token-registry/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Nibiru/token-registry

This directory implements the Nibiru Token Registry by providing a means to
register offchain digital token metadata to onchain identifiers for use with
applications like wallets.
199 changes: 199 additions & 0 deletions token-registry/assetlist.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package tokenregistry

func NibiruAssetList() AssetList {
var tokens = TOKENS()
for idx, token := range tokens {
tokens[idx] = token.GitHubify()
}

return AssetList{
Schema: "../assetlist.schema.json",
ChainName: "nibiru",
Assets: tokens,
}
}

func TOKENS() []Token {
return []Token{
{
Description: "The native token of Nibiru blockchain",
ExtendedDescription: some("Nibiru is a smart contract ecosystem with a high-performance, EVM-equivalent execution layer. Nibiru is engineered to meet the growing demand for versatile, scalable, and easy-to-use Web3 applications."),
Socials: &SocialLinks{
Website: some("https://nibiru.fi"),
Twitter: some("https://twitter.com/nibiruchain"),
},
DenomUnits: []DenomUnit{
{Denom: "unibi", Exponent: 0},
{Denom: "nibi", Exponent: 6},
{Denom: "attonibi", Exponent: 18},
},
Base: "unibi",
Name: "Nibiru",
Display: "nibi",
Symbol: "NIBI",
LogoURIs: &LogoURIs{
Png: some("./img/0000_nibiru.png"),
Svg: some("./img/0000_nibiru.svg"),
},
CoingeckoID: some("nibiru"),
Images: []AssetImage{
{
Png: some("./img/0000_nibiru.png"),
Svg: some("./img/0000_nibiru.svg"),
Theme: &ImageTheme{
PrimaryColorHex: some("#14c0ce"),
},
},
},
TypeAsset: TypeAsset_SDKCoin,
},
{
Description: "Liquid Staked Nibiru (Eris)",
ExtendedDescription: some("Liquid Staked Nibiru, powered by Eris Protocol's amplifier contracts. Nibiru is a smart contract ecosystem with a high-performance, EVM-equivalent execution layer. Nibiru is engineered to meet the growing demand for versatile, scalable, and easy-to-use Web3 applications."),
Socials: &SocialLinks{
Website: some("https://nibiru.fi/docs/learn/liquid-stake/"),
Twitter: some("https://x.com/eris_protocol"),
},
DenomUnits: []DenomUnit{
{Denom: "tf/nibi1udqqx30cw8nwjxtl4l28ym9hhrp933zlq8dqxfjzcdhvl8y24zcqpzmh8m/ampNIBI", Exponent: 0},
{Denom: "stNIBI", Exponent: 6},
},
Base: "tf/nibi1udqqx30cw8nwjxtl4l28ym9hhrp933zlq8dqxfjzcdhvl8y24zcqpzmh8m/ampNIBI",
Name: "Liquid Staked Nibiru (Eris)",
Display: "stNIBI",
Symbol: "stNIBI",
LogoURIs: &LogoURIs{
Png: some("./img/0001_stnibi-500x500.png"),
Svg: some("./img/0001_stnibi-500x500.svg"),
},
Images: []AssetImage{
{
Png: some("./img/0001_stnibi-500x500.png"),
Svg: some("./img/0001_stnibi-500x500.svg"),
Theme: &ImageTheme{
PrimaryColorHex: some("#14c0ce"),
},
},
},
Traces: []Trace{
{
Type: "liquid-stake",
Counterparty: Counterparty{
ChainName: "nibiru",
BaseDenom: "unibi",
},
Provider: some("Eris Protocol"),
},
},
TypeAsset: TypeAsset_SDKCoin,
},
{
Description: "Noble USDC on Nibiru",
DenomUnits: []DenomUnit{
{Denom: "ibc/F082B65C88E4B6D5EF1DB243CDA1D331D002759E938A0F5CD3FFDC5D53B3E349", Exponent: 0},
{Denom: "usdc", Exponent: 6},
},
Base: "ibc/F082B65C88E4B6D5EF1DB243CDA1D331D002759E938A0F5CD3FFDC5D53B3E349",
Name: "Noble USDC",
Display: "usdc",
Symbol: "USDC",
Traces: []Trace{
{
Type: TraceType_IBC,
Counterparty: Counterparty{
ChainName: "noble",
BaseDenom: "uusdc",
ChannelID: some("channel-67"),
},
Chain: &TraceChainInfo{
ChannelID: "channel-2",
Path: "transfer/channel-2/uusdc",
},
},
},
Images: []AssetImage{
{
ImageSync: &ImageSync{
ChainName: "noble",
BaseDenom: "uusdc",
},
Png: some("./img/0002_usdc.png"),
Svg: some("./img/0002_usdc.svg"),
Theme: &ImageTheme{
Circle: some(true),
PrimaryColorHex: some("#2775CA"),
},
},
},
LogoURIs: &LogoURIs{
Png: some("./img/0002_usdc.png"),
Svg: some("./img/0002_usdc.svg"),
},
TypeAsset: TypeAsset_ICS20,
},
{
Description: "AXV",
ExtendedDescription: some("AXV is the Astrovault token."),
Socials: &SocialLinks{
Website: some("https://astrovault.io/"),
Twitter: some("https://x.com/axvdex"),
},
DenomUnits: []DenomUnit{
{Denom: "tf/nibi1vetfuua65frvf6f458xgtjerf0ra7wwjykrdpuyn0jur5x07awxsfka0ga/axv", Exponent: 0},
{Denom: "AXV", Exponent: 6},
},
Base: "tf/nibi1vetfuua65frvf6f458xgtjerf0ra7wwjykrdpuyn0jur5x07awxsfka0ga/axv",
Name: "AXV",
Display: "AXV",
Symbol: "AXV",
LogoURIs: &LogoURIs{
Png: some("./img/0003_astrovault-axv.png"),
Svg: some("./img/0003_astrovault-axv.svg"),
},
Images: []AssetImage{
{
ImageSync: &ImageSync{
ChainName: "neutron",
BaseDenom: "cw20:neutron10dxyft3nv4vpxh5vrpn0xw8geej8dw3g39g7nqp8mrm307ypssksau29af",
},
Png: some("./img/0003_astrovault-axv.png"),
Svg: some("./img/0003_astrovault-axv.svg"),
},
},
TypeAsset: TypeAsset_SDKCoin,
},
{
Description: "uoprek",
DenomUnits: []DenomUnit{
{Denom: "tf/nibi149m52kn7nvsg5nftvv4fh85scsavpdfxp5nr7zasz97dum89dp5qkyhy0t/uoprek", Exponent: 0},
},
Base: "tf/nibi149m52kn7nvsg5nftvv4fh85scsavpdfxp5nr7zasz97dum89dp5qkyhy0t/uoprek",
Name: "uoprek",
Display: "tf/nibi149m52kn7nvsg5nftvv4fh85scsavpdfxp5nr7zasz97dum89dp5qkyhy0t/uoprek",
Symbol: "UOPREK",
TypeAsset: TypeAsset_SDKCoin,
},
{
Description: "utestate",
DenomUnits: []DenomUnit{
{Denom: "tf/nibi1lp28kx3gz0prsztl024z730ufkg3alahaq3e7a6gae22nk0dqdvsyrrgqw/utestate", Exponent: 0},
},
Base: "tf/nibi1lp28kx3gz0prsztl024z730ufkg3alahaq3e7a6gae22nk0dqdvsyrrgqw/utestate",
Name: "utestate",
Display: "tf/nibi1lp28kx3gz0prsztl024z730ufkg3alahaq3e7a6gae22nk0dqdvsyrrgqw/utestate",
Symbol: "UTESTATE",
TypeAsset: TypeAsset_SDKCoin,
},
{
Description: "npp",
DenomUnits: []DenomUnit{
{Denom: "tf/nibi1xpp7yn0tce62ffattws3gpd6v0tah0mlevef3ej3r4pnfvsehcgqk3jvxq/NPP", Exponent: 0},
},
Base: "tf/nibi1xpp7yn0tce62ffattws3gpd6v0tah0mlevef3ej3r4pnfvsehcgqk3jvxq/NPP",
Name: "npp",
Display: "tf/nibi1xpp7yn0tce62ffattws3gpd6v0tah0mlevef3ej3r4pnfvsehcgqk3jvxq/NPP",
Symbol: "NPP",
TypeAsset: TypeAsset_SDKCoin,
},
}
}
54 changes: 54 additions & 0 deletions token-registry/assetlist_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package tokenregistry_test

import (
"os"
"strings"
"testing"

"github.com/stretchr/testify/suite"

tokenregistry "github.com/NibiruChain/nibiru/v2/token-registry"
)

type Suite struct {
suite.Suite
}

func TestSuite(t *testing.T) {
suite.Run(t, new(Suite))
}

func (s *Suite) TestImagesPresent() {
assetList := tokenregistry.NibiruAssetList()
for _, token := range assetList.Assets {
s.Run(token.Name, func() {
token = token.GitHubify()

// Make sure all local images in Token.LogoURIs exist
if token.LogoURIs != nil {
png, svg := token.LogoURIs.Png, token.LogoURIs.Svg
if png != nil && strings.Contains(*png, "token-registry/img/") {
_, err := os.Stat(*png)
s.NoError(err)
}
if svg != nil && strings.Contains(*svg, "token-registry/img/") {
_, err := os.Stat(*svg)
s.NoError(err)
}
}

// Make sure all local images in Token.Images exist
for _, img := range token.Images {
png, svg := img.Png, img.Svg
if png != nil && strings.Contains(*png, "token-registry/img/") {
_, err := os.Stat(*png)
s.NoError(err)
}
if svg != nil && strings.Contains(*svg, "token-registry/img/") {
_, err := os.Stat(*svg)
s.NoError(err)
}
}
})
}
}
54 changes: 54 additions & 0 deletions token-registry/githubify.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package tokenregistry

import "strings"

func (t Token) GitHubify() Token {
out := t

if out.LogoURIs != nil {
out.LogoURIs = out.LogoURIs.GitHubify()
}

for imgIdx, img := range out.Images {
out.Images[imgIdx] = img.GitHubify()
}

return out
}

func localImageToGitHub(local string) string {
trimmed := strings.TrimPrefix(local, "./img/")
return "https://raw.githubusercontent.com/NibiruChain/nibiru/main/token-registry/img/" + trimmed
}

func isLocalImage(maybeLocal *string) bool {
return strings.HasPrefix(*maybeLocal, "./img")
}
Unique-Divine marked this conversation as resolved.
Show resolved Hide resolved

func (logouris LogoURIs) GitHubify() *LogoURIs {
out := new(LogoURIs)
if logouris.Png != nil && isLocalImage(logouris.Png) {
out.Png = some(localImageToGitHub(*logouris.Png))
}
if logouris.Svg != nil && isLocalImage(logouris.Svg) {
out.Svg = some(localImageToGitHub(*logouris.Svg))
}
return out
}
Unique-Divine marked this conversation as resolved.
Show resolved Hide resolved

func (ai AssetImage) GitHubify() AssetImage {
out := AssetImage{}
if ai.Png != nil && isLocalImage(ai.Png) {
out.Png = some(localImageToGitHub(*ai.Png))
}
if ai.Svg != nil && isLocalImage(ai.Svg) {
out.Svg = some(localImageToGitHub(*ai.Svg))
}
if ai.Theme != nil {
out.Theme = ai.Theme
}
if ai.ImageSync != nil {
out.ImageSync = ai.ImageSync
}
return out
}
Unique-Divine marked this conversation as resolved.
Show resolved Hide resolved
Binary file added token-registry/img/0000_nibiru.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions token-registry/img/0000_nibiru.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added token-registry/img/0001_stnibi-500x500.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions token-registry/img/0001_stnibi-500x500.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added token-registry/img/0002_usdc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions token-registry/img/0002_usdc.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added token-registry/img/0003_astrovault-axv.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions token-registry/img/0003_astrovault-axv.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading