Skip to content

Commit

Permalink
Merge branch 'goulding/krak/aptops-v2-examples' of https://github.com…
Browse files Browse the repository at this point in the history
…/LayerZero-Labs/devtools into goulding/krak/aptops-v2-examples
  • Loading branch information
AlexanderLiteplo committed Dec 16, 2024
2 parents 6860966 + 3e5e1b9 commit c9fe525
Show file tree
Hide file tree
Showing 19 changed files with 522 additions and 256 deletions.
2 changes: 2 additions & 0 deletions examples/oft-aptos/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@ pnpm-error.log
# Editor and OS files
.DS_Store
.idea

.aptos
14 changes: 7 additions & 7 deletions examples/oft-aptos/evmOAppConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,21 @@ const bscOAppConfig: OAppEdgeConfig = {
sendConfig: {
executorConfig: {
maxMessageSize: 65536,
executor: '',
executor: '0x3ebD570ed38B1b3b4BC886999fcF507e9D584859',
},
ulnConfig: {
confirmations: BigInt(5),
requiredDVNs: [''],
optionalDVNs: [''],
optionalDVNThreshold: 0,
requiredDVNs: ['0x0eE552262f7B562eFcED6DD4A7e2878AB897d405', '0x6f99eA3Fc9206E2779249E15512D7248dAb0B52e'],
optionalDVNs: ['0x2dDf08e397541721acD82E5b8a1D0775454a180B', '0x6F978ee5bfd7b1A8085A3eA9e54eB76e668E195a'],
optionalDVNThreshold: 1,
},
},
receiveConfig: {
ulnConfig: {
confirmations: BigInt(5),
requiredDVNs: [''],
optionalDVNs: [''],
optionalDVNThreshold: 0,
requiredDVNs: ['0x0eE552262f7B562eFcED6DD4A7e2878AB897d405', '0x6f99eA3Fc9206E2779249E15512D7248dAb0B52e'],
optionalDVNs: ['0x2dDf08e397541721acD82E5b8a1D0775454a180B', '0x6F978ee5bfd7b1A8085A3eA9e54eB76e668E195a'],
optionalDVNThreshold: 1,
},
},
}
Expand Down
5 changes: 5 additions & 0 deletions examples/oft-aptos/hardhat.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,11 @@ const config: HardhatUserConfig = {
url: process.env.RPC_URL_ETHEREUM || 'https://rpc.ankr.com/eth_sepolia',
accounts,
},
'aptos-testnet': {
eid: EndpointId.APTOS_V2_TESTNET,
url: process.env.RPC_URL_APTOS_TESTNET || 'http://127.0.0.1:8080',
accounts,
},
hardhat: {
// Need this for testing because TestHelperOz5.sol is exceeding the compiled contract size limit
allowUnlimitedContractSize: true,
Expand Down
3 changes: 2 additions & 1 deletion examples/oft-aptos/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
"test": "$npm_execpath run test:forge && $npm_execpath run test:hardhat && $npm_execpath run test:aptos",
"test:aptos": "aptos move test --dev --skip-fetch-latest-git-deps",
"test:forge": "forge test",
"test:hardhat": "hardhat test"
"test:hardhat": "hardhat test",
"wire:evm": "npx hardhat run tasks/evm/wire-evm.ts"
},
"resolutions": {
"ethers": "^5.7.2",
Expand Down
108 changes: 108 additions & 0 deletions examples/oft-aptos/tasks/evm/utils/libraryConfigUtils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { Contract, PopulatedTransaction, utils } from 'ethers'

import { Uln302ExecutorConfig, Uln302UlnUserConfig } from '@layerzerolabs/toolbox-hardhat'

import { returnChecksum, returnChecksums } from '../utils/types'

import type { SetConfigParam, address, eid } from '../utils/types'

export async function getConfig(
epv2Contract: Contract,
evmAddress: address,
libraryAddress: address,
aptosEid: eid,
configType: number
): Promise<string> {
const config = await epv2Contract.getConfig(evmAddress, libraryAddress, aptosEid, configType)
// const toDecode: SetConfigParam = {
// eid: aptosEid,
// configType: configType,
// config: config,
// }
// decodeConfig([toDecode])
return config
}

export function setConfig(
epv2Contract: Contract,
evmAddress: address,
libraryAddress: address,
config: SetConfigParam[]
): Promise<PopulatedTransaction> {
return epv2Contract.populateTransaction.setConfig(evmAddress, libraryAddress, config)
}

export function buildConfig(
ulnConfig: Uln302UlnUserConfig,
executorConfig: Uln302ExecutorConfig | null = null
): { executorConfigBytes: string; ulnConfigBytes: string } {
if (!ulnConfig.optionalDVNs) {
ulnConfig.optionalDVNs = []
}
const _optionalDVNs = returnChecksums(ulnConfig.optionalDVNs)
const _requiredDVNs = returnChecksums(ulnConfig.requiredDVNs)

const ulnConfigBytes = utils.defaultAbiCoder.encode(
[
'tuple(uint64 confirmations, uint8 requiredDVNCount, uint8 optionalDVNCount, uint8 optionalDVNThreshold, address[] requiredDVNs, address[] optionalDVNs)',
],
[
{
confirmations: ulnConfig.confirmations,
requiredDVNCount: _requiredDVNs.length,
optionalDVNCount: _optionalDVNs.length,
optionalDVNThreshold: ulnConfig.optionalDVNThreshold,
requiredDVNs: _requiredDVNs.sort(),
optionalDVNs: _optionalDVNs.sort(),
},
]
)

if (executorConfig !== null) {
const _executor = returnChecksum(executorConfig.executor)
const executorConfigBytes = utils.defaultAbiCoder.encode(
['uint32', 'address'],
[executorConfig.maxMessageSize, _executor]
)

return { executorConfigBytes, ulnConfigBytes }
}
return { executorConfigBytes: '0x', ulnConfigBytes }
}

export function decodeConfig(configParam: SetConfigParam[]) {
const decodedConfig: {
executorConfig: Uln302ExecutorConfig
ulnConfig: Uln302UlnUserConfig
// eslint-disable-next-line @typescript-eslint/no-explicit-any
} = {} as any
try {
for (const { configType, config } of configParam) {
if (configType === 1) {
const decoded = utils.defaultAbiCoder.decode(['uint32', 'address'], config)
decodedConfig.executorConfig = {
maxMessageSize: decoded[0],
executor: decoded[1],
}
} else if (configType === 2) {
const decoded = utils.defaultAbiCoder.decode(
[
'tuple(uint64 confirmations, uint8 requiredDVNCount, uint8 optionalDVNCount, uint8 optionalDVNThreshold, address[] requiredDVNs, address[] optionalDVNs)',
],
config
)
decodedConfig.ulnConfig = {
confirmations: decoded[0]['confirmations'],
requiredDVNs: decoded[0]['requiredDVNs'],
optionalDVNs: decoded[0]['optionalDVNs'],
optionalDVNThreshold: decoded[0]['optionalDVNThreshold'],
}
}
}
} catch (e) {
console.log(decodeConfig)
return
}

return decodedConfig
}
33 changes: 28 additions & 5 deletions examples/oft-aptos/tasks/evm/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ChildProcess } from 'child_process'

