From 551d3764ae82b3c4db30ccf2699d6fbbacd9166a Mon Sep 17 00:00:00 2001 From: Jawad <38837406+JDawg287@users.noreply.github.com> Date: Wed, 22 Nov 2023 10:09:02 -0500 Subject: [PATCH] chore: refactor using a unique symbol per token (#115) Signed-off-by: Jawad Tariq --- contracts/examples/ERC20Messaging.sol | 131 +++++++++--------- contracts/interfaces/IERC20Messaging.sol | 26 ++-- package.json | 2 +- test/topos-core/ToposMessaging.test.ts | 66 +++------ .../shared/constants/transactions.ts | 12 +- 5 files changed, 111 insertions(+), 126 deletions(-) diff --git a/contracts/examples/ERC20Messaging.sol b/contracts/examples/ERC20Messaging.sol index a15175d..919ce03 100644 --- a/contracts/examples/ERC20Messaging.sol +++ b/contracts/examples/ERC20Messaging.sol @@ -41,8 +41,8 @@ contract ERC20Messaging is IERC20Messaging, ToposMessaging { function deployToken(bytes calldata params) external { (string memory name, string memory symbol, uint256 cap, uint256 dailyMintLimit, uint256 initialSupply) = abi .decode(params, (string, string, uint256, uint256, uint256)); - - bytes32 salt = keccak256(abi.encodePacked(msg.sender, symbol)); + // Note: this does not stop deployment of the same symbol to other subnets. Do not use in a production system. + bytes32 salt = keccak256(abi.encodePacked(symbol)); // Deploy the token contract // The tx will revert if the token already exists because the salt will be the same address tokenAddress = ITokenDeployer(_tokenDeployerAddr).deployToken( @@ -55,9 +55,9 @@ contract ERC20Messaging is IERC20Messaging, ToposMessaging { salt ); - _setTokenType(tokenAddress, TokenType.InternalBurnableFrom); + _setTokenType(symbol, TokenType.InternalBurnableFrom); _setTokenAddress(symbol, tokenAddress); - _setTokenDailyMintLimit(dailyMintLimit, tokenAddress); + _setTokenDailyMintLimit(dailyMintLimit, symbol); emit TokenDeployed(symbol, tokenAddress); } @@ -65,20 +65,21 @@ contract ERC20Messaging is IERC20Messaging, ToposMessaging { /// @notice Entry point for sending a cross-subnet asset transfer /// @dev The input data is sent to the target subnet externally /// @param targetSubnetId Target subnet ID - /// @param tokenAddress Address of target token contract + /// @param symbol Symbol of token /// @param receiver Receiver's address /// @param amount Amount of token to send - function sendToken(SubnetId targetSubnetId, address tokenAddress, address receiver, uint256 amount) external { + function sendToken(SubnetId targetSubnetId, string calldata symbol, address receiver, uint256 amount) external { if (_toposCoreAddr.code.length == uint256(0)) revert InvalidToposCore(); - _burnTokenFrom(msg.sender, tokenAddress, amount); - emit TokenSent(targetSubnetId, tokenAddress, receiver, amount); + Token memory token = getTokenBySymbol(symbol); + _burnTokenFrom(msg.sender, symbol, amount); + emit TokenSent(targetSubnetId, symbol, token.addr, receiver, amount); _emitMessageSentEvent(targetSubnetId); } - /// @notice Gets the token by address - /// @param tokenAddress Address of token contract - function getTokenByAddress(address tokenAddress) public view returns (Token memory token) { - bytes32 tokenKey = _getTokenKey(tokenAddress); + /// @notice Gets the token by symbol + /// @param symbol Symbol of token + function getTokenBySymbol(string calldata symbol) public view returns (Token memory token) { + bytes32 tokenKey = _getTokenKey(symbol); token = tokens[tokenKey]; } @@ -94,15 +95,15 @@ contract ERC20Messaging is IERC20Messaging, ToposMessaging { } /// @notice Get the token daily mint amount - /// @param tokenAddress Address of token contract - function tokenDailyMintAmount(address tokenAddress) public view returns (uint256) { - return getUint(_getTokenDailyMintAmountKey(tokenAddress, block.timestamp / 1 days)); + /// @param symbol Symbol of token + function tokenDailyMintAmount(string memory symbol) public view returns (uint256) { + return getUint(_getTokenDailyMintAmountKey(symbol, block.timestamp / 1 days)); } /// @notice Get the token daily mint limit - /// @param tokenAddress Address of token contract - function tokenDailyMintLimit(address tokenAddress) public view returns (uint256) { - return getUint(_getTokenDailyMintLimitKey(tokenAddress)); + /// @param symbol Symbol of token + function tokenDailyMintLimit(string memory symbol) public view returns (uint256) { + return getUint(_getTokenDailyMintLimitKey(symbol)); } /// @notice Get the address of token deployer contract @@ -131,33 +132,34 @@ contract ERC20Messaging is IERC20Messaging, ToposMessaging { bytes32 targetSubnetId = logsTopics[tokenSentEventIndex][1]; if (SubnetId.unwrap(networkSubnetId) != targetSubnetId) revert InvalidSubnetId(); - (address tokenAddress, address receiver, uint256 amount) = abi.decode( + (string memory symbol, , address receiver, uint256 amount) = abi.decode( logsData[tokenSentEventIndex], - (address, address, uint256) + (string, address, address, uint256) ); - _mintToken(tokenAddress, receiver, amount); + _mintToken(symbol, receiver, amount); } /// @notice Burn token internally - /// @param sender Account to burn token from - /// @param tokenAddress Address of target token contract + /// @param sender Sender of token + /// @param symbol Symbol of token /// @param amount Amount of token to burn - function _burnTokenFrom(address sender, address tokenAddress, uint256 amount) internal { - bytes32 tokenKey = _getTokenKey(tokenAddress); - if (!tokenSet.exists(tokenKey)) revert TokenDoesNotExist(tokenAddress); + function _burnTokenFrom(address sender, string calldata symbol, uint256 amount) internal { + bytes32 tokenKey = _getTokenKey(symbol); + if (!tokenSet.exists(tokenKey)) revert TokenDoesNotExist(symbol); if (amount == 0) revert InvalidAmount(); - TokenType tokenType = _getTokenType(tokenAddress); + TokenType tokenType = _getTokenType(symbol); bool burnSuccess; if (tokenType == TokenType.External) { revert UnsupportedTokenType(); } else { + Token memory token = tokens[tokenKey]; burnSuccess = _callERC20Token( - tokenAddress, + token.addr, abi.encodeWithSelector(IBurnableMintableCappedERC20.burnFrom.selector, sender, amount) ); - if (!burnSuccess) revert BurnFailed(tokenAddress); + if (!burnSuccess) revert BurnFailed(symbol); } } @@ -172,19 +174,20 @@ contract ERC20Messaging is IERC20Messaging, ToposMessaging { } /// @notice Mint token internally - /// @param tokenAddress Address of token contract + /// @param symbol Symbol of token /// @param account Account to mint token to /// @param amount Amount of token to mint - function _mintToken(address tokenAddress, address account, uint256 amount) internal { - bytes32 tokenKey = _getTokenKey(tokenAddress); - if (!tokenSet.exists(tokenKey)) revert TokenDoesNotExist(tokenAddress); + function _mintToken(string memory symbol, address account, uint256 amount) internal { + bytes32 tokenKey = _getTokenKey(symbol); + if (!tokenSet.exists(tokenKey)) revert TokenDoesNotExist(symbol); - _setTokenDailyMintAmount(tokenAddress, tokenDailyMintAmount(tokenAddress) + amount); + _setTokenDailyMintAmount(symbol, tokenDailyMintAmount(symbol) + amount); - if (_getTokenType(tokenAddress) == TokenType.External) { + if (_getTokenType(symbol) == TokenType.External) { revert UnsupportedTokenType(); } else { - IBurnableMintableCappedERC20(tokenAddress).mint(account, amount); + Token memory token = tokens[tokenKey]; + IBurnableMintableCappedERC20(token.addr).mint(account, amount); } } @@ -192,7 +195,7 @@ contract ERC20Messaging is IERC20Messaging, ToposMessaging { /// @param symbol Symbol of token /// @param tokenAddress Address of token contract function _setTokenAddress(string memory symbol, address tokenAddress) internal { - bytes32 tokenKey = _getTokenKey(tokenAddress); + bytes32 tokenKey = _getTokenKey(symbol); tokenSet.insert(tokenKey); Token storage token = tokens[tokenKey]; token.symbol = symbol; @@ -201,58 +204,58 @@ contract ERC20Messaging is IERC20Messaging, ToposMessaging { /// @notice Set the token daily mint limit for a token address /// @param limit Daily mint limit of token - /// @param tokenAddress Address of token contract - function _setTokenDailyMintLimit(uint256 limit, address tokenAddress) internal { - _setUint(_getTokenDailyMintLimitKey(tokenAddress), limit); + /// @param symbol Symbol of token + function _setTokenDailyMintLimit(uint256 limit, string memory symbol) internal { + _setUint(_getTokenDailyMintLimitKey(symbol), limit); - emit TokenDailyMintLimitUpdated(tokenAddress, limit); + emit TokenDailyMintLimitUpdated(symbol, limit); } /// @notice Set the token daily mint amount for a token address - /// @param tokenAddress Address of token contract + /// @param symbol Symbol of token /// @param amount Daily mint amount of token - function _setTokenDailyMintAmount(address tokenAddress, uint256 amount) internal { - uint256 limit = tokenDailyMintLimit(tokenAddress); - if (limit > 0 && amount > limit) revert ExceedDailyMintLimit(tokenAddress); + function _setTokenDailyMintAmount(string memory symbol, uint256 amount) internal { + uint256 limit = tokenDailyMintLimit(symbol); + if (limit > 0 && amount > limit) revert ExceedDailyMintLimit(symbol); - _setUint(_getTokenDailyMintAmountKey(tokenAddress, block.timestamp / 1 days), amount); + _setUint(_getTokenDailyMintAmountKey(symbol, block.timestamp / 1 days), amount); } /// @notice Set the token type for a token address - /// @param tokenAddress Address of token contract + /// @param symbol Symbol of token /// @param tokenType Type of token (external/internal) - function _setTokenType(address tokenAddress, TokenType tokenType) internal { - _setUint(_getTokenTypeKey(tokenAddress), uint256(tokenType)); + function _setTokenType(string memory symbol, TokenType tokenType) internal { + _setUint(_getTokenTypeKey(symbol), uint256(tokenType)); } /// @notice Get the token type for a token address - /// @param tokenAddress Address of token contract - function _getTokenType(address tokenAddress) internal view returns (TokenType) { - return TokenType(getUint(_getTokenTypeKey(tokenAddress))); + /// @param symbol Symbol of token + function _getTokenType(string memory symbol) internal view returns (TokenType) { + return TokenType(getUint(_getTokenTypeKey(symbol))); } /// @notice Get the key for the token daily mint limit - /// @param tokenAddress Address of token contract - function _getTokenDailyMintLimitKey(address tokenAddress) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(PREFIX_TOKEN_DAILY_MINT_LIMIT, tokenAddress)); + /// @param symbol Symbol of token + function _getTokenDailyMintLimitKey(string memory symbol) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(PREFIX_TOKEN_DAILY_MINT_LIMIT, symbol)); } /// @notice Get the key for the token daily mint amount - /// @param tokenAddress Address of token contract + /// @param symbol Symbol of token /// @param day Day of token daily mint amount - function _getTokenDailyMintAmountKey(address tokenAddress, uint256 day) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(PREFIX_TOKEN_DAILY_MINT_AMOUNT, tokenAddress, day)); + function _getTokenDailyMintAmountKey(string memory symbol, uint256 day) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(PREFIX_TOKEN_DAILY_MINT_AMOUNT, symbol, day)); } /// @notice Get the key for the token type - /// @param tokenAddress Address of token contract - function _getTokenTypeKey(address tokenAddress) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(PREFIX_TOKEN_TYPE, tokenAddress)); + /// @param symbol Symbol of token + function _getTokenTypeKey(string memory symbol) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(PREFIX_TOKEN_TYPE, symbol)); } /// @notice Get the key for the token - /// @param tokenAddress Address of token contract - function _getTokenKey(address tokenAddress) internal pure returns (bytes32) { - return keccak256(abi.encodePacked(PREFIX_TOKEN_KEY, tokenAddress)); + /// @param symbol Symbol of token + function _getTokenKey(string memory symbol) internal pure returns (bytes32) { + return keccak256(abi.encodePacked(PREFIX_TOKEN_KEY, symbol)); } } diff --git a/contracts/interfaces/IERC20Messaging.sol b/contracts/interfaces/IERC20Messaging.sol index 2c5b0a6..500047f 100644 --- a/contracts/interfaces/IERC20Messaging.sol +++ b/contracts/interfaces/IERC20Messaging.sol @@ -14,28 +14,34 @@ interface IERC20Messaging is IToposMessaging { External // Not supported yet } - event TokenDailyMintLimitUpdated(address tokenAddress, uint256 limit); + event TokenDailyMintLimitUpdated(string symbol, uint256 limit); event TokenDeployed(string symbol, address tokenAddress); - event TokenSent(SubnetId indexed targetSubnetId, address tokenAddress, address receiver, uint256 amount); + event TokenSent( + SubnetId indexed targetSubnetId, + string symbol, + address tokenAddress, + address receiver, + uint256 amount + ); - error BurnFailed(address tokenAddress); - error ExceedDailyMintLimit(address tokenAddress); + error BurnFailed(string symbol); + error ExceedDailyMintLimit(string symbol); error InvalidAmount(); error InvalidOriginAddress(); error InvalidSetDailyMintLimitsParams(); error InvalidSubnetId(); error InvalidTokenDeployer(); - error TokenAlreadyExists(address tokenAddress); - error TokenDoesNotExist(address tokenAddress); + error TokenAlreadyExists(string symbol); + error TokenDoesNotExist(string symbol); error UnsupportedTokenType(); function deployToken(bytes calldata params) external; - function sendToken(SubnetId targetSubnetId, address tokenAddress, address receiver, uint256 amount) external; + function sendToken(SubnetId targetSubnetId, string calldata symbol, address receiver, uint256 amount) external; - function getTokenByAddress(address tokenAddress) external view returns (Token memory token); + function getTokenBySymbol(string calldata symbol) external view returns (Token memory token); function getTokenCount() external view returns (uint256); @@ -43,9 +49,9 @@ interface IERC20Messaging is IToposMessaging { function tokens(bytes32 tokenKey) external view returns (string memory, address); - function tokenDailyMintAmount(address tokenAddress) external view returns (uint256); + function tokenDailyMintAmount(string memory symbol) external view returns (uint256); - function tokenDailyMintLimit(address tokenAddress) external view returns (uint256); + function tokenDailyMintLimit(string memory symbol) external view returns (uint256); function tokenDeployer() external view returns (address); } diff --git a/package.json b/package.json index 33610f8..1a9fe50 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@topos-protocol/topos-smart-contracts", - "version": "2.0.0", + "version": "3.0.0-rc1", "description": "Topos Smart Contracts", "repository": { "type": "git", diff --git a/test/topos-core/ToposMessaging.test.ts b/test/topos-core/ToposMessaging.test.ts index c24bfbe..66b619c 100644 --- a/test/topos-core/ToposMessaging.test.ts +++ b/test/topos-core/ToposMessaging.test.ts @@ -145,37 +145,18 @@ describe('ToposMessaging', () => { expect(await erc20Messaging.getTokenCount()).to.equal(1) }) - it('reverts if the token is already deployed', async () => { + it('reverts if two deployers deploy a token with the same symbol', async () => { const { defaultToken, erc20Messaging } = await loadFixture( deployERC20MessagingFixture ) - await erc20Messaging.deployToken(defaultToken) + await erc20Messaging.deployToken(defaultToken) // deployed by admin + const [, deployer2] = await ethers.getSigners() await expect( - erc20Messaging.deployToken(erc20Messaging.deployToken(defaultToken)) + erc20Messaging.deployToken( + erc20Messaging.connect(deployer2).deployToken(defaultToken) + ) ).to.be.reverted - }) - - it('allows two separate deployers to deploy tokens with same symbol', async () => { - const [deployerOne, deployerTwo] = await ethers.getSigners() - const { defaultToken, erc20Messaging } = await loadFixture( - deployERC20MessagingFixture - ) - const erc20MessagingOne = erc20Messaging.connect(deployerOne) - const txOne = await erc20MessagingOne.deployToken(defaultToken) - const { logs: logsOne } = await txOne.wait() - const tokenAddressOne = logsOne[0]['address'] - await expect(txOne) - .to.emit(erc20Messaging, 'TokenDeployed') - .withArgs(tc.TOKEN_SYMBOL_X, tokenAddressOne) - - const erc20MessagingTwo = erc20Messaging.connect(deployerTwo) - const txTwo = await erc20MessagingTwo.deployToken(defaultToken) - const { logs: logsTwo } = await txTwo.wait() - const tokenAddressTwo = logsTwo[0]['address'] - await expect(txTwo) - .to.emit(erc20Messaging, 'TokenDeployed') - .withArgs(tc.TOKEN_SYMBOL_X, tokenAddressTwo) - expect(tokenAddressOne).to.not.equal(tokenAddressTwo) + expect(await erc20Messaging.getTokenCount()).to.equal(1) }) it('emits a token deployed event', async () => { @@ -201,7 +182,7 @@ describe('ToposMessaging', () => { tc.TOKEN_NAME, tc.TOKEN_SYMBOL_X, tc.MINT_CAP_100_000_000, - 0, + 0, // zero mint limit tc.INITIAL_SUPPLY_10_000_000 ) const tx = await erc20Messaging.deployToken(token) @@ -217,7 +198,7 @@ describe('ToposMessaging', () => { receiver.address, admin, cc.SOURCE_SUBNET_ID_2, - tokenAddress + tc.TOKEN_SYMBOL_X ) const { proofBlob, receiptsRoot } = await getReceiptMptProof( @@ -488,7 +469,7 @@ describe('ToposMessaging', () => { await toposCore.pushCertificate(certificate, cc.CERT_POS_1) await expect( erc20Messaging.execute( - [tc.TOKEN_SENT_INDEX_0], + [tc.TOKEN_SENT_INDEX_2], txc.UNKNOWN_TOKEN_TRANSACTION.proofBlob, txc.UNKNOWN_TOKEN_TRANSACTION.receiptRoot ) @@ -616,14 +597,11 @@ describe('ToposMessaging', () => { const { defaultToken, erc20Messaging } = await loadFixture( deployERC20MessagingFixture ) - const tx = await erc20Messaging.deployToken(defaultToken) - const txReceipt = await tx.wait() - const logs = txReceipt.events?.find((e) => e.event === 'TokenDeployed') - const tokenAddress = logs?.args?.tokenAddress + await erc20Messaging.deployToken(defaultToken) await expect( erc20Messaging.sendToken( cc.TARGET_SUBNET_ID_4, - tokenAddress, + tc.TOKEN_SYMBOL_X, tc.RECIPIENT_ADDRESS, 0 ) @@ -635,20 +613,17 @@ describe('ToposMessaging', () => { deployERC20MessagingFixture ) - const tx = await erc20Messaging.deployToken(defaultToken) - const txReceipt = await tx.wait() - const logs = txReceipt.events?.find((e) => e.event === 'TokenDeployed') - const tokenAddress = logs?.args?.tokenAddress + await erc20Messaging.deployToken(defaultToken) await expect( erc20Messaging.sendToken( cc.TARGET_SUBNET_ID_4, - tokenAddress, + tc.TOKEN_SYMBOL_X, tc.RECIPIENT_ADDRESS, tc.SEND_AMOUNT_50 ) ) .to.be.revertedWithCustomError(erc20Messaging, 'BurnFailed') - .withArgs(tokenAddress) + .withArgs(tc.TOKEN_SYMBOL_X) }) it('emits a token sent event', async () => { @@ -665,7 +640,7 @@ describe('ToposMessaging', () => { await expect( erc20Messaging.sendToken( cc.TARGET_SUBNET_ID_4, - tokenAddress, + tc.TOKEN_SYMBOL_X, tc.RECIPIENT_ADDRESS, tc.SEND_AMOUNT_50 ) @@ -679,6 +654,7 @@ describe('ToposMessaging', () => { .to.emit(erc20Messaging, 'TokenSent') .withArgs( cc.TARGET_SUBNET_ID_4, + tc.TOKEN_SYMBOL_X, tokenAddress, tc.RECIPIENT_ADDRESS, tc.SEND_AMOUNT_50 @@ -708,7 +684,7 @@ describe('ToposMessaging', () => { receiver.address, admin, cc.SOURCE_SUBNET_ID_2, - tokenAddress + await erc20.symbol() ) const { proofBlob, receiptsRoot } = await getReceiptMptProof( @@ -724,18 +700,18 @@ describe('ToposMessaging', () => { receiver: string, signer: SignerWithAddress, targetSubnetId: string, - tokenAddress: string + symbol: string ) { const estimatedGasLimit = await contractInstance.estimateGas.sendToken( targetSubnetId, - tokenAddress, + symbol, receiver, tc.SEND_AMOUNT_50, { gasLimit: 4_000_000 } ) const TxUnsigned = await contractInstance.populateTransaction.sendToken( targetSubnetId, - tokenAddress, + symbol, receiver, tc.SEND_AMOUNT_50, { gasLimit: 4_000_000 } diff --git a/test/topos-core/shared/constants/transactions.ts b/test/topos-core/shared/constants/transactions.ts index 48a7145..6dd7922 100644 --- a/test/topos-core/shared/constants/transactions.ts +++ b/test/topos-core/shared/constants/transactions.ts @@ -11,18 +11,18 @@ class TransactionData { } export const MINT_EXCEED_TRANSACTION: TransactionData = new TransactionData( - '0xf9036f0180f9036af90367822080b90361f9035e018301034fb9010004000000000000000000000000000000000100000400000000000000000000000000000000000000000000000000080040000000000000000000000000200001000000000000000000000008000000000000000240000000000000000800000000000000020000000001000100000800000200000000000000000010000000000000000008000000000000000000000000000000000080000000000000000000120000000000001000000100000000000000000000000000000000000000000000000002000000200000000040000000000000002000001000000001000020000010000000000000000000100000000000000000008000000000000000000000f90253f89b94aff00e3d9958009a7ad46df6b4a5b181dd5cbb38f863a08c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a0000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266a00000000000000000000000005fc8d32690cc91d4c39d9d3abcbd16989f875707a00000000000000000000000000000000000000000000000000000000000000000f89b94aff00e3d9958009a7ad46df6b4a5b181dd5cbb38f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000006df8bb945fc8d32690cc91d4c39d9d3abcbd16989f875707f842a0920718295e8e03a7fda1fe1d8d41ba008f378b1d679ea1a5f70eca3a389a2578a00000000000000000000000000000000000000000000000000000000000000002b860000000000000000000000000aff00e3d9958009a7ad46df6b4a5b181dd5cbb3800000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000006df85a94cf7ed3acca5a467e9e704c703e8d87f634fb0fc9f842a0f27439dc0ef741d8be6e7efbd4f85c0995f73cc11fc82ad08ede2b7bf735a640a0000000000000000000000000000000000000000000000000000000000000000280', - '0xf00cc0c622198fd4cd84cf47433d704d38e374d6d7dc55df705864a457021093' + '0xf903d00180f903cbf903c8822080b903c2f903bf01830124f6b9010004000000000000000000002000000000000100000400000000000000000000000000000000000000200000000000080040000000000000000000000000200001000000000000000000000008000000000000000240000000000000000800000000000000020000000001000100000800000000000000000000000010000000000000000008000000000000000000000000000000000000000000000000000000120000000000001000000100000000000000000000000000000000000000000000000002000000200000000000000000000000002000001000000001000020040010000000000000000000100000000000000000008000000000000000000000f902b4f89b94aff00e3d9958009a7ad46df6b4a5b181dd5cbb38f863a08c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a0000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266a00000000000000000000000005fc8d32690cc91d4c39d9d3abcbd16989f875707a00000000000000000000000000000000000000000000000000000000000000000f89b94aff00e3d9958009a7ad46df6b4a5b181dd5cbb38f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266a00000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000006df9011b945fc8d32690cc91d4c39d9d3abcbd16989f875707f842a00acb1ee8fec20e7591bf34a0435baebd1d056bbfa95b586cbd3d6ba9d0fb646ba00000000000000000000000000000000000000000000000000000000000000002b8c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000aff00e3d9958009a7ad46df6b4a5b181dd5cbb3800000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c8000000000000000000000000000000000000000000000000000000000000006d0000000000000000000000000000000000000000000000000000000000000003544b580000000000000000000000000000000000000000000000000000000000f85a94cf7ed3acca5a467e9e704c703e8d87f634fb0fc9f842a0f27439dc0ef741d8be6e7efbd4f85c0995f73cc11fc82ad08ede2b7bf735a640a0000000000000000000000000000000000000000000000000000000000000000280', + '0xb6433e3ddbe7149c69bd7a8f4643957a0a961157b7c7bb04ae6c2edf20005e94' ) export const UNKNOWN_TOKEN_TRANSACTION: TransactionData = new TransactionData( - '0xf902340180f9022ff9022c822080b90226f9022301828425b9010004000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000080000000000000000000000000000000001000000000000000000000000000000000000000240000000000000000000000000000000000000000001000000000000000200000000000000000000000000000000000008000000000000000000000000000000000080000000000000000000000000000000001000000100000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000001000000000000000000000000000000000000000000000000008000000000000000000000f90119f8bb945fc8d32690cc91d4c39d9d3abcbd16989f875707f842a0920718295e8e03a7fda1fe1d8d41ba008f378b1d679ea1a5f70eca3a389a2578a00000000000000000000000000000000000000000000000000000000000000002b860000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000000000000000000000000000000000000000000032f85a94cf7ed3acca5a467e9e704c703e8d87f634fb0fc9f842a0f27439dc0ef741d8be6e7efbd4f85c0995f73cc11fc82ad08ede2b7bf735a640a0000000000000000000000000000000000000000000000000000000000000000280', - '0xcb65f89f072a5ad7d55d01ea47ff273d723ae875ef41b4733dfb6727d1e042c0' + '0xf903d00180f903cbf903c8822080b903c2f903bf01830124edb9010004000000000000000000002000000000000100000400000000000000000000000000000000000000200000000000080040000000000000000000000000200001000000000000000000000008000000000000000240000000000000000800000000000000020000000001000100000800000000000000000000000010000000000000000008000000000000000000000000000000000000000000000000000000120000000000001000000100000000000000000000000000000000000000000000000002000000200000000000000000000000002000001000000001000020040010000000000000000000100000000000000000008000000000000000000000f902b4f89b94aff00e3d9958009a7ad46df6b4a5b181dd5cbb38f863a08c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a0000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266a00000000000000000000000005fc8d32690cc91d4c39d9d3abcbd16989f875707a00000000000000000000000000000000000000000000000000000000000000000f89b94aff00e3d9958009a7ad46df6b4a5b181dd5cbb38f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000032f9011b945fc8d32690cc91d4c39d9d3abcbd16989f875707f842a00acb1ee8fec20e7591bf34a0435baebd1d056bbfa95b586cbd3d6ba9d0fb646ba00000000000000000000000000000000000000000000000000000000000000002b8c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000003544b580000000000000000000000000000000000000000000000000000000000f85a94cf7ed3acca5a467e9e704c703e8d87f634fb0fc9f842a0f27439dc0ef741d8be6e7efbd4f85c0995f73cc11fc82ad08ede2b7bf735a640a0000000000000000000000000000000000000000000000000000000000000000280', + '0x374fb60b1f8997abb555b628ec568680eb3b62a7e31ada522d43223d1f6ab1ac' ) export const ZERO_ADDRESS_TRANSACTION: TransactionData = new TransactionData( - '0xf9036f0180f9036af90367822080b90361f9035e018301025fb9010004000000000000000000000000000000000100000400000000000000000000000000000000000000000000000000080040000000000000000000000000200001000000000000000000000008000000000000000240000000000000000800000000000000020000000001000100000800000200000000000000000010000000000000000008000000000000000000000000000000000080000000000000000000120000000000001000000100000000000000000000000000000000000000000000000002000000200000000040000000000000002000001000000001000020000010000000000000000000100000000000000000008000000000000000000000f90253f89b94aff00e3d9958009a7ad46df6b4a5b181dd5cbb38f863a08c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a0000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266a00000000000000000000000005fc8d32690cc91d4c39d9d3abcbd16989f875707a00000000000000000000000000000000000000000000000000000000000000000f89b94aff00e3d9958009a7ad46df6b4a5b181dd5cbb38f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000032f8bb945fc8d32690cc91d4c39d9d3abcbd16989f875707f842a0920718295e8e03a7fda1fe1d8d41ba008f378b1d679ea1a5f70eca3a389a2578a00000000000000000000000000000000000000000000000000000000000000002b860000000000000000000000000aff00e3d9958009a7ad46df6b4a5b181dd5cbb3800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000032f85a94cf7ed3acca5a467e9e704c703e8d87f634fb0fc9f842a0f27439dc0ef741d8be6e7efbd4f85c0995f73cc11fc82ad08ede2b7bf735a640a0000000000000000000000000000000000000000000000000000000000000000280', - '0xedbada940f7e82253305537b0a16b58b9d0b13e284eb175052042c5bb57b4847' + '0xf903d00180f903cbf903c8822080b903c2f903bf0183012406b9010004000000000000000000002000000000000100000400000000000000000000000000000000000000200000000000080040000000000000000000000000200001000000000000000000000008000000000000000240000000000000000800000000000000020000000001000100000800000000000000000000000010000000000000000008000000000000000000000000000000000000000000000000000000120000000000001000000100000000000000000000000000000000000000000000000002000000200000000000000000000000002000001000000001000020040010000000000000000000100000000000000000008000000000000000000000f902b4f89b94aff00e3d9958009a7ad46df6b4a5b181dd5cbb38f863a08c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925a0000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266a00000000000000000000000005fc8d32690cc91d4c39d9d3abcbd16989f875707a00000000000000000000000000000000000000000000000000000000000000000f89b94aff00e3d9958009a7ad46df6b4a5b181dd5cbb38f863a0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa0000000000000000000000000f39fd6e51aad88f6f4ce6ab8827279cfffb92266a00000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000032f9011b945fc8d32690cc91d4c39d9d3abcbd16989f875707f842a00acb1ee8fec20e7591bf34a0435baebd1d056bbfa95b586cbd3d6ba9d0fb646ba00000000000000000000000000000000000000000000000000000000000000002b8c00000000000000000000000000000000000000000000000000000000000000080000000000000000000000000aff00e3d9958009a7ad46df6b4a5b181dd5cbb38000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000003544b580000000000000000000000000000000000000000000000000000000000f85a94cf7ed3acca5a467e9e704c703e8d87f634fb0fc9f842a0f27439dc0ef741d8be6e7efbd4f85c0995f73cc11fc82ad08ede2b7bf735a640a0000000000000000000000000000000000000000000000000000000000000000280', + '0x468237a7f4844d3f75ca5d7bdc3099294769bee29841b1057cfb27fb06394799' ) export const INVALID_STATUS_TRANSACTION: TransactionData = new TransactionData(