-
Notifications
You must be signed in to change notification settings - Fork 196
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(world-modules): add ERC20 module (#1789)
Co-authored-by: Fraser Scott <[email protected]> Co-authored-by: 0xhank <[email protected]>
- Loading branch information
1 parent
35348f8
commit 8363837
Showing
22 changed files
with
2,666 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
--- | ||
"@latticexyz/world-modules": minor | ||
--- | ||
|
||
Added the `ERC20Module` to `@latticexyz/world-modules`. | ||
This module allows the registration of `ERC20` tokens in an existing World. | ||
|
||
Important note: this module has not been audited yet, so any production use is discouraged for now. | ||
|
||
```solidity | ||
import { PuppetModule } from "@latticexyz/world-modules/src/modules/puppet/PuppetModule.sol"; | ||
import { IERC20Mintable } from "@latticexyz/world-modules/src/modules/erc20-puppet/IERC20Mintable.sol"; | ||
import { registerERC20 } from "@latticexyz/world-modules/src/modules/erc20-puppet/registerERC20.sol"; | ||
// The ERC20 module requires the Puppet module to be installed first | ||
world.installModule(new PuppetModule(), new bytes(0)); | ||
// After the Puppet module is installed, new ERC20 tokens can be registered | ||
IERC20Mintable token = registerERC20(world, "myERC20", ERC20MetadataData({ decimals: 18, name: "Token", symbol: "TKN" })); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
ds-test/=node_modules/ds-test/src/ | ||
forge-std/=node_modules/forge-std/src/ | ||
@latticexyz/=node_modules/@latticexyz/ | ||
@latticexyz/=node_modules/@latticexyz/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.21; | ||
|
||
/* Autogenerated file. Do not edit manually. */ | ||
|
||
/** | ||
* @title IERC20System | ||
* @dev This interface is automatically generated from the corresponding system contract. Do not edit manually. | ||
*/ | ||
interface IERC20System { | ||
function name() external view returns (string memory); | ||
|
||
function symbol() external view returns (string memory); | ||
|
||
function decimals() external view returns (uint8); | ||
|
||
function totalSupply() external view returns (uint256); | ||
|
||
function balanceOf(address account) external view returns (uint256); | ||
|
||
function allowance(address owner, address spender) external view returns (uint256); | ||
|
||
function transfer(address to, uint256 value) external returns (bool); | ||
|
||
function approve(address spender, uint256 value) external returns (bool); | ||
|
||
function transferFrom(address from, address to, uint256 value) external returns (bool); | ||
|
||
function mint(address account, uint256 value) external; | ||
|
||
function burn(address account, uint256 value) external; | ||
} |
93 changes: 93 additions & 0 deletions
93
packages/world-modules/src/modules/erc20-puppet/ERC20Module.sol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
// SPDX-License-Identifier: MIT | ||
pragma solidity >=0.8.21; | ||
|
||
import { ResourceIds } from "@latticexyz/store/src/codegen/tables/ResourceIds.sol"; | ||
import { ResourceId } from "@latticexyz/store/src/ResourceId.sol"; | ||
import { Module } from "@latticexyz/world/src/Module.sol"; | ||
import { WorldResourceIdLib } from "@latticexyz/world/src/WorldResourceId.sol"; | ||
import { IBaseWorld } from "@latticexyz/world/src/codegen/interfaces/IBaseWorld.sol"; | ||
import { InstalledModules } from "@latticexyz/world/src/codegen/tables/InstalledModules.sol"; | ||
|
||
import { Puppet } from "../puppet/Puppet.sol"; | ||
import { createPuppet } from "../puppet/createPuppet.sol"; | ||
import { MODULE_NAME as PUPPET_MODULE_NAME } from "../puppet/constants.sol"; | ||
|
||
import { MODULE_NAME, MODULE_NAMESPACE, MODULE_NAMESPACE_ID, ERC20_REGISTRY_TABLE_ID } from "./constants.sol"; | ||
import { _allowancesTableId, _balancesTableId, _metadataTableId, _erc20SystemId } from "./utils.sol"; | ||
import { ERC20System } from "./ERC20System.sol"; | ||
|
||
import { ERC20Registry } from "./tables/ERC20Registry.sol"; | ||
import { Balances } from "./tables/Balances.sol"; | ||
import { Allowances } from "./tables/Allowances.sol"; | ||
import { Metadata, MetadataData } from "./tables/Metadata.sol"; | ||
|
||
contract ERC20Module is Module { | ||
error ERC20Module_InvalidNamespace(bytes14 namespace); | ||
|
||
function getName() public pure override returns (bytes16) { | ||
return MODULE_NAME; | ||
} | ||
|
||
/** | ||
* Register systems and tables for a new ERC20 token in a given namespace | ||
*/ | ||
function _registerERC20(bytes14 namespace) internal { | ||
// Register the tables | ||
Allowances.register(_allowancesTableId(namespace)); | ||
Balances.register(_balancesTableId(namespace)); | ||
Metadata.register(_metadataTableId(namespace)); | ||
|
||
// Register a new ERC20System | ||
IBaseWorld(_world()).registerSystem(_erc20SystemId(namespace), new ERC20System(), true); | ||
} | ||
|
||
function _requireDependencies() internal view { | ||
// If the PuppetModule is not installed yet, install it | ||
if (InstalledModules.get(PUPPET_MODULE_NAME, keccak256(new bytes(0))) == address(0)) { | ||
revert Module_MissingDependency(string(bytes.concat(PUPPET_MODULE_NAME))); | ||
} | ||
} | ||
|
||
function install(bytes memory args) public { | ||
// Require the module to not be installed with these args yet | ||
if (InstalledModules.get(MODULE_NAME, keccak256(args)) != address(0)) { | ||
revert Module_AlreadyInstalled(); | ||
} | ||
|
||
// Extract args | ||
(bytes14 namespace, MetadataData memory metadata) = abi.decode(args, (bytes14, MetadataData)); | ||
|
||
// Require the namespace to not be the module's namespace | ||
if (namespace == MODULE_NAMESPACE) { | ||
revert ERC20Module_InvalidNamespace(namespace); | ||
} | ||
|
||
// Require dependencies | ||
_requireDependencies(); | ||
|
||
// Register the ERC20 tables and system | ||
_registerERC20(namespace); | ||
|
||
// Initialize the Metadata | ||
Metadata.set(_metadataTableId(namespace), metadata); | ||
|
||
// Deploy and register the ERC20 puppet. | ||
IBaseWorld world = IBaseWorld(_world()); | ||
ResourceId erc20SystemId = _erc20SystemId(namespace); | ||
address puppet = createPuppet(world, erc20SystemId); | ||
|
||
// Transfer ownership of the namespace to the caller | ||
ResourceId namespaceId = WorldResourceIdLib.encodeNamespace(namespace); | ||
world.transferOwnership(namespaceId, _msgSender()); | ||
|
||
// Register the ERC20 in the ERC20Registry | ||
if (!ResourceIds.getExists(ERC20_REGISTRY_TABLE_ID)) { | ||
ERC20Registry.register(ERC20_REGISTRY_TABLE_ID); | ||
} | ||
ERC20Registry.set(ERC20_REGISTRY_TABLE_ID, namespaceId, puppet); | ||
} | ||
|
||
function installRoot(bytes memory) public pure { | ||
revert Module_RootInstallNotSupported(); | ||
} | ||
} |
Oops, something went wrong.