Skip to content

feat(precompiles): erc20 factory precompile #405

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

Open
wants to merge 8 commits into
base: main
Choose a base branch
from

Conversation

GuillemGarciaDev
Copy link

Description

This PR implements event emission functionality for the ERC20 Factory precompile and fixes critical issues with event topic handling.

ERC20 Factory Precompile Overview

The ERC20 Factory precompile is a precompile deployed at address 0x0000000000000000000000000000000000000900 that enables deterministic creation of ERC20 token pairs. It provides a factory pattern for deploying ERC20 tokens with predictable addresses.

Core Functionality

The precompile bridges Ethereum-style ERC20 tokens with Cosmos SDK's bank module, automatically:

  • Creating bank denomination metadata for new tokens
  • Registering token pairs in the ERC20 module
  • Enabling dynamic precompiles for token contracts

Available Methods

1. create(uint8 tokenPairType, bytes32 salt, string name, string symbol, uint8 decimals) → address

Transaction Method | Gas Cost: 3,000,000

Creates a new ERC20 token pair and returns the deployed contract address.

Parameters:

  • tokenPairType: Type identifier for the token pair (uint8)
  • salt: 32-byte salt for deterministic address generation
  • name: Token name (3-128 characters)
  • symbol: Token symbol (3-16 characters)
  • decimals: Number of decimal places (uint8)

Process:

  1. Calculates deterministic address using CREATE2
  2. Creates bank denomination metadata
  3. Registers token pair in ERC20 module
  4. Enables dynamic precompiles for the token
  5. Emits Create event
  6. Returns the token contract address

2. calculateAddress(uint8 tokenPairType, bytes32 salt) → address

View Method | Gas Cost: 3,000

Calculates the deterministic address where a token would be deployed without actually creating it.

Parameters:

  • tokenPairType: Type identifier for the token pair
  • salt: 32-byte salt for address calculation

Returns: The calculated contract address using CREATE2 formula

Events Emitted

Create(address indexed tokenAddress, uint8 tokenPairType, bytes32 salt, string name, string symbol, uint8 decimals)

Emitted when a new ERC20 token pair is successfully created.

Indexed Parameters:

  • tokenAddress: Address of the deployed token contract

Non-Indexed Parameters:

  • tokenPairType: Type identifier used during creation
  • salt: Salt value used for deterministic deployment
  • name: Token name
  • symbol: Token symbol
  • decimals: Decimal precision

Integration with Cosmos SDK

The precompile seamlessly integrates with multiple Cosmos SDK modules:

  • Bank Module: Creates denomination metadata for token accounting
  • ERC20 Module: Registers token pairs for cross-module compatibility

Critical Files to Review

  • precompiles/erc20factory/events.go - Core event emission logic
  • precompiles/erc20factory/types.go - Event struct definitions
  • precompiles/erc20factory/tx.go - Integration with Create method
  • tests/integration/precompiles/erc20factory/test_events.go - Go test coverage
  • tests/solidity/suites/precompiles/test/erc20factory.js - JavaScript test coverage

Closes: #XXXX


Author Checklist

All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.

I have...

  • tackled an existing issue or discussed with a team member
  • left instructions on how to review the changes
  • targeted the main branch

Reviewers Checklist

All items are required.
Please add a note if the item is not applicable
and please add your handle next to the items reviewed
if you only reviewed selected items.

I have...

  • added a relevant changelog entry to the Unreleased section in CHANGELOG.md
  • confirmed all author checklist items have been addressed
  • confirmed that this PR does not change production code
  • reviewed content
  • tested instructions (if applicable)
  • confirmed all CI checks have passed

@GuillemGarciaDev GuillemGarciaDev requested review from a team as code owners August 5, 2025 13:02
@GuillemGarciaDev
Copy link
Author

@aljo242 @vladjdk reopening this PR since it was closed by error. Ready for another review, all conflicts solved.

@aljo242
Copy link
Contributor

aljo242 commented Aug 6, 2025

Hey @GuillemGarciaDev looks like we have some solidity tests failing from these changes

@vladjdk vladjdk self-assigned this Aug 11, 2025
@aljo242 aljo242 added the v0.5.x targeting v0.5.x label Aug 14, 2025
@GuillemGarciaDev
Copy link
Author

Hey @GuillemGarciaDev looks like we have some solidity tests failing from these changes

Fixes applied! They should pass now.

Copy link
Member

@vladjdk vladjdk left a comment

Choose a reason for hiding this comment

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

Overall, looks great! I do have a couple nits and comments, though. After you look at those, we should be good to finally merge :)

*/
event Create(
address indexed tokenAddress,
uint8 tokenPairType,
Copy link
Member

Choose a reason for hiding this comment

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

Could you explain what this is and why it's needed? If I understand correctly, this is the ownership type, but we seem to always set this to externally owned. If it's something different, can you link this in the docs?

return nil, err
}

address := crypto.CreateAddress2(caller, salt, calculateCodeHash(tokenType))
Copy link
Member

Choose a reason for hiding this comment

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

As a sanity check, could we also make sure that there's no contract storage/hash at the address? Probably fine here regardless, but would be good to verify

errContains: "invalid premintedSupply",
},
{
name: "fail - invalid number of arguments",
Copy link
Member

Choose a reason for hiding this comment

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

Could we add a test here that checks that blocked addresses (like module addresses) cannot receive the tokens?

}

symbol, ok = args[3].(string)
if !ok || len(symbol) < 3 || len(symbol) > 16 {
Copy link
Member

Choose a reason for hiding this comment

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

We should allow the symbol to be 1 character. There are cases like this in production already, like Sonic's $S.

uint8(0),
[32]uint8{},
name,
"is",
Copy link
Member

Choose a reason for hiding this comment

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

This should probably be a valid symbol, nothing in the bank metadata validation prevents symbols of under 3 characters to be added.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
v0.5.x targeting v0.5.x
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants