Deploy LL + CircleBridgeAdapter to mainnet (#2166)

### Description

Deploy LL + CircleBridgeAdapter to mainnet with the relevant changes and
artifacts
pull/2190/head
Nam Chu Hoai 2 years ago committed by GitHub
parent 95d8fdd330
commit 85a1bf0fba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      typescript/infra/config/environments/mainnet2/index.ts
  2. 49
      typescript/infra/config/environments/mainnet2/liquidityLayer.ts
  3. 12
      typescript/infra/config/environments/mainnet2/middleware/liquidity-layer/addresses.json
  4. 42
      typescript/infra/config/environments/mainnet2/middleware/liquidity-layer/verification.json
  5. 63
      typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerApp.ts

@ -13,6 +13,7 @@ import { storageGasOracleConfig } from './gas-oracle';
import { helloWorld } from './helloworld'; import { helloWorld } from './helloworld';
import { igp } from './igp'; import { igp } from './igp';
import { infrastructure } from './infrastructure'; import { infrastructure } from './infrastructure';
import { bridgeAdapterConfigs, relayerConfig } from './liquidityLayer';
import { owners } from './owners'; import { owners } from './owners';
export const environment: EnvironmentConfig = { export const environment: EnvironmentConfig = {
@ -39,4 +40,8 @@ export const environment: EnvironmentConfig = {
helloWorld, helloWorld,
keyFunderConfig, keyFunderConfig,
storageGasOracleConfig, storageGasOracleConfig,
liquidityLayerConfig: {
bridgeAdapters: bridgeAdapterConfigs,
relayer: relayerConfig,
},
}; };

@ -0,0 +1,49 @@
import {
AgentConnectionType,
BridgeAdapterConfig,
BridgeAdapterType,
ChainMap,
Chains,
chainMetadata,
} from '@hyperlane-xyz/sdk';
import { LiquidityLayerRelayerConfig } from '../../../src/config/middleware';
import { environment } from './chains';
const circleDomainMapping = [
{ hyperlaneDomain: chainMetadata[Chains.ethereum].chainId, circleDomain: 0 },
{ hyperlaneDomain: chainMetadata[Chains.avalanche].chainId, circleDomain: 1 },
];
export const bridgeAdapterConfigs: ChainMap<BridgeAdapterConfig> = {
[Chains.ethereum]: {
circle: {
type: BridgeAdapterType.Circle,
tokenMessengerAddress: '0xBd3fa81B58Ba92a82136038B25aDec7066af3155',
messageTransmitterAddress: '0x0a992d191DEeC32aFe36203Ad87D7d289a738F81',
usdcAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
circleDomainMapping,
},
},
[Chains.avalanche]: {
circle: {
type: BridgeAdapterType.Circle,
tokenMessengerAddress: '0x6B25532e1060CE10cc3B0A99e5683b91BFDe6982',
messageTransmitterAddress: '0x8186359af5f57fbb40c6b14a588d2a59c0c29880',
usdcAddress: '0xB97EF9Ef8734C71904D8002F8b6Bc66Dd9c48a6E',
circleDomainMapping,
},
},
};
export const relayerConfig: LiquidityLayerRelayerConfig = {
docker: {
repo: 'gcr.io/abacus-labs-dev/hyperlane-monorepo',
tag: '59410cd-20230420-091923',
},
namespace: environment,
prometheusPushGateway:
'http://prometheus-pushgateway.monitoring.svc.cluster.local:9091',
connectionType: AgentConnectionType.Http,
};

@ -0,0 +1,12 @@
{
"ethereum": {
"proxyAdmin": "0x75EE15Ee1B4A75Fa3e2fDF5DF3253c25599cc659",
"liquidityLayerRouter": "0x9954A0d5C9ac7e4a3687f9B08c0FF272f9d0dc71",
"circleBridgeAdapter": "0xf7Cb9e767247144D89bcf36614D56C33FD4Db562"
},
"avalanche": {
"proxyAdmin": "0xd7CF8c05fd81b8cA7CfF8E6C49B08a9D63265c9B",
"liquidityLayerRouter": "0xEff8C988b9F9f606059c436F5C1Cc431571C8B03",
"circleBridgeAdapter": "0x0BFf79f395A73817df1d3c80D78bb3C57Fbbc2Ed"
}
}

@ -0,0 +1,42 @@
{
"ethereum": [
{
"name": "LiquidityLayerRouter",
"address": "0x9954A0d5C9ac7e4a3687f9B08c0FF272f9d0dc71",
"constructorArguments": "",
"isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0x75FE1c9cf9CD1f49bD655F4a173FE5CA7C22D8E1",
"constructorArguments": "0000000000000000000000009954a0d5c9ac7e4a3687f9b08c0ff272f9d0dc7100000000000000000000000075ee15ee1b4a75fa3e2fdf5df3253c25599cc65900000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000084f8c8765e00000000000000000000000035231d4c2d8b8adcb5617a638a0c4548684c7c7000000000000000000000000056f52c0a1ddcd557285f7cbc782d3d83096ce1cc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000",
"isProxy": true
},
{
"name": "CircleBridgeAdapter",
"address": "0xf7Cb9e767247144D89bcf36614D56C33FD4Db562",
"constructorArguments": "",
"isProxy": false
}
],
"avalanche": [
{
"name": "LiquidityLayerRouter",
"address": "0xDc68A5829F7Edfe2954EEe1bff23C3C994197596",
"constructorArguments": "",
"isProxy": false
},
{
"name": "TransparentUpgradeableProxy",
"address": "0xEff8C988b9F9f606059c436F5C1Cc431571C8B03",
"constructorArguments": "000000000000000000000000dc68a5829f7edfe2954eee1bff23c3c994197596000000000000000000000000d7cf8c05fd81b8ca7cff8e6c49b08a9d63265c9b00000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000084f8c8765e00000000000000000000000035231d4c2d8b8adcb5617a638a0c4548684c7c7000000000000000000000000056f52c0a1ddcd557285f7cbc782d3d83096ce1cc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a7eccdb9be08178f896c26b7bbd8c3d4e844d9ba00000000000000000000000000000000000000000000000000000000",
"isProxy": true
},
{
"name": "CircleBridgeAdapter",
"address": "0x0BFf79f395A73817df1d3c80D78bb3C57Fbbc2Ed",
"constructorArguments": "",
"isProxy": false
}
]
}

@ -4,12 +4,12 @@ import {
CircleBridgeAdapter__factory, CircleBridgeAdapter__factory,
ICircleMessageTransmitter__factory, ICircleMessageTransmitter__factory,
ITokenMessenger__factory, ITokenMessenger__factory,
Mailbox__factory,
PortalAdapter__factory, PortalAdapter__factory,
} from '@hyperlane-xyz/core'; } from '@hyperlane-xyz/core';
import { utils } from '@hyperlane-xyz/utils'; import { utils } from '@hyperlane-xyz/utils';
import { HyperlaneApp } from '../../HyperlaneApp'; import { HyperlaneApp } from '../../HyperlaneApp';
import { Chains } from '../../consts/chains';
import { HyperlaneContracts } from '../../contracts'; import { HyperlaneContracts } from '../../contracts';
import { MultiProvider } from '../../providers/MultiProvider'; import { MultiProvider } from '../../providers/MultiProvider';
import { ChainMap, ChainName } from '../../types'; import { ChainMap, ChainName } from '../../types';
@ -20,8 +20,10 @@ import { liquidityLayerFactories } from './contracts';
const PORTAL_VAA_SERVICE_TESTNET_BASE_URL = const PORTAL_VAA_SERVICE_TESTNET_BASE_URL =
'https://wormhole-v2-testnet-api.certus.one/v1/signed_vaa/'; 'https://wormhole-v2-testnet-api.certus.one/v1/signed_vaa/';
const CIRCLE_ATTESTATIONS_BASE_URL = const CIRCLE_ATTESTATIONS_TESTNET_BASE_URL =
'https://iris-api-sandbox.circle.com/attestations/'; 'https://iris-api-sandbox.circle.com/attestations/';
const CIRCLE_ATTESTATIONS_MAINNET_BASE_URL =
'https://iris-api.circle.com/attestations/';
const PORTAL_VAA_SERVICE_SUCCESS_CODE = 5; const PORTAL_VAA_SERVICE_SUCCESS_CODE = 5;
@ -29,6 +31,7 @@ const TokenMessengerInterface = ITokenMessenger__factory.createInterface();
const CircleBridgeAdapterInterface = const CircleBridgeAdapterInterface =
CircleBridgeAdapter__factory.createInterface(); CircleBridgeAdapter__factory.createInterface();
const PortalAdapterInterface = PortalAdapter__factory.createInterface(); const PortalAdapterInterface = PortalAdapter__factory.createInterface();
const MailboxInterface = Mailbox__factory.createInterface();
const BridgedTokenTopic = CircleBridgeAdapterInterface.getEventTopic( const BridgedTokenTopic = CircleBridgeAdapterInterface.getEventTopic(
CircleBridgeAdapterInterface.getEvent('BridgedToken'), CircleBridgeAdapterInterface.getEvent('BridgedToken'),
@ -69,6 +72,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
} }
async fetchCircleMessageTransactions(chain: ChainName): Promise<string[]> { async fetchCircleMessageTransactions(chain: ChainName): Promise<string[]> {
console.log(`Fetch circle messages for ${chain}`);
const url = new URL(this.multiProvider.getExplorerApiUrl(chain)); const url = new URL(this.multiProvider.getExplorerApiUrl(chain));
url.searchParams.set('module', 'logs'); url.searchParams.set('module', 'logs');
url.searchParams.set('action', 'getLogs'); url.searchParams.set('action', 'getLogs');
@ -80,7 +84,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
const req = await fetchWithTimeout(url); const req = await fetchWithTimeout(url);
const response = await req.json(); const response = await req.json();
return response.result.map((_: any) => _.transactionHash).flat(); return response.result.map((tx: any) => tx.transactionHash).flat();
} }
async fetchPortalBridgeTransactions(chain: ChainName): Promise<string[]> { async fetchPortalBridgeTransactions(chain: ChainName): Promise<string[]> {
@ -99,7 +103,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
throw Error(`Expected result in response: ${response}`); throw Error(`Expected result in response: ${response}`);
} }
return response.result.map((_: any) => _.transactionHash).flat(); return response.result.map((tx: any) => tx.transactionHash).flat();
} }
async parsePortalMessages( async parsePortalMessages(
@ -109,9 +113,9 @@ export class LiquidityLayerApp extends HyperlaneApp<
const provider = this.multiProvider.getProvider(chain); const provider = this.multiProvider.getProvider(chain);
const receipt = await provider.getTransactionReceipt(txHash); const receipt = await provider.getTransactionReceipt(txHash);
const matchingLogs = receipt.logs const matchingLogs = receipt.logs
.map((_) => { .map((log) => {
try { try {
return [PortalAdapterInterface.parseLog(_)]; return [PortalAdapterInterface.parseLog(log)];
} catch { } catch {
return []; return [];
} }
@ -119,7 +123,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
.flat(); .flat();
if (matchingLogs.length == 0) return []; if (matchingLogs.length == 0) return [];
const event = matchingLogs.find((_) => _!.name === 'BridgedToken')!; const event = matchingLogs.find((log) => log!.name === 'BridgedToken')!;
const portalSequence = event.args.portalSequence.toNumber(); const portalSequence = event.args.portalSequence.toNumber();
const nonce = event.args.nonce.toNumber(); const nonce = event.args.nonce.toNumber();
const destination = this.multiProvider.getChainName(event.args.destination); const destination = this.multiProvider.getChainName(event.args.destination);
@ -131,30 +135,41 @@ export class LiquidityLayerApp extends HyperlaneApp<
chain: ChainName, chain: ChainName,
txHash: string, txHash: string,
): Promise<CircleBridgeMessage[]> { ): Promise<CircleBridgeMessage[]> {
console.debug(`Parse Circle messages for chain ${chain} ${txHash}`);
const provider = this.multiProvider.getProvider(chain); const provider = this.multiProvider.getProvider(chain);
const receipt = await provider.getTransactionReceipt(txHash); const receipt = await provider.getTransactionReceipt(txHash);
const matchingLogs = receipt.logs const matchingLogs = receipt.logs
.map((_) => { .map((log) => {
try { try {
return [TokenMessengerInterface.parseLog(_)]; return [TokenMessengerInterface.parseLog(log)];
} catch { } catch {
try { try {
return [CircleBridgeAdapterInterface.parseLog(_)]; return [CircleBridgeAdapterInterface.parseLog(log)];
} catch { } catch {
return []; try {
return [MailboxInterface.parseLog(log)];
} catch {
return [];
}
} }
} }
}) })
.flat(); .flat();
if (matchingLogs.length == 0) return []; if (matchingLogs.length == 0) return [];
const message = matchingLogs.find((_) => _!.name === 'MessageSent')!.args const message = matchingLogs.find((log) => log!.name === 'MessageSent')!
.message; .args.message;
const nonce = matchingLogs.find((_) => _!.name === 'BridgedToken')!.args const nonce = matchingLogs.find((log) => log!.name === 'BridgedToken')!.args
.nonce; .nonce;
const remoteChain = chain === Chains.fuji ? Chains.goerli : Chains.fuji;
const destinationDomain = matchingLogs.find(
(log) => log!.name === 'Dispatch',
)!.args.destination;
const remoteChain = this.multiProvider.getChainName(destinationDomain);
const domain = this.config[chain].circle!.circleDomainMapping.find( const domain = this.config[chain].circle!.circleDomainMapping.find(
(_) => _.hyperlaneDomain === this.multiProvider.getDomainId(chain), (mapping) =>
mapping.hyperlaneDomain === this.multiProvider.getDomainId(chain),
)!.circleDomain; )!.circleDomain;
return [ return [
{ {
@ -196,8 +211,9 @@ export class LiquidityLayerApp extends HyperlaneApp<
const wormholeOriginDomain = this.config[ const wormholeOriginDomain = this.config[
message.destination message.destination
].portal!.wormholeDomainMapping.find( ].portal!.wormholeDomainMapping.find(
(_) => (mapping) =>
_.hyperlaneDomain === this.multiProvider.getDomainId(message.origin), mapping.hyperlaneDomain ===
this.multiProvider.getDomainId(message.origin),
)?.wormholeDomain; )?.wormholeDomain;
const emitter = utils.strip0x( const emitter = utils.strip0x(
utils.addressToBytes32( utils.addressToBytes32(
@ -207,7 +223,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
const vaa = await fetchWithTimeout( const vaa = await fetchWithTimeout(
`${PORTAL_VAA_SERVICE_TESTNET_BASE_URL}${wormholeOriginDomain}/${emitter}/${message.portalSequence}`, `${PORTAL_VAA_SERVICE_TESTNET_BASE_URL}${wormholeOriginDomain}/${emitter}/${message.portalSequence}`,
).then((_) => _.json()); ).then((response) => response.json());
if (vaa.code && vaa.code === PORTAL_VAA_SERVICE_SUCCESS_CODE) { if (vaa.code && vaa.code === PORTAL_VAA_SERVICE_SUCCESS_CODE) {
console.log(`VAA not yet found for nonce ${message.nonce}`); console.log(`VAA not yet found for nonce ${message.nonce}`);
@ -253,10 +269,13 @@ export class LiquidityLayerApp extends HyperlaneApp<
return; return;
} }
console.log(`Attempt Circle message delivery`, JSON.stringify(message));
const messageHash = ethers.utils.keccak256(message.message); const messageHash = ethers.utils.keccak256(message.message);
const attestationsB = await fetchWithTimeout( const baseurl = this.multiProvider.getChainMetadata(message.chain).isTestnet
`${CIRCLE_ATTESTATIONS_BASE_URL}${messageHash}`, ? CIRCLE_ATTESTATIONS_TESTNET_BASE_URL
); : CIRCLE_ATTESTATIONS_MAINNET_BASE_URL;
const attestationsB = await fetchWithTimeout(`${baseurl}${messageHash}`);
const attestations = await attestationsB.json(); const attestations = await attestationsB.json();
if (attestations.status !== 'complete') { if (attestations.status !== 'complete') {

Loading…
Cancel
Save