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: custom token registrars #116

Merged
merged 59 commits into from
Nov 1, 2023
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
e9c1939
Added a canonical token registrar.
Foivos Oct 2, 2023
10e4503
wrote some canonical token registrar tests
Foivos Oct 2, 2023
2866ecf
made the standardized token registrar
Foivos Oct 2, 2023
1127093
Wrote some basic tests
Foivos Oct 3, 2023
943de1f
Merge remote-tracking branch 'origin/main' into feat/custom-token-reg…
Foivos Oct 3, 2023
09b66bb
lint and fix a merge bug
Foivos Oct 3, 2023
f4ef75b
feat: bump to latest gmp-sdk and cgp
milapsheth Oct 9, 2023
4569336
Merge branch 'axe-2034' into feat/custom-token-registars
milapsheth Oct 9, 2023
14fecc4
rebase over dep bump
milapsheth Oct 9, 2023
8682513
Merge branch 'main' into feat/custom-token-registars
milapsheth Oct 12, 2023
1bd5f9b
clean lock file
milapsheth Oct 12, 2023
3391cd8
Merge branch 'main' into feat/custom-token-registars
milapsheth Oct 12, 2023
f82b23c
Merge branch 'main' into feat/custom-token-registars
milapsheth Oct 12, 2023
f0a7e29
slither checks
milapsheth Oct 12, 2023
04972f9
Merge branch 'main' into feat/custom-token-registars
milapsheth Oct 12, 2023
df97235
Added roles, tests pending
Foivos Oct 17, 2023
8ea68ca
fix: tests
Oct 19, 2023
afdb98d
Merge remote-tracking branch 'origin/main' into feat/roles
Oct 19, 2023
fc0d72b
Added some tests and fixed constants
Foivos Oct 19, 2023
4b0586d
made lint happy
Foivos Oct 19, 2023
8c28d6d
Chnaged roles constants to enum to make slither happy
Foivos Oct 19, 2023
3ef1db2
Fixed tests
Foivos Oct 20, 2023
1566fec
Merge branch 'main' into feat/custom-token-registars
milapsheth Oct 23, 2023
ed4be65
querrying chain name from the remoteAddressValidator for the registrars
Foivos Oct 25, 2023
4ec3612
Merge remote-tracking branch 'origin/feat/custom-token-registars' int…
Foivos Oct 25, 2023
844bfb6
Merge remote-tracking branch 'origin/feat/roles' into feat/custom-tok…
Foivos Oct 25, 2023
a8db922
stash to add more utils to roles.
Foivos Oct 25, 2023
6c4e38f
Added getter for distributor and opearator.
Foivos Oct 25, 2023
51a3ce4
made lint happy
Foivos Oct 25, 2023
68fcbdd
fixed a spelling error
Foivos Oct 25, 2023
7b69d55
Merge branch 'feat/roles' into feat/custom-token-registars
Foivos Oct 25, 2023
7815108
Fixed tests and interfaces
Foivos Oct 25, 2023
de5bcda
Removed a lot of unused imports and made routers upgradable.
Foivos Oct 27, 2023
fe2af9f
Merge remote-tracking branch 'origin/main' into feat/roles
Foivos Oct 27, 2023
6147bf3
Merge remote-tracking branch 'origin/main' into feat/custom-token-reg…
Foivos Oct 30, 2023
09fa22d
Merge branch 'feat/roles' into feat/custom-token-registars
Foivos Oct 30, 2023
551f67e
Addressed changes
Foivos Oct 31, 2023
a6216f0
update for the new roles functions
Foivos Oct 31, 2023
992ba96
Merge branch 'feat/roles' into feat/custom-token-registars
Foivos Oct 31, 2023
05c1855
allow for mintAmount for standardized tokens
Foivos Oct 31, 2023
a593d69
Merge remote-tracking branch 'origin/main' into feat/roles
Foivos Oct 31, 2023
2831316
update sdk
Foivos Oct 31, 2023
394dca9
Merge branch 'main' into feat/roles
Foivos Oct 31, 2023
c555815
updage to newest sdk
Foivos Oct 31, 2023
fc791d1
made lint happy
Foivos Oct 31, 2023
6cc49c0
Merge branch 'feat/roles' into feat/custom-token-registars
Foivos Oct 31, 2023
b8ab648
added some changes
Foivos Oct 31, 2023
a8aac7d
Merge remote-tracking branch 'origin/main' into feat/custom-token-reg…
Foivos Oct 31, 2023
7d4d5bd
Added some utilities
Foivos Oct 31, 2023
ca65004
made lint happy
Foivos Oct 31, 2023
f190a59
Merge branch 'main' into feat/custom-token-registars
milapsheth Oct 31, 2023
9ac0cf7
fix test
milapsheth Oct 31, 2023
3b76ac1
build warnings
milapsheth Oct 31, 2023
44dc8fc
revert fix
milapsheth Nov 1, 2023
83353a6
fix create3 deployer reference
milapsheth Nov 1, 2023
e692dbc
fix test
milapsheth Nov 1, 2023
f2d76c2
slither warnings
milapsheth Nov 1, 2023
0f78048
switch proxies
milapsheth Nov 1, 2023
f7f4b47
fix import
milapsheth Nov 1, 2023
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
11 changes: 11 additions & 0 deletions contracts/interfaces/ICanonicalTokenRegistrar.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface ICanonicalTokenRegistrar {
error ZeroAddress();

function chainName() external view returns (string memory);

function chainNameHash() external view returns (bytes32);
}
19 changes: 17 additions & 2 deletions contracts/interfaces/IStandardizedToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,35 @@

pragma solidity ^0.8.0;

import { IERC20 } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IERC20.sol';
import { IContractIdentifier } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/interfaces/IContractIdentifier.sol';

import { IImplementation } from './IImplementation.sol';
import { IInterchainToken } from './IInterchainToken.sol';
import { IDistributable } from './IDistributable.sol';
import { IERC20MintableBurnable } from './IERC20MintableBurnable.sol';
import { ITokenManager } from './ITokenManager.sol';
import { IERC20Named } from './IERC20Named.sol';

/**
* @title StandardizedToken
* @notice This contract implements a standardized token which extends InterchainToken functionality.
* This contract also inherits Distributable and Implementation logic.
*/
interface IStandardizedToken is IImplementation, IInterchainToken, IDistributable, IERC20MintableBurnable, IERC20, IContractIdentifier {
interface IStandardizedToken is IInterchainToken, IDistributable, IERC20MintableBurnable, IERC20Named, IContractIdentifier {
error TokenManagerAddressZero();
error TokenNameEmpty();

/**
* @notice Called by the proxy to setup itself.
* @dev This should be hidden by the proxy.
* @param params the data to be used for the initialization.
*/
function setup(bytes calldata params) external;

/**
* @notice Getter for the tokenManager used for this token.
* @dev Needs to be overwitten.
* @return tokenManager_ the TokenManager called to facilitate cross chain transfers.
*/
function tokenManager() external view returns (ITokenManager tokenManager_);
}
11 changes: 11 additions & 0 deletions contracts/interfaces/IStandardizedTokenRegistrar.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

interface IStandardizedTokenRegistrar {
error ZeroAddress();

function chainName() external view returns (string memory);

function chainNameHash() external view returns (bytes32);
}
5 changes: 3 additions & 2 deletions contracts/token-implementations/StandardizedToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

pragma solidity ^0.8.0;

import { IImplementation } from '../interfaces/IImplementation.sol';
import { IStandardizedToken } from '../interfaces/IStandardizedToken.sol';
import { ITokenManager } from '../interfaces/ITokenManager.sol';
import { IInterchainToken } from '../interfaces/IInterchainToken.sol';
Expand Down Expand Up @@ -46,7 +47,7 @@ contract StandardizedToken is InterchainToken, ERC20Permit, Implementation, Dist
* @notice Returns the token manager for this token
* @return ITokenManager The token manager contract
*/
function tokenManager() public view override(InterchainToken, IInterchainToken) returns (ITokenManager) {
function tokenManager() public view override(InterchainToken, IStandardizedToken) returns (ITokenManager) {
return ITokenManager(tokenManager_);
}

Expand All @@ -55,7 +56,7 @@ contract StandardizedToken is InterchainToken, ERC20Permit, Implementation, Dist
* @param params The setup parameters in bytes
* The setup params include tokenManager, distributor, tokenName, symbol, decimals, mintAmount and mintTo
*/
function setup(bytes calldata params) external override onlyProxy {
function setup(bytes calldata params) external override(IImplementation, IStandardizedToken) onlyProxy {
{
address distributor_;
address tokenManagerAddress;
Expand Down
63 changes: 63 additions & 0 deletions contracts/token-registrars/CanonicalTokenRegistrar.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { IInterchainTokenService } from '../interfaces/IInterchainTokenService.sol';
import { ICanonicalTokenRegistrar } from '../interfaces/ICanonicalTokenRegistrar.sol';
import { ITokenManagerType } from '../interfaces/ITokenManagerType.sol';
import { IERC20Named } from '../interfaces/IERC20Named.sol';

import { Multicall } from '../utils/Multicall.sol';

contract CanonicalTokenRegistrar is ICanonicalTokenRegistrar, ITokenManagerType, Multicall {
IInterchainTokenService public immutable service;
string public chainName;
bytes32 public immutable chainNameHash;

bytes32 internal constant PREFIX_CANONICAL_TOKEN_SALT = keccak256('canonical-token-salt');

constructor(address interchainTokenServiceAddress, string memory chainName_) {
if (interchainTokenServiceAddress == address(0)) revert ZeroAddress();
service = IInterchainTokenService(interchainTokenServiceAddress);
chainName = chainName_;
chainNameHash = keccak256(bytes(chainName_));
}

function getCanonicalTokenSalt(address tokenAddress) public view returns (bytes32 salt) {
salt = keccak256(abi.encode(PREFIX_CANONICAL_TOKEN_SALT, chainNameHash, tokenAddress));
}

function getCanonicalTokenId(address tokenAddress) public view returns (bytes32 tokenId) {
tokenId = service.getCustomTokenId(address(this), getCanonicalTokenSalt(tokenAddress));
}

function registerCanonicalToken(address tokenAddress) external payable returns (bytes32 tokenId) {
bytes memory params = abi.encode('', tokenAddress);
bytes32 salt = getCanonicalTokenSalt(tokenAddress);
tokenId = service.deployCustomTokenManager(salt, TokenManagerType.LOCK_UNLOCK, params);
Copy link
Member

Choose a reason for hiding this comment

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

Shall we remove the canonical register/deploy methods from ITS?

}

function deployAndRegisterRemoteCanonicalToken(bytes32 salt, string calldata destinationChain, uint256 gasValue) external payable {
// This ensures that the token manages has been deployed by this address, so it's safe to trust it.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// This ensures that the token manages has been deployed by this address, so it's safe to trust it.
// This ensures that the token manager has been deployed by this address, so it's safe to trust it.

bytes32 tokenId = service.getCustomTokenId(address(this), salt);
IERC20Named token = IERC20Named(service.getTokenAddress(tokenId));
// The 3 lines below will revert if the token manager does not exist.
string memory tokenName = token.name();
string memory tokenSymbol = token.symbol();
uint8 tokenDecimals = token.decimals();

// slither-disable-next-line arbitrary-send-eth
service.deployAndRegisterRemoteStandardizedToken{ value: gasValue }(
salt,
tokenName,
tokenSymbol,
tokenDecimals,
'',
'',
0,
'',
destinationChain,
gasValue
);
}
}
138 changes: 138 additions & 0 deletions contracts/token-registrars/StandardizedTokenRegistrar.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import { SafeTokenTransfer } from '@axelar-network/axelar-gmp-sdk-solidity/contracts/libs/SafeTransfer.sol';

import { IInterchainTokenService } from '../interfaces/IInterchainTokenService.sol';
import { IStandardizedTokenRegistrar } from '../interfaces/IStandardizedTokenRegistrar.sol';
import { ITokenManagerType } from '../interfaces/ITokenManagerType.sol';
import { ITokenManager } from '../interfaces/ITokenManager.sol';
import { IStandardizedToken } from '../interfaces/IStandardizedToken.sol';

import { Multicall } from '../utils/Multicall.sol';

import { AddressBytesUtils } from '../libraries/AddressBytesUtils.sol';

contract StandardizedTokenRegistrar is IStandardizedTokenRegistrar, ITokenManagerType, Multicall {
using AddressBytesUtils for bytes;
using AddressBytesUtils for address;
using SafeTokenTransfer for IStandardizedToken;

IInterchainTokenService public immutable service;
string public chainName;
bytes32 public immutable chainNameHash;

struct DeployParams {
address deployer;
bytes distributor;
bytes operator;
}

mapping(bytes32 => DeployParams) public deploymentParameterMap;
Comment on lines +28 to +34
Copy link
Member

Choose a reason for hiding this comment

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

unused?


bytes32 internal constant PREFIX_STANDARDIZED_TOKEN_SALT = keccak256('standardized-token-salt');

constructor(address interchainTokenServiceAddress, string memory chainName_) {
if (interchainTokenServiceAddress == address(0)) revert ZeroAddress();
service = IInterchainTokenService(interchainTokenServiceAddress);
chainName = chainName_;
chainNameHash = keccak256(bytes(chainName_));
}

function getStandardizedTokenSalt(address deployer, bytes32 salt) public view returns (bytes32) {
return keccak256(abi.encode(PREFIX_STANDARDIZED_TOKEN_SALT, chainNameHash, deployer, salt));
}

function getStandardizedTokenId(address deployer, bytes32 salt) public view returns (bytes32 tokenId) {
tokenId = service.getCustomTokenId(address(this), getStandardizedTokenSalt(deployer, salt));
}

function getStandardizedTokenAddress(address deployer, bytes32 salt) public view returns (address tokenAddress) {
tokenAddress = service.getStandardizedTokenAddress(getStandardizedTokenId(deployer, salt));
}

function deployStandardizedToken(
bytes32 salt,
string calldata name,
string calldata symbol,
uint8 decimals,
uint256 mintAmount,
address distributor
Copy link
Member

Choose a reason for hiding this comment

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

let operator still be different than sender, since it's an argument for the remote deploy method as well?

) external payable {
address sender = msg.sender;
salt = getStandardizedTokenSalt(sender, salt);
bytes32 tokenId = service.getCustomTokenId(address(this), salt);

service.deployAndRegisterStandardizedToken(salt, name, symbol, decimals, mintAmount, distributor);
ITokenManager tokenManager = ITokenManager(service.getTokenManagerAddress(tokenId));
tokenManager.transferOperatorship(sender);

IStandardizedToken token = IStandardizedToken(service.getStandardizedTokenAddress(tokenId));
token.safeTransfer(sender, mintAmount);
}

function deployRemoteStandarizedToken(
Copy link
Member

Choose a reason for hiding this comment

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

Can we combine the two deploy methods into one? The interchain address tracker has the current chain, so we can specialize the logic by comparing the chain name being passed. Reduces number of entrypoints. Perhaps we can simplify this in ITS itself.

Copy link
Member

@milapsheth milapsheth Nov 1, 2023

Choose a reason for hiding this comment

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

Similarly, we could combine deploy custom token manager current/remote into one method

bytes32 salt,
bool sameDistributor,
string memory destinationChain,
uint256 gasValue
) external payable {
string memory tokenName;
string memory tokenSymbol;
uint8 tokenDecimals;
bytes memory distributor = '';
bytes memory operator;

{
address sender = msg.sender;
salt = getStandardizedTokenSalt(sender, salt);
bytes32 tokenId = service.getCustomTokenId(address(this), salt);

IStandardizedToken token = IStandardizedToken(service.getStandardizedTokenAddress(tokenId));
ITokenManager tokenManager = ITokenManager(service.getTokenManagerAddress(tokenId));

tokenName = token.name();
tokenSymbol = token.symbol();
tokenDecimals = token.decimals();
if (sameDistributor) distributor = token.distributor().toBytes();
operator = tokenManager.operator().toBytes();
}

_deployAndRegisterRemoteStandardizedToken(
salt,
tokenName,
tokenSymbol,
tokenDecimals,
distributor,
operator,
destinationChain,
gasValue
);
}

function _deployAndRegisterRemoteStandardizedToken(
bytes32 salt,
string memory tokenName,
string memory tokenSymbol,
uint8 tokenDecimals,
bytes memory distributor,
bytes memory operator,
string memory destinationChain,
uint256 gasValue
) internal {
// slither-disable-next-line arbitrary-send-eth
service.deployAndRegisterRemoteStandardizedToken{ value: gasValue }(
salt,
tokenName,
tokenSymbol,
tokenDecimals,
distributor,
'',
Copy link
Member

Choose a reason for hiding this comment

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

mintTo isn't being provided so I think the initial mint will be skipped? Can you add that, and add test coverage for it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed

0,
operator,
destinationChain,
gasValue
);
}
}
Loading
Loading