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. 61
      typescript/sdk/src/middleware/liquidity-layer/LiquidityLayerApp.ts

@ -13,6 +13,7 @@ import { storageGasOracleConfig } from './gas-oracle';
import { helloWorld } from './helloworld';
import { igp } from './igp';
import { infrastructure } from './infrastructure';
import { bridgeAdapterConfigs, relayerConfig } from './liquidityLayer';
import { owners } from './owners';
export const environment: EnvironmentConfig = {
@ -39,4 +40,8 @@ export const environment: EnvironmentConfig = {
helloWorld,
keyFunderConfig,
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,
ICircleMessageTransmitter__factory,
ITokenMessenger__factory,
Mailbox__factory,
PortalAdapter__factory,
} from '@hyperlane-xyz/core';
import { utils } from '@hyperlane-xyz/utils';
import { HyperlaneApp } from '../../HyperlaneApp';
import { Chains } from '../../consts/chains';
import { HyperlaneContracts } from '../../contracts';
import { MultiProvider } from '../../providers/MultiProvider';
import { ChainMap, ChainName } from '../../types';
@ -20,8 +20,10 @@ import { liquidityLayerFactories } from './contracts';
const PORTAL_VAA_SERVICE_TESTNET_BASE_URL =
'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/';
const CIRCLE_ATTESTATIONS_MAINNET_BASE_URL =
'https://iris-api.circle.com/attestations/';
const PORTAL_VAA_SERVICE_SUCCESS_CODE = 5;
@ -29,6 +31,7 @@ const TokenMessengerInterface = ITokenMessenger__factory.createInterface();
const CircleBridgeAdapterInterface =
CircleBridgeAdapter__factory.createInterface();
const PortalAdapterInterface = PortalAdapter__factory.createInterface();
const MailboxInterface = Mailbox__factory.createInterface();
const BridgedTokenTopic = CircleBridgeAdapterInterface.getEventTopic(
CircleBridgeAdapterInterface.getEvent('BridgedToken'),
@ -69,6 +72,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
}
async fetchCircleMessageTransactions(chain: ChainName): Promise<string[]> {
console.log(`Fetch circle messages for ${chain}`);
const url = new URL(this.multiProvider.getExplorerApiUrl(chain));
url.searchParams.set('module', 'logs');
url.searchParams.set('action', 'getLogs');
@ -80,7 +84,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
const req = await fetchWithTimeout(url);
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[]> {
@ -99,7 +103,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
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(
@ -109,9 +113,9 @@ export class LiquidityLayerApp extends HyperlaneApp<
const provider = this.multiProvider.getProvider(chain);
const receipt = await provider.getTransactionReceipt(txHash);
const matchingLogs = receipt.logs
.map((_) => {
.map((log) => {
try {
return [PortalAdapterInterface.parseLog(_)];
return [PortalAdapterInterface.parseLog(log)];
} catch {
return [];
}
@ -119,7 +123,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
.flat();
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 nonce = event.args.nonce.toNumber();
const destination = this.multiProvider.getChainName(event.args.destination);
@ -131,30 +135,41 @@ export class LiquidityLayerApp extends HyperlaneApp<
chain: ChainName,
txHash: string,
): Promise<CircleBridgeMessage[]> {
console.debug(`Parse Circle messages for chain ${chain} ${txHash}`);
const provider = this.multiProvider.getProvider(chain);
const receipt = await provider.getTransactionReceipt(txHash);
const matchingLogs = receipt.logs
.map((_) => {
.map((log) => {
try {
return [TokenMessengerInterface.parseLog(_)];
return [TokenMessengerInterface.parseLog(log)];
} catch {
try {
return [CircleBridgeAdapterInterface.parseLog(_)];
return [CircleBridgeAdapterInterface.parseLog(log)];
} catch {
try {
return [MailboxInterface.parseLog(log)];
} catch {
return [];
}
}
}
})
.flat();
if (matchingLogs.length == 0) return [];
const message = matchingLogs.find((_) => _!.name === 'MessageSent')!.args
.message;
const nonce = matchingLogs.find((_) => _!.name === 'BridgedToken')!.args
const message = matchingLogs.find((log) => log!.name === 'MessageSent')!
.args.message;
const nonce = matchingLogs.find((log) => log!.name === 'BridgedToken')!.args
.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(
(_) => _.hyperlaneDomain === this.multiProvider.getDomainId(chain),
(mapping) =>
mapping.hyperlaneDomain === this.multiProvider.getDomainId(chain),
)!.circleDomain;
return [
{
@ -196,8 +211,9 @@ export class LiquidityLayerApp extends HyperlaneApp<
const wormholeOriginDomain = this.config[
message.destination
].portal!.wormholeDomainMapping.find(
(_) =>
_.hyperlaneDomain === this.multiProvider.getDomainId(message.origin),
(mapping) =>
mapping.hyperlaneDomain ===
this.multiProvider.getDomainId(message.origin),
)?.wormholeDomain;
const emitter = utils.strip0x(
utils.addressToBytes32(
@ -207,7 +223,7 @@ export class LiquidityLayerApp extends HyperlaneApp<
const vaa = await fetchWithTimeout(
`${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) {
console.log(`VAA not yet found for nonce ${message.nonce}`);
@ -253,10 +269,13 @@ export class LiquidityLayerApp extends HyperlaneApp<
return;
}
console.log(`Attempt Circle message delivery`, JSON.stringify(message));
const messageHash = ethers.utils.keccak256(message.message);
const attestationsB = await fetchWithTimeout(
`${CIRCLE_ATTESTATIONS_BASE_URL}${messageHash}`,
);
const baseurl = this.multiProvider.getChainMetadata(message.chain).isTestnet
? CIRCLE_ATTESTATIONS_TESTNET_BASE_URL
: CIRCLE_ATTESTATIONS_MAINNET_BASE_URL;
const attestationsB = await fetchWithTimeout(`${baseurl}${messageHash}`);
const attestations = await attestationsB.json();
if (attestations.status !== 'complete') {

Loading…
Cancel
Save