import { PopulatedTransaction, ethers, providers } from 'ethers'
import { PopulatedTransaction, ethers } from 'ethers'

import type { OAppEdgeConfig, OAppNodeConfig } from '@layerzerolabs/toolbox-hardhat'

Expand All @@ -14,8 +14,8 @@ export type TxTypes =
| 'sendConfig'
| 'receiveConfig'

export type eid = string
export type EidTxMap = Record<eid, [PopulatedTransaction]>
export type eid = number
export type address = string

export type NonEvmOAppMetadata = {
Expand All @@ -35,14 +35,14 @@ export type ContractMetadata = {
}
provider: ethers.providers.JsonRpcProvider
configAccount: OAppNodeConfig
configOapp: OAppEdgeConfig
configOapp: OAppEdgeConfig | undefined
}

export type AccountData = {
[eid: number]: {
[eid: string]: {
gasPrice: ethers.BigNumber
nonce: number
signer: providers.JsonRpcSigner
signer: ethers.Wallet
}
}
//[TxTypes][eid] = PopulatedTransaction
Expand Down Expand Up @@ -72,4 +72,27 @@ export type SetConfigParam = {
configType: number
config: string
}

export const ZEROADDRESS_EVM = '0x0000000000000000000000000000000000000000'

export type AnvilNode = { process: ChildProcess; rpcUrl: string }

export function returnChecksums(addresses: string[]): string[] {
const checksumAddresses: string[] = []
for (const address of addresses) {
try {
checksumAddresses.push(returnChecksum(address))
} catch (error) {
console.error(`Invalid address: ${address}. Error: ${error}`)
}
}
return checksumAddresses
}

export function returnChecksum(address: string): string {
try {
return ethers.utils.getAddress(address)
} catch (error) {
throw new Error(`Invalid address: ${address}. Error: ${error}`)
}
}
37 changes: 19 additions & 18 deletions examples/oft-aptos/tasks/evm/wire-evm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,27 @@ import { Contract, ethers } from 'ethers'

import { getDeploymentAddressAndAbi } from '@layerzerolabs/lz-evm-sdk-v2'

// eslint-disable-next-line @typescript-eslint/no-unused-vars
// import { createSetSendConfigTransactions } from './wire/setSendConfig'

import { getEidFromAptosNetwork, getLzNetworkStage, parseYaml } from '../move/utils/aptosNetworkParser'
import { getMoveVMOftAddress } from '../move/utils/utils'
import { createEidToNetworkMapping, getConfigConnections, getHHAccountConfig } from '../shared/utils'

import AnvilForkNode from './utils/anvilForkNode'
import { ContractMetadataMapping, NonEvmOAppMetadata, TxEidMapping, eid } from './utils/types'
import { createSetDelegateTransactions } from './wire/setDelegate'
import { createSetEnforcedOptionsTransactions } from './wire/setEnforcedOptions'
import { createSetPeerTransactions } from './wire/setPeer'
import { createSetReceiveConfigTransactions } from './wire/setReceiveConfig'
import { createSetReceiveLibraryTransactions } from './wire/setReceiveLibrary'
import { createSetSendConfigTransactions } from './wire/setSendConfig'
import { createSetSendLibraryTransactions } from './wire/setSendLibrary'
import { executeTransactions } from './wire/transactionExecutor'

import type { ContractMetadataMapping, NonEvmOAppMetadata, TxEidMapping } from './utils/types'

if (!process.env.PRIVATE_KEY) {
console.error('PRIVATE_KEY environment variable is not set.')
process.exit(1)
}
const privateKey = process.env.PRIVATE_KEY

/**
* @description Handles wiring of EVM contracts with the Aptos OApp
Expand All @@ -37,7 +38,7 @@ async function main() {
const connectionsToWire = getConfigConnections('to', EID_APTOS)

const accountConfigs = getHHAccountConfig()
const networks = createEidToNetworkMapping()
const networks = createEidToNetworkMapping('networkName')
const rpcUrls = createEidToNetworkMapping('url')

// Build a Transaction mapping for each type of transaction. It is further indexed by the eid.
Expand All @@ -61,7 +62,7 @@ async function main() {

const nonEvmOapp: NonEvmOAppMetadata = {
address: APTOS_OAPP_ADDRESS,
eid: EID_APTOS,
eid: EID_APTOS.toString(),
rpc: rpcUrls[EID_APTOS],
}

Expand All @@ -70,11 +71,12 @@ async function main() {
* contractMetaData contains ethers Contract objects for the OApp and EndpointV2 contracts.
*/
for (const conn of connectionsToWire) {
const fromEid = conn.from.eid as eid
const fromEid = conn.from.eid
const fromNetwork = networks[fromEid]
const configOapp = conn?.config

const provider = new ethers.providers.JsonRpcProvider(rpcUrls[fromEid])
const signer = new ethers.Wallet(process.env.PRIVATE_KEY as string, provider)
const signer = new ethers.Wallet(privateKey, provider)

const OAppDeploymentPath = `deployments/${fromNetwork}/${conn.from.contractName}.json`
const OAppDeploymentData = JSON.parse(fs.readFileSync(OAppDeploymentPath, 'utf8'))
Expand All @@ -97,7 +99,7 @@ async function main() {
},
provider: provider,
configAccount: accountConfigs[fromEid],
configOapp: conn.config ?? {},
configOapp: configOapp,
}
}

