Commit 280f348c authored by Maurelian's avatar Maurelian Committed by Kelvin Fichter

feat(contracts): Store canonical address names in ts object

This commit adds an addressNames object, which should be used both for
names in the address manager, and naming deployment artifacts.

fix(contracts): Remove unused queue container test code

feat(contracts): Split up managed and unmanaged names

refactor(contracts): Move address names into a single nested object

refactor(contracts): Make address keys similar to values

chore: add changeset

docs(contracts): Add a docstring to deployAndPostDeploy

refactor(contracts): Remove unnecessary contract name

If the Address Manager's name is the same as the contract artifact
we don't need specify the contract name argument.
parent 64ea3ac9
---
'@eth-optimism/contracts': patch
---
Adds an exported `names` object with contract and account names
...@@ -7,6 +7,7 @@ import { ...@@ -7,6 +7,7 @@ import {
sendImpersonatedTx, sendImpersonatedTx,
BIG_BALANCE, BIG_BALANCE,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
import { awaitCondition } from '@eth-optimism/core-utils' import { awaitCondition } from '@eth-optimism/core-utils'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
...@@ -24,7 +25,7 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -24,7 +25,7 @@ const deployFn: DeployFunction = async (hre) => {
// Get a reference to the AddressManager contract. // Get a reference to the AddressManager contract.
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
// Transfer ownership of the AddressManager to the deployer. // Transfer ownership of the AddressManager to the deployer.
......
/* Imports: Internal */
import { names } from '../src'
/* Imports: External */ /* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types' import { DeployFunction } from 'hardhat-deploy/dist/types'
...@@ -5,7 +8,7 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -5,7 +8,7 @@ const deployFn: DeployFunction = async (hre) => {
const { deploy } = hre.deployments const { deploy } = hre.deployments
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
await deploy('Lib_AddressManager', { await deploy(names.unmanaged.Lib_AddressManager, {
from: deployer, from: deployer,
args: [], args: [],
log: true, log: true,
......
...@@ -6,16 +6,17 @@ import { ...@@ -6,16 +6,17 @@ import {
deployAndVerifyAndThen, deployAndVerifyAndThen,
getContractFromArtifact, getContractFromArtifact,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
await deployAndVerifyAndThen({ await deployAndVerifyAndThen({
hre, hre,
name: 'ChainStorageContainer-CTC-batches', name: names.managed.contracts.ChainStorageContainer_CTC_batches,
contract: 'ChainStorageContainer', contract: 'ChainStorageContainer',
args: [Lib_AddressManager.address, 'CanonicalTransactionChain'], args: [Lib_AddressManager.address, 'CanonicalTransactionChain'],
}) })
......
...@@ -6,16 +6,17 @@ import { ...@@ -6,16 +6,17 @@ import {
deployAndVerifyAndThen, deployAndVerifyAndThen,
getContractFromArtifact, getContractFromArtifact,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
await deployAndVerifyAndThen({ await deployAndVerifyAndThen({
hre, hre,
name: 'ChainStorageContainer-SCC-batches', name: names.managed.contracts.ChainStorageContainer_SCC_batches,
contract: 'ChainStorageContainer', contract: 'ChainStorageContainer',
args: [Lib_AddressManager.address, 'StateCommitmentChain'], args: [Lib_AddressManager.address, 'StateCommitmentChain'],
}) })
......
...@@ -6,16 +6,17 @@ import { ...@@ -6,16 +6,17 @@ import {
deployAndVerifyAndThen, deployAndVerifyAndThen,
getContractFromArtifact, getContractFromArtifact,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
await deployAndVerifyAndThen({ await deployAndVerifyAndThen({
hre, hre,
name: 'CanonicalTransactionChain', name: names.managed.contracts.CanonicalTransactionChain,
args: [ args: [
Lib_AddressManager.address, Lib_AddressManager.address,
(hre as any).deployConfig.ctcMaxTransactionGasLimit, (hre as any).deployConfig.ctcMaxTransactionGasLimit,
......
...@@ -6,16 +6,17 @@ import { ...@@ -6,16 +6,17 @@ import {
deployAndVerifyAndThen, deployAndVerifyAndThen,
getContractFromArtifact, getContractFromArtifact,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
await deployAndVerifyAndThen({ await deployAndVerifyAndThen({
hre, hre,
name: 'StateCommitmentChain', name: names.managed.contracts.StateCommitmentChain,
args: [ args: [
Lib_AddressManager.address, Lib_AddressManager.address,
(hre as any).deployConfig.sccFraudProofWindow, (hre as any).deployConfig.sccFraudProofWindow,
......
...@@ -6,16 +6,17 @@ import { ...@@ -6,16 +6,17 @@ import {
deployAndVerifyAndThen, deployAndVerifyAndThen,
getContractFromArtifact, getContractFromArtifact,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
await deployAndVerifyAndThen({ await deployAndVerifyAndThen({
hre, hre,
name: 'BondManager', name: names.managed.contracts.BondManager,
args: [Lib_AddressManager.address], args: [Lib_AddressManager.address],
}) })
} }
......
...@@ -7,16 +7,17 @@ import { ...@@ -7,16 +7,17 @@ import {
deployAndVerifyAndThen, deployAndVerifyAndThen,
getContractFromArtifact, getContractFromArtifact,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
await deployAndVerifyAndThen({ await deployAndVerifyAndThen({
hre, hre,
name: 'OVM_L1CrossDomainMessenger', name: names.managed.contracts.OVM_L1CrossDomainMessenger,
contract: 'L1CrossDomainMessenger', contract: 'L1CrossDomainMessenger',
args: [], args: [],
postDeployAction: async (contract) => { postDeployAction: async (contract) => {
......
...@@ -6,11 +6,12 @@ import { ...@@ -6,11 +6,12 @@ import {
deployAndVerifyAndThen, deployAndVerifyAndThen,
getContractFromArtifact, getContractFromArtifact,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
await deployAndVerifyAndThen({ await deployAndVerifyAndThen({
......
...@@ -3,13 +3,14 @@ import { DeployFunction } from 'hardhat-deploy/dist/types' ...@@ -3,13 +3,14 @@ import { DeployFunction } from 'hardhat-deploy/dist/types'
/* Imports: Internal */ /* Imports: Internal */
import { deployAndVerifyAndThen } from '../src/hardhat-deploy-ethers' import { deployAndVerifyAndThen } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
await deployAndVerifyAndThen({ await deployAndVerifyAndThen({
hre, hre,
name: 'Proxy__OVM_L1StandardBridge', name: names.managed.contracts.Proxy__OVM_L1StandardBridge,
contract: 'L1ChugSplashProxy', contract: 'L1ChugSplashProxy',
iface: 'L1StandardBridge', iface: 'L1StandardBridge',
args: [deployer], args: [deployer],
......
...@@ -7,30 +7,20 @@ import { ...@@ -7,30 +7,20 @@ import {
deployAndVerifyAndThen, deployAndVerifyAndThen,
getContractFromArtifact, getContractFromArtifact,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
import { predeploys } from '../src/predeploys' import { predeploys } from '../src/predeploys'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
const allContractNames = [
'ChainStorageContainer-CTC-batches',
'ChainStorageContainer-SCC-batches',
'CanonicalTransactionChain',
'StateCommitmentChain',
'BondManager',
'OVM_L1CrossDomainMessenger',
'Proxy__OVM_L1CrossDomainMessenger',
'Proxy__OVM_L1StandardBridge',
]
let namesAndAddresses: { let namesAndAddresses: {
name: string name: string
address: string address: string
}[] = await Promise.all( }[] = await Promise.all(
allContractNames.map(async (name) => { Object.values(names.managed.contracts).map(async (name) => {
return { return {
name, name,
address: (await getContractFromArtifact(hre, name)).address, address: (await getContractFromArtifact(hre, name)).address,
...@@ -51,13 +41,13 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -51,13 +41,13 @@ const deployFn: DeployFunction = async (hre) => {
// OVM_Sequencer is the address allowed to submit "Sequencer" blocks to the // OVM_Sequencer is the address allowed to submit "Sequencer" blocks to the
// CanonicalTransactionChain. // CanonicalTransactionChain.
{ {
name: 'OVM_Sequencer', name: names.managed.accounts.OVM_Sequencer,
address: (hre as any).deployConfig.ovmSequencerAddress, address: (hre as any).deployConfig.ovmSequencerAddress,
}, },
// OVM_Proposer is the address allowed to submit state roots (transaction results) to the // OVM_Proposer is the address allowed to submit state roots (transaction results) to the
// StateCommitmentChain. // StateCommitmentChain.
{ {
name: 'OVM_Proposer', name: names.managed.accounts.OVM_Proposer,
address: (hre as any).deployConfig.ovmProposerAddress, address: (hre as any).deployConfig.ovmProposerAddress,
}, },
] ]
...@@ -76,8 +66,7 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -76,8 +66,7 @@ const deployFn: DeployFunction = async (hre) => {
await deployAndVerifyAndThen({ await deployAndVerifyAndThen({
hre, hre,
name: 'AddressDictator', name: names.unmanaged.AddressDictator,
contract: 'AddressDictator',
args: [ args: [
Lib_AddressManager.address, Lib_AddressManager.address,
(hre as any).deployConfig.ovmAddressManagerOwner, (hre as any).deployConfig.ovmAddressManagerOwner,
......
...@@ -6,7 +6,9 @@ import { DeployFunction } from 'hardhat-deploy/dist/types' ...@@ -6,7 +6,9 @@ import { DeployFunction } from 'hardhat-deploy/dist/types'
import { import {
getContractFromArtifact, getContractFromArtifact,
isHardhatNode, isHardhatNode,
getContractFromArtifact,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
...@@ -21,14 +23,14 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -21,14 +23,14 @@ const deployFn: DeployFunction = async (hre) => {
// First get relevant contract references. // First get relevant contract references.
const AddressDictator = await getContractFromArtifact( const AddressDictator = await getContractFromArtifact(
hre, hre,
'AddressDictator', names.unmanaged.AddressDictator,
{ {
signerOrProvider: deployer, signerOrProvider: deployer,
} }
) )
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
const namedAddresses: Array<{ name: string; addr: string }> = const namedAddresses: Array<{ name: string; addr: string }> =
await AddressDictator.getNamedAddresses() await AddressDictator.getNamedAddresses()
......
...@@ -4,6 +4,7 @@ import { hexStringEquals, awaitCondition } from '@eth-optimism/core-utils' ...@@ -4,6 +4,7 @@ import { hexStringEquals, awaitCondition } from '@eth-optimism/core-utils'
/* Imports: Internal */ /* Imports: Internal */
import { getContractFromArtifact } from '../src/hardhat-deploy-ethers' import { getContractFromArtifact } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
...@@ -16,7 +17,7 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -16,7 +17,7 @@ const deployFn: DeployFunction = async (hre) => {
// recover from so let's just ignore it for now. // recover from so let's just ignore it for now.
const Proxy__OVM_L1CrossDomainMessenger = await getContractFromArtifact( const Proxy__OVM_L1CrossDomainMessenger = await getContractFromArtifact(
hre, hre,
'Proxy__OVM_L1CrossDomainMessenger', names.managed.contracts.Proxy__OVM_L1CrossDomainMessenger,
{ {
iface: 'L1CrossDomainMessenger', iface: 'L1CrossDomainMessenger',
signerOrProvider: deployer, signerOrProvider: deployer,
...@@ -25,7 +26,7 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -25,7 +26,7 @@ const deployFn: DeployFunction = async (hre) => {
const Lib_AddressManager = await getContractFromArtifact( const Lib_AddressManager = await getContractFromArtifact(
hre, hre,
'Lib_AddressManager' names.unmanaged.Lib_AddressManager
) )
await Proxy__OVM_L1CrossDomainMessenger.initialize(Lib_AddressManager.address) await Proxy__OVM_L1CrossDomainMessenger.initialize(Lib_AddressManager.address)
......
...@@ -9,6 +9,7 @@ import { ...@@ -9,6 +9,7 @@ import {
getContractFromArtifact, getContractFromArtifact,
deployAndVerifyAndThen, deployAndVerifyAndThen,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const Proxy__OVM_L1StandardBridge = await getContractFromArtifact( const Proxy__OVM_L1StandardBridge = await getContractFromArtifact(
...@@ -22,13 +23,12 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -22,13 +23,12 @@ const deployFn: DeployFunction = async (hre) => {
const Proxy__OVM_L1CrossDomainMessenger = await getContractFromArtifact( const Proxy__OVM_L1CrossDomainMessenger = await getContractFromArtifact(
hre, hre,
'Proxy__OVM_L1CrossDomainMessenger' names.managed.contracts.Proxy__OVM_L1CrossDomainMessenger
) )
await deployAndVerifyAndThen({ await deployAndVerifyAndThen({
hre, hre,
name: 'ChugSplashDictator', name: names.unmanaged.ChugSplashDictator,
contract: 'ChugSplashDictator',
args: [ args: [
Proxy__OVM_L1StandardBridge.address, Proxy__OVM_L1StandardBridge.address,
(hre as any).deployConfig.ovmAddressManagerOwner, (hre as any).deployConfig.ovmAddressManagerOwner,
......
...@@ -10,13 +10,14 @@ import { ...@@ -10,13 +10,14 @@ import {
deployAndVerifyAndThen, deployAndVerifyAndThen,
isHardhatNode, isHardhatNode,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
const deployFn: DeployFunction = async (hre) => { const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts() const { deployer } = await hre.getNamedAccounts()
const ChugSplashDictator = await getContractFromArtifact( const ChugSplashDictator = await getContractFromArtifact(
hre, hre,
'ChugSplashDictator', names.unmanaged.ChugSplashDictator,
{ {
signerOrProvider: deployer, signerOrProvider: deployer,
} }
...@@ -24,7 +25,7 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -24,7 +25,7 @@ const deployFn: DeployFunction = async (hre) => {
const Proxy__OVM_L1StandardBridge = await getContractFromArtifact( const Proxy__OVM_L1StandardBridge = await getContractFromArtifact(
hre, hre,
'Proxy__OVM_L1StandardBridge', names.managed.contracts.Proxy__OVM_L1StandardBridge,
{ {
iface: 'L1ChugSplashProxy', iface: 'L1ChugSplashProxy',
signerOrProvider: deployer, signerOrProvider: deployer,
......
...@@ -9,6 +9,7 @@ import { ...@@ -9,6 +9,7 @@ import {
getContractFromArtifact, getContractFromArtifact,
isHardhatNode, isHardhatNode,
} from '../src/hardhat-deploy-ethers' } from '../src/hardhat-deploy-ethers'
import { names } from '../src'
// This is a TEMPORARY way to fund the default hardhat accounts on L2. The better way to do this is // This is a TEMPORARY way to fund the default hardhat accounts on L2. The better way to do this is
// to make a modification to hardhat-ovm. However, I don't have the time right now to figure the // to make a modification to hardhat-ovm. However, I don't have the time right now to figure the
...@@ -18,7 +19,7 @@ const deployFn: DeployFunction = async (hre) => { ...@@ -18,7 +19,7 @@ const deployFn: DeployFunction = async (hre) => {
if (await isHardhatNode(hre)) { if (await isHardhatNode(hre)) {
const L1StandardBridge = await getContractFromArtifact( const L1StandardBridge = await getContractFromArtifact(
hre, hre,
'Proxy__OVM_L1StandardBridge', names.managed.contracts.Proxy__OVM_L1StandardBridge,
{ {
iface: 'L1StandardBridge', iface: 'L1StandardBridge',
} }
......
/**
* This object defines the correct names to be used in the Address Manager and deployment artifacts.
*/
export const names = {
managed: {
contracts: {
ChainStorageContainer_CTC_batches: 'ChainStorageContainer-CTC-batches',
ChainStorageContainer_SCC_batches: 'ChainStorageContainer-SCC-batches',
CanonicalTransactionChain: 'CanonicalTransactionChain',
StateCommitmentChain: 'StateCommitmentChain',
BondManager: 'BondManager',
OVM_L1CrossDomainMessenger: 'OVM_L1CrossDomainMessenger',
Proxy__OVM_L1CrossDomainMessenger: 'Proxy__OVM_L1CrossDomainMessenger',
Proxy__OVM_L1StandardBridge: 'Proxy__OVM_L1StandardBridge',
},
accounts: { OVM_Sequencer: 'OVM_Sequencer', OVM_Proposer: 'OVM_Proposer' },
},
unmanaged: {
AddressDictator: 'AddressDictator',
ChugSplashDictator: 'ChugSplashDictator',
Lib_AddressManager: 'Lib_AddressManager',
},
}
...@@ -5,6 +5,15 @@ import { Signer } from '@ethersproject/abstract-signer' ...@@ -5,6 +5,15 @@ import { Signer } from '@ethersproject/abstract-signer'
import { sleep, awaitCondition } from '@eth-optimism/core-utils' import { sleep, awaitCondition } from '@eth-optimism/core-utils'
import { HttpNetworkConfig } from 'hardhat/types' import { HttpNetworkConfig } from 'hardhat/types'
/**
* @param {Any} hre Hardhat runtime environment
* @param {String} name Contract name from the names object
* @param {Any[]} args Constructor arguments
* @param {String} contract Name of the solidity contract
* @param {String} iface Alternative interface for calling the contract
* @param {Function} postDeployAction Called after deployment
*/
export const deployAndVerifyAndThen = async ({ export const deployAndVerifyAndThen = async ({
hre, hre,
name, name,
......
export * from './contract-defs' export * from './contract-defs'
export * from './predeploys' export * from './predeploys'
export * from './connect-contracts' export * from './connect-contracts'
export * from './address-names'
...@@ -23,6 +23,7 @@ import { ...@@ -23,6 +23,7 @@ import {
getEthTime, getEthTime,
getNextBlockNumber, getNextBlockNumber,
} from '../../../helpers' } from '../../../helpers'
import { names } from '../../../../src'
const ELEMENT_TEST_SIZES = [1, 2, 4, 8, 16] const ELEMENT_TEST_SIZES = [1, 2, 4, 8, 16]
const MAX_GAS_LIMIT = 8_000_000 const MAX_GAS_LIMIT = 8_000_000
...@@ -113,10 +114,6 @@ describe('CanonicalTransactionChain', () => { ...@@ -113,10 +114,6 @@ describe('CanonicalTransactionChain', () => {
AddressManager.address, AddressManager.address,
'CanonicalTransactionChain' 'CanonicalTransactionChain'
) )
await Factory__ChainStorageContainer.deploy(
AddressManager.address,
'CanonicalTransactionChain'
)
await AddressManager.setAddress( await AddressManager.setAddress(
'ChainStorageContainer-CTC-batches', 'ChainStorageContainer-CTC-batches',
...@@ -124,7 +121,7 @@ describe('CanonicalTransactionChain', () => { ...@@ -124,7 +121,7 @@ describe('CanonicalTransactionChain', () => {
) )
await AddressManager.setAddress( await AddressManager.setAddress(
'CanonicalTransactionChain', names.managed.contracts.CanonicalTransactionChain,
CanonicalTransactionChain.address CanonicalTransactionChain.address
) )
}) })
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment