diff --git a/contracts/interfaces/IToposCore.sol b/contracts/interfaces/IToposCore.sol index f216fa0..f6bd48d 100644 --- a/contracts/interfaces/IToposCore.sol +++ b/contracts/interfaces/IToposCore.sol @@ -34,13 +34,13 @@ interface IToposCore { function emitCrossSubnetMessage(SubnetId targetSubnetId) external; + function initialize(address[] memory adminAddresses, uint256 newAdminThreshold) external; + function pushCertificate(bytes calldata certBytes, uint256 position) external; function setNetworkSubnetId(SubnetId _networkSubnetId) external; - function setup(bytes calldata params) external; - - function upgrade(address newImplementation, bytes32 newImplementationCodeHash, bytes calldata setupParams) external; + function upgrade(address newImplementation, bytes32 newImplementationCodeHash) external; function adminEpoch() external view returns (uint256); diff --git a/contracts/topos-core/ToposCore.sol b/contracts/topos-core/ToposCore.sol index 075d7ff..83136dd 100644 --- a/contracts/topos-core/ToposCore.sol +++ b/contracts/topos-core/ToposCore.sol @@ -4,9 +4,11 @@ pragma solidity ^0.8.9; import "./AdminMultisigBase.sol"; import "./Bytes32Sets.sol"; +import {Initializable} from "@openzeppelin/contracts/proxy/utils/Initializable.sol"; + import "./../interfaces/IToposCore.sol"; -contract ToposCore is IToposCore, AdminMultisigBase { +contract ToposCore is IToposCore, AdminMultisigBase, Initializable { using Bytes32SetsLib for Bytes32SetsLib.Set; /// @dev Storage slot with the address of the current implementation. `keccak256('eip1967.proxy.implementation') - 1` @@ -31,7 +33,10 @@ contract ToposCore is IToposCore, AdminMultisigBase { /// @notice Mapping of transactions root to the certificate ID mapping(bytes32 => CertificateId) public txRootToCertId; - constructor() {} + /// @custom:oz-upgrades-unsafe-allow constructor + constructor() { + _disableInitializers(); + } /// @notice Sets the subnet ID /// @param _networkSubnetId The subnet ID of the subnet this contract is to be deployed on @@ -43,31 +48,16 @@ contract ToposCore is IToposCore, AdminMultisigBase { /// @dev Need to pass the setup parameters to set the admins again /// @param newImplementation The address of the new implementation /// @param newImplementationCodeHash The code hash of the new implementation - /// @param setupParams The setup parameters for the new implementation - function upgrade( - address newImplementation, - bytes32 newImplementationCodeHash, - bytes calldata setupParams - ) external override onlyAdmin { + function upgrade(address newImplementation, bytes32 newImplementationCodeHash) external override onlyAdmin { if (newImplementationCodeHash != newImplementation.codehash) revert InvalidCodeHash(); _setImplementation(newImplementation); - // AUDIT: If `newImplementation.setup` performs `selfdestruct`, it will result in the loss of _this_ implementation (thereby losing the ToposCore) - // if `upgrade` is entered within the context of _this_ implementation itself. - if (setupParams.length != 0) { - // solhint-disable-next-line avoid-low-level-calls - (bool success, ) = newImplementation.delegatecall( - abi.encodeWithSelector(IToposCore.setup.selector, setupParams) - ); - - if (!success) revert SetupFailed(); - } emit Upgraded(newImplementation); } /// @notice Push the certificate on-chain /// @param certBytes The certificate in byte /// @param position The position of the certificate - function pushCertificate(bytes memory certBytes, uint256 position) external override { + function pushCertificate(bytes memory certBytes, uint256 position) external override onlyAdmin { ( CertificateId prevId, SubnetId sourceSubnetId, @@ -107,20 +97,6 @@ contract ToposCore is IToposCore, AdminMultisigBase { emit CertStored(certId, txRoot); } - /// @notice Sets the admin threshold and admin addresses - /// @dev This function can only be called by the proxy contract - /// @param params Admin threshold and admin addresses - function setup(bytes calldata params) external override { - (address[] memory adminAddresses, uint256 newAdminThreshold) = abi.decode(params, (address[], uint256)); - // Prevent setup from being called on a non-proxy (the implementation). - if (implementation() == address(0)) revert NotProxy(); - - // NOTE: Admin epoch is incremented to easily invalidate current admin-related state. - uint256 newAdminEpoch = _adminEpoch() + uint256(1); - _setAdminEpoch(newAdminEpoch); - _setAdmins(newAdminEpoch, adminAddresses, newAdminThreshold); - } - /// @notice Emits an event to signal a cross subnet message has been sent /// @param targetSubnetId The subnet ID of the target subnet function emitCrossSubnetMessage(SubnetId targetSubnetId) external { @@ -147,6 +123,17 @@ contract ToposCore is IToposCore, AdminMultisigBase { } } + /// @notice Contract initializer + /// @dev Can only be called once + /// @param adminAddresses list of admins + /// @param newAdminThreshold number of admins required to approve a call + function initialize(address[] memory adminAddresses, uint256 newAdminThreshold) public initializer { + // NOTE: Admin epoch is incremented to easily invalidate current admin-related state. + uint256 newAdminEpoch = _adminEpoch() + uint256(1); + _setAdminEpoch(newAdminEpoch); + _setAdmins(newAdminEpoch, adminAddresses, newAdminThreshold); + } + /// @notice Checks if a certificate exists on the ToposCore contract /// @param certId The Certificate ID function certificateExists(CertificateId certId) public view returns (bool) { diff --git a/contracts/topos-core/ToposCoreProxy.sol b/contracts/topos-core/ToposCoreProxy.sol index 3fc3d02..dc613a5 100644 --- a/contracts/topos-core/ToposCoreProxy.sol +++ b/contracts/topos-core/ToposCoreProxy.sol @@ -10,16 +10,11 @@ contract ToposCoreProxy is EternalStorage { bytes32(0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc); error InvalidImplementation(); - error SetupFailed(); error NativeCurrencyNotAccepted(); - constructor(address tccImplementation, bytes memory params) { + constructor(address tccImplementation) { if (tccImplementation.code.length == 0) revert InvalidImplementation(); _setAddress(KEY_IMPLEMENTATION, tccImplementation); - - // solhint-disable-next-line avoid-low-level-calls - (bool success, ) = tccImplementation.delegatecall(abi.encodeWithSelector(IToposCore.setup.selector, params)); - if (!success) revert SetupFailed(); } receive() external payable { diff --git a/scripts/deploy-topos-msg-protocol-dynamic.ts b/scripts/deploy-topos-msg-protocol-dynamic.ts index 49e2c7a..d6c6f93 100644 --- a/scripts/deploy-topos-msg-protocol-dynamic.ts +++ b/scripts/deploy-topos-msg-protocol-dynamic.ts @@ -74,23 +74,27 @@ const main = async function (...args: string[]) { console.log(`Topos Core contract deployed to ${ToposCore.address}`) // Deploy ToposCoreProxy - const toposCoreProxyParams = utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[wallet.address], 1] // TODO: Use a different admin address than ToposDeployer - ) const ToposCoreProxyFactory = new ContractFactory( toposCoreProxyJSON.abi, toposCoreProxyJSON.bytecode, wallet ) - const ToposCoreProxy = await ToposCoreProxyFactory.deploy( - ToposCore.address, - toposCoreProxyParams, - { gasLimit: 5_000_000 } - ) + const ToposCoreProxy = await ToposCoreProxyFactory.deploy(ToposCore.address, { + gasLimit: 5_000_000, + }) await ToposCoreProxy.deployed() console.log(`Topos Core Proxy contract deployed to ${ToposCoreProxy.address}`) + console.info(`Initializing Topos Core Contract`) + const sequencerWallet = new Wallet(sequencerPrivateKey, provider) + const toposCoreInterface = new Contract( + ToposCoreProxy.address, + toposCoreInterfaceJSON.abi, + sequencerWallet + ) + const adminThreshold = 1 + await initialize(toposCoreInterface, sequencerWallet, adminThreshold) + // Deploy ERC20Messaging const ERC20MessagingFactory = new ContractFactory( erc20MessagingJSON.abi, @@ -105,12 +109,7 @@ const main = async function (...args: string[]) { await ERC20Messaging.deployed() console.log(`ERC20 Messaging contract deployed to ${ERC20Messaging.address}`) - console.info(`\nSetting subnetId on ToposCore via proxy`) - const toposCoreInterface = new Contract( - ToposCoreProxy.address, - toposCoreInterfaceJSON.abi, - wallet - ) + console.info(`Setting subnetId on ToposCore via proxy`) await toposCoreInterface .setNetworkSubnetId(subnetId, { gasLimit: 4_000_000 }) .then(async (tx: ContractTransaction) => { @@ -130,7 +129,7 @@ const main = async function (...args: string[]) { process.exit(1) }) - console.info(`\nReading subnet id`) + console.info(`Reading subnet id`) const networkSubnetId = await toposCoreInterface.networkSubnetId() console.info( @@ -142,5 +141,26 @@ const sanitizeHexString = function (hexString: string) { return hexString.startsWith('0x') ? hexString : `0x${hexString}` } +async function initialize( + toposCoreInterface: Contract, + wallet: Wallet, + adminThreshold: number +) { + await toposCoreInterface + .initialize([wallet.address], adminThreshold, { gasLimit: 4_000_000 }) + .then(async (tx: ContractTransaction) => { + await tx.wait().catch((error) => { + console.error(`Error: Failed (wait) to initialize ToposCore via proxy!`) + console.error(error) + process.exit(1) + }) + }) + .catch((error: Error) => { + console.error(`Error: Failed to initialize ToposCore via proxy!`) + console.error(error) + process.exit(1) + }) +} + const args = process.argv.slice(2) main(...args) diff --git a/scripts/deploy-topos-msg-protocol.ts b/scripts/deploy-topos-msg-protocol.ts index 0c41318..7629978 100644 --- a/scripts/deploy-topos-msg-protocol.ts +++ b/scripts/deploy-topos-msg-protocol.ts @@ -73,18 +73,23 @@ const main = async function (...args: string[]) { 4_000_000 ) - const toposCoreProxyParams = utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[wallet.address], 1] // TODO: Use a different admin address than ToposDeployer - ) const toposCoreProxyAddress = await processContract( wallet, toposCoreProxyJSON, toposCoreProxySalt!, - [toposCoreAddress, toposCoreProxyParams], + [toposCoreAddress], 4_000_000 ) + const sequencerWallet = new Wallet(sequencerPrivateKey, provider) + const toposCoreInterface = new Contract( + toposCoreProxyAddress, + toposCoreInterfaceJSON.abi, + sequencerWallet + ) + const adminThreshold = 1 + await initialize(toposCoreInterface, sequencerWallet, adminThreshold) + const erc20MessagingAddresss = await processContract( wallet, erc20MessagingJSON, @@ -93,7 +98,7 @@ const main = async function (...args: string[]) { 4_000_000 ) - setSubnetId(toposCoreProxyAddress, wallet, subnetId) + setSubnetId(toposCoreInterface, subnetId) console.log(` export TOPOS_CORE_CONTRACT_ADDRESS=${toposCoreAddress} @@ -164,16 +169,9 @@ const processContract = async function ( } const setSubnetId = async function ( - toposCoreProxyAddress: string, - wallet: Wallet, + toposCoreInterface: Contract, subnetId: string ) { - const toposCoreInterface = new Contract( - toposCoreProxyAddress, - toposCoreInterfaceJSON.abi, - wallet - ) - await toposCoreInterface .setNetworkSubnetId(subnetId, { gasLimit: 4_000_000 }) .then(async (tx: ContractTransaction) => { @@ -196,5 +194,26 @@ const setSubnetId = async function ( await toposCoreInterface.networkSubnetId() } +async function initialize( + toposCoreInterface: Contract, + wallet: Wallet, + adminThreshold: number +) { + await toposCoreInterface + .initialize([wallet.address], adminThreshold, { gasLimit: 4_000_000 }) + .then(async (tx: ContractTransaction) => { + await tx.wait().catch((error) => { + console.error(`Error: Failed (wait) to initialize ToposCore via proxy!`) + console.error(error) + process.exit(1) + }) + }) + .catch((error: Error) => { + console.error(`Error: Failed to initialize ToposCore via proxy!`) + console.error(error) + process.exit(1) + }) +} + const args = process.argv.slice(2) main(...args) diff --git a/test/topos-core/ToposCore.test.ts b/test/topos-core/ToposCore.test.ts index 7e03b28..06b6230 100644 --- a/test/topos-core/ToposCore.test.ts +++ b/test/topos-core/ToposCore.test.ts @@ -18,25 +18,88 @@ describe('ToposCore', () => { cc.DUMMY_STARK_PROOF, cc.DUMMY_SIGNATURE ) - const setupParams = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[admin.address], 1] - ) + const adminAddresses = [admin.address] + const adminThreshold = 1 const ToposCore = await ethers.getContractFactory('ToposCore') const ToposCoreProxy = await ethers.getContractFactory('ToposCoreProxy') - const toposCoreImplementation = await await ToposCore.deploy() + const toposCoreImplementation = await ToposCore.deploy() const toposCoreProxy = await ToposCoreProxy.deploy( - toposCoreImplementation.address, - setupParams + toposCoreImplementation.address ) const toposCore = ToposCore.attach(toposCoreProxy.address) - const toposCoreNew = await ToposCore.deploy() + await toposCore.initialize(adminAddresses, adminThreshold) + + const altToposCoreImplementation = await ToposCore.deploy() + const altToposCoreProxy = await ToposCoreProxy.deploy( + altToposCoreImplementation.address + ) + const altToposCore = ToposCore.attach(altToposCoreProxy.address) - return { admin, defaultCert, setupParams, toposCore, toposCoreNew } + return { + altToposCore, + altToposCoreImplementation, + admin, + adminAddresses, + adminThreshold, + defaultCert, + toposCore, + toposCoreImplementation, + } } + describe('initialize', () => { + it('reverts if implementation contract has already been initialized', async () => { + const { adminAddresses, adminThreshold, toposCore } = await loadFixture( + deployToposCoreFixture + ) + await expect( + toposCore.initialize(adminAddresses, adminThreshold) + ).to.be.revertedWith('Initializable: contract is already initialized') + }) + + it('reverts if the admin threshold mismatch the length of the admin list', async () => { + const { adminAddresses, altToposCore } = await loadFixture( + deployToposCoreFixture + ) + const falseAdminThreshold = 2 // admin threshold is 2, but we supply one admin address + await expect( + altToposCore.initialize(adminAddresses, falseAdminThreshold) + ).to.be.revertedWithCustomError(altToposCore, 'InvalidAdmins') + }) + + it('reverts if the admin threshold is zero', async () => { + const { adminAddresses, altToposCore } = await loadFixture( + deployToposCoreFixture + ) + const falseAdminThreshold = 0 // admin threshold is 0, but we supply one admin address + await expect( + altToposCore.initialize(adminAddresses, falseAdminThreshold) + ).to.be.revertedWithCustomError(altToposCore, 'InvalidAdminThreshold') + }) + + it('reverts if trying to add duplicate admins', async () => { + const { admin, adminThreshold, altToposCore } = await loadFixture( + deployToposCoreFixture + ) + const adminAddresses = [admin.address, admin.address] // duplicate admins + await expect( + altToposCore.initialize(adminAddresses, adminThreshold) + ).to.to.be.revertedWithCustomError(altToposCore, 'DuplicateAdmin') + }) + + it('reverts if the admin address is zero address', async () => { + const { adminThreshold, altToposCore } = await loadFixture( + deployToposCoreFixture + ) + const adminAddresses = [ethers.constants.AddressZero] // zero address admin + await expect( + altToposCore.initialize(adminAddresses, adminThreshold) + ).to.to.be.revertedWithCustomError(altToposCore, 'InvalidAdmins') + }) + }) + describe('pushCertificate', () => { it('reverts if the certificate is already stored', async () => { const { defaultCert, toposCore } = await loadFixture( @@ -48,6 +111,16 @@ describe('ToposCore', () => { ).to.be.revertedWith('Bytes32Set: key already exists in the set.') }) + it('reverts if non-admin tries to push certificate', async () => { + const { defaultCert, toposCore } = await loadFixture( + deployToposCoreFixture + ) + const [, nonAdmin] = await ethers.getSigners() + await expect( + toposCore.connect(nonAdmin).pushCertificate(defaultCert, cc.CERT_POS_1) + ).to.be.revertedWithCustomError(toposCore, 'NotAdmin') + }) + it('gets the certificate count', async () => { const { defaultCert, toposCore } = await loadFixture( deployToposCoreFixture @@ -164,119 +237,50 @@ describe('ToposCore', () => { describe('proxy', () => { it('reverts if the ToposCore implementation contract is not present', async () => { - const { admin } = await loadFixture(deployToposCoreFixture) - const ToposCoreProxy = await ethers.getContractFactory('ToposCoreProxy') - const setupParams = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[admin.address], 1] - ) - await expect( - ToposCoreProxy.deploy(ethers.constants.AddressZero, setupParams) - ).to.be.reverted - }) - - it('reverts if the admin threshold mismatch the length of the admin list', async () => { - const { admin, toposCoreNew } = await loadFixture(deployToposCoreFixture) - const setupParams = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[admin.address], 2] // admin threshold is 2, but only one admin - ) - const ToposCoreProxy = await ethers.getContractFactory('ToposCoreProxy') - await expect(ToposCoreProxy.deploy(toposCoreNew.address, setupParams)).to - .be.reverted - }) - - it('reverts if the admin threshold is zero', async () => { - const { admin, toposCoreNew } = await loadFixture(deployToposCoreFixture) - const setupParams = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[admin.address], 0] // admin threshold is 0 - ) - const ToposCoreProxy = await ethers.getContractFactory('ToposCoreProxy') - await expect(ToposCoreProxy.deploy(toposCoreNew.address, setupParams)).to - .be.reverted - }) - - it('reverts if trying to add duplicate admins', async () => { - const { admin, toposCoreNew } = await loadFixture(deployToposCoreFixture) - const setupParams = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[admin.address, admin.address], 1] // duplicate admin - ) const ToposCoreProxy = await ethers.getContractFactory('ToposCoreProxy') - await expect(ToposCoreProxy.deploy(toposCoreNew.address, setupParams)).to - .be.reverted - }) - - it('reverts if the admin address is zero address', async () => { - const { toposCoreNew } = await loadFixture(deployToposCoreFixture) - const setupParams = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[ethers.constants.AddressZero], 1] // zero address - ) - const ToposCoreProxy = await ethers.getContractFactory('ToposCoreProxy') - await expect(ToposCoreProxy.deploy(toposCoreNew.address, setupParams)).to - .be.reverted - }) - }) - - describe('setup', () => { - it('reverts if not called by the ToposCoreProxy contract', async () => { - const { setupParams, toposCoreNew } = await loadFixture( - deployToposCoreFixture - ) - await expect( - toposCoreNew.setup(setupParams) - ).to.be.revertedWithCustomError(toposCoreNew, 'NotProxy') + await expect(ToposCoreProxy.deploy(ethers.constants.AddressZero)).to.be + .reverted }) }) describe('upgrade', () => { it('reverts if the code hash does not match', async () => { - const { admin, toposCore, toposCoreNew } = await loadFixture( + const { toposCore, altToposCore } = await loadFixture( deployToposCoreFixture ) - const setupParams = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[admin.address], 1] - ) + const emptyCodeHash = + '0x0000000000000000000000000000000000000000000000000000000000000000' await expect( - toposCore.upgrade( - toposCoreNew.address, - '0x0000000000000000000000000000000000000000000000000000000000000000', - setupParams - ) + toposCore.upgrade(altToposCore.address, emptyCodeHash) ).to.be.revertedWithCustomError(toposCore, 'InvalidCodeHash') }) it('emits an upgraded event', async () => { - const { admin, toposCore, toposCoreNew } = await loadFixture( - deployToposCoreFixture - ) + const { admin, altToposCoreImplementation, toposCore } = + await loadFixture(deployToposCoreFixture) expect(await toposCore.implementation()).to.not.equal( - toposCoreNew.address + altToposCoreImplementation.address ) const CodeHash = await ethers.getContractFactory('CodeHash') const codeHash = await CodeHash.deploy() const implementationCodeHash = await codeHash.getCodeHash( - toposCoreNew.address - ) - const setupParams = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[admin.address], 1] + altToposCoreImplementation.address ) await expect( toposCore.upgrade( - toposCoreNew.address, - implementationCodeHash, - setupParams + altToposCoreImplementation.address, + implementationCodeHash ) ) .to.emit(toposCore, 'Upgraded') - .withArgs(toposCoreNew.address) - expect(await toposCore.implementation()).to.equal(toposCoreNew.address) + .withArgs(altToposCoreImplementation.address) + expect(await toposCore.implementation()).to.equal( + altToposCoreImplementation.address + ) + const currentAdmins = await toposCore.admins(1) + expect(currentAdmins[0]).to.equal(admin.address) // check that the admin is unchanged }) }) }) diff --git a/test/topos-core/ToposMessaging.test.ts b/test/topos-core/ToposMessaging.test.ts index c8d032d..f651178 100644 --- a/test/topos-core/ToposMessaging.test.ts +++ b/test/topos-core/ToposMessaging.test.ts @@ -45,10 +45,8 @@ describe('ToposMessaging', () => { tc.DAILY_MINT_LIMIT_100, tc.INITIAL_SUPPLY_10_000_000 ) - const setupParams = ethers.utils.defaultAbiCoder.encode( - ['address[]', 'uint256'], - [[admin.address], 1] - ) + const adminAddresses = [admin.address] + const adminThreshold = 1 const ConstAddressDeployer = await ethers.getContractFactory( 'ConstAddressDeployer' @@ -73,10 +71,10 @@ describe('ToposMessaging', () => { const toposCoreImplementation = await ToposCore.deploy() const toposCoreProxy = await ToposCoreProxy.deploy( - toposCoreImplementation.address, - setupParams + toposCoreImplementation.address ) const toposCore = ToposCore.attach(toposCoreProxy.address) + await toposCore.initialize(adminAddresses, adminThreshold) const erc20Messaging = await ERC20Messaging.deploy( tokenDeployer.address, diff --git a/test/topos-core/shared/constants/transactions.ts b/test/topos-core/shared/constants/transactions.ts index 869e448..0fe989e 100644 --- a/test/topos-core/shared/constants/transactions.ts +++ b/test/topos-core/shared/constants/transactions.ts @@ -20,9 +20,9 @@ class TransactionData { } export const MINT_EXCEED_TRANSACTION: TransactionData = new TransactionData( - '0xf8f80180f8f4f8f2822080b8edf8eb078451e864ab83010e6494dc64a140aa3e981100a9beca4e685f962f0cf6c980b8845c914ec6000000000000000000000000000000000000000000000000000000000000000200000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000007d8794cc292c8d25e410f33c53fa4341ab9365df000000000000000000000000000000000000000000000000000000000000006d82f4f5a020f0caf4045fed9afea707d5715f5367ad3ea1c3c4f1b5c3a98f9a100bee3e3aa07ff71319969fdb6c500588b1a67301de9e63f011a2ed646e7d0cd619dced3f28', - '0xf8eb078451e864ab83010e6494dc64a140aa3e981100a9beca4e685f962f0cf6c980b8845c914ec6000000000000000000000000000000000000000000000000000000000000000200000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c80000000000000000000000007d8794cc292c8d25e410f33c53fa4341ab9365df000000000000000000000000000000000000000000000000000000000000006d82f4f5a020f0caf4045fed9afea707d5715f5367ad3ea1c3c4f1b5c3a98f9a100bee3e3aa07ff71319969fdb6c500588b1a67301de9e63f011a2ed646e7d0cd619dced3f28', - '0x1d8a23e1a34d5b71d5e0567dea7d426fbb82d05cdce65405e159d64c8ad2d4e8' + '0xf8f80180f8f4f8f2822080b8edf8eb08844f22ad6983010e80945fc8d32690cc91d4c39d9d3abcbd16989f87570780b8845c914ec6000000000000000000000000000000000000000000000000000000000000000200000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000080470aae1435c000e381896adce853000cc58c13000000000000000000000000000000000000000000000000000000000000006d82f4f5a0687e37d19b2f7a66e3e0d0ace96ac65fb6b94f195ace9dbd019d87a02a46f301a06df601ef6b564443efbc14d0c5662d685e6c66d0850953a2db143a4167f4e84c', + '0xf8eb08844f22ad6983010e80945fc8d32690cc91d4c39d9d3abcbd16989f87570780b8845c914ec6000000000000000000000000000000000000000000000000000000000000000200000000000000000000000070997970c51812dc3a010c7d01b50e0d17dc79c800000000000000000000000080470aae1435c000e381896adce853000cc58c13000000000000000000000000000000000000000000000000000000000000006d82f4f5a0687e37d19b2f7a66e3e0d0ace96ac65fb6b94f195ace9dbd019d87a02a46f301a06df601ef6b564443efbc14d0c5662d685e6c66d0850953a2db143a4167f4e84c', + '0x389cb8f507f0b3a0fdd25f04dcfe33e60b338e37e13aac6cc224c0bb12f322f8' ) export const UNKNOWN_TOKEN_TRANSACTION: TransactionData = new TransactionData( @@ -32,7 +32,7 @@ export const UNKNOWN_TOKEN_TRANSACTION: TransactionData = new TransactionData( ) export const ZERO_ADDRESS_TRANSACTION: TransactionData = new TransactionData( - '0xf8f80180f8f4f8f2822080b8edf8eb078451e864ab83010d6194dc64a140aa3e981100a9beca4e685f962f0cf6c980b8845c914ec6000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000007d8794cc292c8d25e410f33c53fa4341ab9365df000000000000000000000000000000000000000000000000000000000000003282f4f6a0f76828e536baeb87bda95b288e89ff916058ab3b0f3d81237308d853f19f257ca0631bc5c5ab51c696918105ed0c0aca1660adda6ac8a78267d10c43319c3ec476', - '0xf8eb078451e864ab83010d6194dc64a140aa3e981100a9beca4e685f962f0cf6c980b8845c914ec6000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000007d8794cc292c8d25e410f33c53fa4341ab9365df000000000000000000000000000000000000000000000000000000000000003282f4f6a0f76828e536baeb87bda95b288e89ff916058ab3b0f3d81237308d853f19f257ca0631bc5c5ab51c696918105ed0c0aca1660adda6ac8a78267d10c43319c3ec476', - '0x374084da2b2c7401d38bd441e8681855d9d717635ec14a77f36185763c75f1dd' + '0xf8f80180f8f4f8f2822080b8edf8eb08844f1d2bb483010d7d945fc8d32690cc91d4c39d9d3abcbd16989f87570780b8845c914ec60000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080470aae1435c000e381896adce853000cc58c13000000000000000000000000000000000000000000000000000000000000003282f4f5a08ba005948a0f9028543602166ec2316e5faaa2f118b507a0658434cd190632a2a013d153ce46c595608a626f479f41730f9b3ec3152ecefa176ac3220a7122c3b7', + '0xf8eb08844f1d2bb483010d7d945fc8d32690cc91d4c39d9d3abcbd16989f87570780b8845c914ec60000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080470aae1435c000e381896adce853000cc58c13000000000000000000000000000000000000000000000000000000000000003282f4f5a08ba005948a0f9028543602166ec2316e5faaa2f118b507a0658434cd190632a2a013d153ce46c595608a626f479f41730f9b3ec3152ecefa176ac3220a7122c3b7', + '0xf0e029e097fc35ca535c5da1e2e399bad4a8b841eb4052dd891cc5adb932116c' )