Expand All @@ -108,29 +110,28 @@ async function main() {
TxTypeEidMapping.setEnforcedOptions = await createSetEnforcedOptionsTransactions(contractMetaData, nonEvmOapp)
TxTypeEidMapping.setSendLibrary = await createSetSendLibraryTransactions(contractMetaData, nonEvmOapp)
TxTypeEidMapping.setReceiveLibrary = await createSetReceiveLibraryTransactions(contractMetaData, nonEvmOapp)
// TxTypeEidMapping.sendConfig = await createSetSendConfigTransactions(contractMetaData, nonEvmOapp)
TxTypeEidMapping.sendConfig = await createSetSendConfigTransactions(contractMetaData, nonEvmOapp)
TxTypeEidMapping.receiveConfig = await createSetReceiveConfigTransactions(contractMetaData, nonEvmOapp)

// TxTypeEidMapping.setReceiveLibraryTimeout = await createSetReceiveLibraryTimeoutTransactions(
// contractMetaData,
// nonEvmOapp
// )

// @todo Clean this up or move to utils
const rpcUrlSelfMap: { [eid: eid]: string } = {}
for (const [eid, eidData] of Object.entries(contractMetaData) as Array<
[string, (typeof contractMetaData)[keyof typeof contractMetaData]]
>) {
rpcUrlSelfMap[Number(eid)] = eidData.provider.connection.url
const rpcUrlSelfMap: { [eid: string]: string } = {}
for (const [eid, eidData] of Object.entries(contractMetaData)) {
rpcUrlSelfMap[eid] = eidData.provider.connection.url
}

const anvilForkNode = new AnvilForkNode(rpcUrlSelfMap, 8546)

try {
const forkRpcMap = await anvilForkNode.startNodes()
await executeTransactions(contractMetaData, TxTypeEidMapping, forkRpcMap)
await executeTransactions(contractMetaData, TxTypeEidMapping, forkRpcMap, 'dry-run')
console.log('\nAll transactions have been SIMULATED on the blockchains.')
// await executeTransactions(contractMetaData, TxTypeEidMapping, rpcUrlSelfMap)
// console.log('\nAll transactions have been EXECUTED on the blockchains.')
await executeTransactions(contractMetaData, TxTypeEidMapping, rpcUrlSelfMap, 'broadcast')
console.log('\nAll transactions have been EXECUTED on the blockchains.')
} catch (error) {
anvilForkNode.killNodes()
throw error
Expand Down
Loading

0 comments on commit c9fe525

Please sign in to comment.