Skip to content

Commit

Permalink
feat(blast): add blast info to chain adapters (#1652)
Browse files Browse the repository at this point in the history
This commit should make all necessary changes to the finalizer and 
relayer so that it can send messages to Blast.

---------

Signed-off-by: bennett <[email protected]>
Co-authored-by: Paul <[email protected]>
  • Loading branch information
bmzig and pxrl authored Jul 9, 2024
1 parent 5c224b4 commit e4b8b51
Show file tree
Hide file tree
Showing 6 changed files with 329 additions and 10 deletions.
11 changes: 10 additions & 1 deletion src/clients/bridges/AdapterManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export class AdapterManager {
);
};

const { OPTIMISM, ARBITRUM, POLYGON, ZK_SYNC, BASE, MODE, LINEA, LISK } = CHAIN_IDs;
const { OPTIMISM, ARBITRUM, POLYGON, ZK_SYNC, BASE, MODE, LINEA, LISK, BLAST } = CHAIN_IDs;
if (this.spokePoolClients[OPTIMISM] !== undefined) {
this.adapters[OPTIMISM] = new OpStackAdapter(
OPTIMISM,
Expand Down Expand Up @@ -86,6 +86,15 @@ export class AdapterManager {
filterMonitoredAddresses(LISK)
);
}
if (this.spokePoolClients[BLAST] !== undefined) {
this.adapters[BLAST] = new OpStackAdapter(
BLAST,
logger,
SUPPORTED_TOKENS[BLAST],
spokePoolClients,
filterMonitoredAddresses(BLAST)
);
}

logger.debug({
at: "AdapterManager#constructor",
Expand Down
6 changes: 5 additions & 1 deletion src/clients/bridges/op-stack/OpStackAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import { WethBridge } from "./WethBridge";
import { DefaultERC20Bridge } from "./DefaultErc20Bridge";
import { UsdcTokenSplitterBridge } from "./UsdcTokenSplitterBridge";
import { DaiOptimismBridge, SnxOptimismBridge } from "./optimism";
import { BlastBridge } from "./blast/BlastBridge";

export class OpStackAdapter extends BaseAdapter {
public l2Gas: number;
Expand All @@ -42,12 +43,15 @@ export class OpStackAdapter extends BaseAdapter {
const mainnetSigner = this.getSigner(hubChainId);
const l2Signer = this.getSigner(chainId);

const { OPTIMISM } = CHAIN_IDs;
const { OPTIMISM, BLAST } = CHAIN_IDs;
if (chainId === OPTIMISM) {
const dai = TOKEN_SYMBOLS_MAP.DAI.addresses[hubChainId];
const snx = TOKEN_SYMBOLS_MAP.SNX.addresses[hubChainId];
this.customBridges[dai] = new DaiOptimismBridge(chainId, hubChainId, mainnetSigner, l2Signer);
this.customBridges[snx] = new SnxOptimismBridge(chainId, hubChainId, mainnetSigner, l2Signer);
} else if (chainId === BLAST) {
const dai = TOKEN_SYMBOLS_MAP.DAI.addresses[hubChainId];
this.customBridges[dai] = new BlastBridge(chainId, hubChainId, mainnetSigner, l2Signer);
}

// Typically, a custom WETH bridge is not provided, so use the standard one.
Expand Down
69 changes: 69 additions & 0 deletions src/clients/bridges/op-stack/blast/BlastBridge.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Contract, BigNumber, paginatedEventQuery, EventSearchConfig, Signer, Provider } from "../../../../utils";
import { CONTRACT_ADDRESSES } from "../../../../common";
import { OpStackBridge, BridgeTransactionDetails, OpStackEvents } from "../OpStackBridgeInterface";

export class BlastBridge extends OpStackBridge {
private readonly l1Bridge: Contract;
private readonly l2Bridge: Contract;

constructor(l2chainId: number, hubChainId: number, l1Signer: Signer, l2SignerOrProvider: Signer | Provider) {
const { address: l1Address, abi: l1Abi } = CONTRACT_ADDRESSES[hubChainId].blastBridge;
const { address: l2Address, abi: l2Abi } = CONTRACT_ADDRESSES[l2chainId].blastBridge;
super(l2chainId, hubChainId, l1Signer, l2SignerOrProvider, [l1Address]);

this.l1Bridge = new Contract(l1Address, l1Abi, l1Signer);
this.l2Bridge = new Contract(l2Address, l2Abi, l2SignerOrProvider);
}

protected getL1Bridge(): Contract {
return this.l1Bridge;
}

protected getL2Bridge(): Contract {
return this.l2Bridge;
}

constructL1ToL2Txn(
toAddress: string,
l1Token: string,
l2Token: string,
amount: BigNumber,
l2Gas: number
): BridgeTransactionDetails {
return {
contract: this.getL1Bridge(),
method: "bridgeERC20",
args: [l1Token, l2Token, amount, l2Gas, "0x"],
};
}

async queryL1BridgeInitiationEvents(
l1Token: string,
fromAddress: string,
eventConfig: EventSearchConfig
): Promise<OpStackEvents> {
const l1Bridge = this.getL1Bridge();
return {
[this.resolveL2TokenAddress(l1Token)]: await paginatedEventQuery(
l1Bridge,
l1Bridge.filters.ERC20BridgeInitiated(l1Token, undefined, fromAddress),
eventConfig
),
};
}

async queryL2BridgeFinalizationEvents(
l1Token: string,
fromAddress: string,
eventConfig: EventSearchConfig
): Promise<OpStackEvents> {
const l2Bridge = this.getL2Bridge();
return {
[this.resolveL2TokenAddress(l1Token)]: await paginatedEventQuery(
l2Bridge,
l2Bridge.filters.ERC20BridgeFinalized(l1Token, undefined, fromAddress),
eventConfig
),
};
}
}
23 changes: 22 additions & 1 deletion src/common/Constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const DATAWORKER_FAST_LOOKBACK: { [chainId: number]: number } = {
[CHAIN_IDs.MODE]: 172800, // Same as Optimism.
[CHAIN_IDs.ARBITRUM]: 1382400,
[CHAIN_IDs.LINEA]: 115200, // 1 block every 3 seconds
[CHAIN_IDs.BLAST]: 172800,
};

// Target ~14 days per chain. Should cover all events that could be finalized, so 2x the optimistic
Expand Down Expand Up @@ -61,6 +62,7 @@ export const DEFAULT_MIN_DEPOSIT_CONFIRMATIONS = {
[CHAIN_IDs.MODE]: 120,
[CHAIN_IDs.ARBITRUM]: 0,
[CHAIN_IDs.LINEA]: 30,
[CHAIN_IDs.BLAST]: 120,
// Testnets:
[CHAIN_IDs.MODE_SEPOLIA]: 0,
[CHAIN_IDs.POLYGON_AMOY]: 0,
Expand All @@ -69,6 +71,7 @@ export const DEFAULT_MIN_DEPOSIT_CONFIRMATIONS = {
[CHAIN_IDs.SEPOLIA]: 0,
[CHAIN_IDs.OPTIMISM_SEPOLIA]: 0,
[CHAIN_IDs.LISK_SEPOLIA]: 0,
[CHAIN_IDs.BLAST_SEPOLIA]: 0,
};
export const MIN_DEPOSIT_CONFIRMATIONS: { [threshold: number | string]: { [chainId: number]: number } } = {
1000: {
Expand All @@ -82,12 +85,14 @@ export const MIN_DEPOSIT_CONFIRMATIONS: { [threshold: number | string]: { [chain
[CHAIN_IDs.MODE]: 60,
[CHAIN_IDs.ARBITRUM]: 0,
[CHAIN_IDs.LINEA]: 1,
[CHAIN_IDs.BLAST]: 60,
// Testnets:
[CHAIN_IDs.MODE_SEPOLIA]: 0,
[CHAIN_IDs.LISK_SEPOLIA]: 0,
[CHAIN_IDs.POLYGON_AMOY]: 0,
[CHAIN_IDs.BASE_SEPOLIA]: 0,
[CHAIN_IDs.OPTIMISM_SEPOLIA]: 0,
[CHAIN_IDs.BLAST_SEPOLIA]: 0,
},
100: {
[CHAIN_IDs.MAINNET]: 16, // Mainnet reorgs are rarely > 4 blocks in depth so this is a very safe buffer
Expand All @@ -100,12 +105,14 @@ export const MIN_DEPOSIT_CONFIRMATIONS: { [threshold: number | string]: { [chain
[CHAIN_IDs.MODE]: 60,
[CHAIN_IDs.ARBITRUM]: 0,
[CHAIN_IDs.LINEA]: 1,
[CHAIN_IDs.BLAST]: 60,
// Testnets:
[CHAIN_IDs.MODE_SEPOLIA]: 0,
[CHAIN_IDs.LISK_SEPOLIA]: 0,
[CHAIN_IDs.POLYGON_AMOY]: 0,
[CHAIN_IDs.BASE_SEPOLIA]: 0,
[CHAIN_IDs.ARBITRUM_SEPOLIA]: 0,
[CHAIN_IDs.BLAST_SEPOLIA]: 0,
},
};

Expand All @@ -127,6 +134,7 @@ export const CHAIN_MAX_BLOCK_LOOKBACK = {
[CHAIN_IDs.MODE]: 1500,
[CHAIN_IDs.ARBITRUM]: 10000,
[CHAIN_IDs.LINEA]: 5000,
[CHAIN_IDs.BLAST]: 1500,
// Testnets:
[CHAIN_IDs.MODE_SEPOLIA]: 10000,
[CHAIN_IDs.POLYGON_AMOY]: 10000,
Expand All @@ -135,6 +143,7 @@ export const CHAIN_MAX_BLOCK_LOOKBACK = {
[CHAIN_IDs.ARBITRUM_SEPOLIA]: 10000,
[CHAIN_IDs.SEPOLIA]: 10000,
[CHAIN_IDs.OPTIMISM_SEPOLIA]: 10000,
[CHAIN_IDs.BLAST_SEPOLIA]: 10000,
};

// These should be safely above the finalization period for the chain and
Expand All @@ -152,6 +161,7 @@ export const BUNDLE_END_BLOCK_BUFFERS = {
[CHAIN_IDs.MODE]: 60, // 2s/block. Same finality profile as Optimism
[CHAIN_IDs.ARBITRUM]: 240, // ~0.25s/block. Arbitrum is a centralized sequencer
[CHAIN_IDs.LINEA]: 40, // At 3s/block, 2 mins = 40 blocks.
[CHAIN_IDs.BLAST]: 60,
// Testnets:
[CHAIN_IDs.MODE_SEPOLIA]: 0,
[CHAIN_IDs.LISK_SEPOLIA]: 0,
Expand All @@ -160,6 +170,7 @@ export const BUNDLE_END_BLOCK_BUFFERS = {
[CHAIN_IDs.ARBITRUM_SEPOLIA]: 0,
[CHAIN_IDs.SEPOLIA]: 0,
[CHAIN_IDs.OPTIMISM_SEPOLIA]: 0,
[CHAIN_IDs.BLAST_SEPOLIA]: 0,
};

export const DEFAULT_RELAYER_GAS_PADDING = ".15"; // Padding on token- and message-based relayer fill gas estimates.
Expand Down Expand Up @@ -197,6 +208,7 @@ export const CHAIN_CACHE_FOLLOW_DISTANCE: { [chainId: number]: number } = {
[CHAIN_IDs.ARBITRUM]: 32,
[CHAIN_IDs.LINEA]: 100, // Linea has a soft-finality of 1 block. This value is padded - but at 3s/block the padding is 5 minutes
[CHAIN_IDs.SCROLL]: 0,
[CHAIN_IDs.BLAST]: 120,
// Testnets:
[CHAIN_IDs.MODE_SEPOLIA]: 0,
[CHAIN_IDs.LISK_SEPOLIA]: 0,
Expand All @@ -205,6 +217,7 @@ export const CHAIN_CACHE_FOLLOW_DISTANCE: { [chainId: number]: number } = {
[CHAIN_IDs.ARBITRUM_SEPOLIA]: 0,
[CHAIN_IDs.SEPOLIA]: 0,
[CHAIN_IDs.OPTIMISM_SEPOLIA]: 0,
[CHAIN_IDs.BLAST_SEPOLIA]: 0,
};

// This is the block distance at which the bot, by default, stores in redis with no TTL.
Expand All @@ -222,6 +235,7 @@ export const DEFAULT_NO_TTL_DISTANCE: { [chainId: number]: number } = {
[CHAIN_IDs.LINEA]: 57600,
[CHAIN_IDs.ARBITRUM]: 691200,
[CHAIN_IDs.SCROLL]: 57600,
[CHAIN_IDs.BLAST]: 86400,
};

// Reasonable default maxFeePerGas and maxPriorityFeePerGas scalers for each chain.
Expand All @@ -233,6 +247,7 @@ export const DEFAULT_GAS_FEE_SCALERS: {
[CHAIN_IDs.LISK]: { maxFeePerGasScaler: 2, maxPriorityFeePerGasScaler: 1 },
[CHAIN_IDs.BASE]: { maxFeePerGasScaler: 2, maxPriorityFeePerGasScaler: 1 },
[CHAIN_IDs.MODE]: { maxFeePerGasScaler: 2, maxPriorityFeePerGasScaler: 1 },
[CHAIN_IDs.BLAST]: { maxFeePerGasScaler: 2, maxPriorityFeePerGasScaler: 1 },
};

// This is how many seconds stale the block number can be for us to use it for evaluating the reorg distance in the cache provider.
Expand All @@ -254,11 +269,13 @@ export const multicall3Addresses = {
[CHAIN_IDs.ARBITRUM]: "0xcA11bde05977b3631167028862bE2a173976CA11",
[CHAIN_IDs.LINEA]: "0xcA11bde05977b3631167028862bE2a173976CA11",
[CHAIN_IDs.SCROLL]: "0xcA11bde05977b3631167028862bE2a173976CA11",
// testnet
[CHAIN_IDs.BLAST]: "0xcA11bde05977b3631167028862bE2a173976CA11",
// Testnet:
[CHAIN_IDs.POLYGON_AMOY]: "0xcA11bde05977b3631167028862bE2a173976CA11",
[CHAIN_IDs.BASE_SEPOLIA]: "0xcA11bde05977b3631167028862bE2a173976CA11",
[CHAIN_IDs.SCROLL_SEPOLIA]: "0xcA11bde05977b3631167028862bE2a173976CA11",
[CHAIN_IDs.SEPOLIA]: "0xcA11bde05977b3631167028862bE2a173976CA11",
[CHAIN_IDs.BLAST_SEPOLIA]: "0xcA11bde05977b3631167028862bE2a173976CA11",
};
export type Multicall2Call = {
callData: ethers.utils.BytesLike;
Expand All @@ -274,6 +291,7 @@ export const spokesThatHoldEthAndWeth = [
CHAIN_IDs.BASE,
CHAIN_IDs.MODE,
CHAIN_IDs.LINEA,
CHAIN_IDs.BLAST,
];

/**
Expand Down Expand Up @@ -303,13 +321,15 @@ export const SUPPORTED_TOKENS: { [chainId: number]: string[] } = {
[CHAIN_IDs.MODE]: ["ETH", "WETH", "USDC", "USDT", "WBTC"],
[CHAIN_IDs.ARBITRUM]: ["USDC", "USDT", "WETH", "DAI", "WBTC", "UMA", "BAL", "ACX", "POOL"],
[CHAIN_IDs.LINEA]: ["USDC", "USDT", "WETH", "WBTC", "DAI"],
[CHAIN_IDs.BLAST]: ["DAI", "WBTC", "WETH"],

// Testnets:
[CHAIN_IDs.MODE_SEPOLIA]: ["ETH", "WETH", "USDC", "USDT", "WBTC"],
[CHAIN_IDs.LISK_SEPOLIA]: ["WETH", "USDT"],
[CHAIN_IDs.BASE_SEPOLIA]: ["BAL", "DAI", "ETH", "WETH", "USDC"],
[CHAIN_IDs.ARBITRUM_SEPOLIA]: ["USDC", "USDT", "WETH", "DAI", "WBTC", "UMA", "ACX"],
[CHAIN_IDs.OPTIMISM_SEPOLIA]: ["DAI", "SNX", "BAL", "ETH", "WETH", "USDC", "USDT", "WBTC", "UMA", "ACX"],
[CHAIN_IDs.BLAST_SEPOLIA]: ["WETH"],
};

/**
Expand Down Expand Up @@ -347,6 +367,7 @@ export const EXPECTED_L1_TO_L2_MESSAGE_TIME = {
[CHAIN_IDs.LISK]: 20 * 60,
[CHAIN_IDs.BASE]: 20 * 60,
[CHAIN_IDs.MODE]: 20 * 60,
[CHAIN_IDs.BLAST]: 20 * 60,
};

export const OPSTACK_CONTRACT_OVERRIDES = {
Expand Down
33 changes: 26 additions & 7 deletions src/common/ContractAddresses.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,29 @@
// Mainnet
import CCTP_MESSAGE_TRANSMITTER_ABI from "./abi/CctpMessageTransmitter.json";
import CCTP_TOKEN_MESSENGER_ABI from "./abi/CctpTokenMessenger.json";
import ATOMIC_DEPOSITOR_ABI from "./abi/AtomicDepositor.json";
import WETH_ABI from "./abi/Weth.json";
import HUB_POOL_ABI from "./abi/HubPool.json";
import VOTING_V2_ABI from "./abi/VotingV2.json";
// OpStack
import OVM_L2_STANDARD_BRIDGE_ABI from "./abi/OpStackStandardBridgeL2.json";
import OVM_L1_STANDARD_BRIDGE_ABI from "./abi/OpStackStandardBridgeL1.json";
import DAI_OPTIMISM_BRIDGE_L1_ABI from "./abi/DaiOptimismBridgeL1.json";
import DAI_OPTIMISM_BRIDGE_L2_ABI from "./abi/DaiOptimismBridgeL2.json";
import SNX_OPTIMISM_BRIDGE_L1_ABI from "./abi/SnxOptimismBridgeL1.json";
import SNX_OPTIMISM_BRIDGE_L2_ABI from "./abi/SnxOptimismBridgeL2.json";
// Polygon
import POLYGON_BRIDGE_ABI from "./abi/PolygonBridge.json";
import POLYGON_ROOT_CHAIN_MANAGER_ABI from "./abi/PolygonRootChainManager.json";
import POLYGON_WITHDRAWABLE_ERC20_ABI from "./abi/PolygonWithdrawableErc20.json";
// ZkSync
import ZK_SYNC_DEFAULT_ERC20_BRIDGE_L1_ABI from "./abi/ZkSyncDefaultErc20BridgeL1.json";
import ZK_SYNC_DEFAULT_ERC20_BRIDGE_L2_ABI from "./abi/ZkSyncDefaultErc20BridgeL2.json";
import ZK_SYNC_MAILBOX_ABI from "./abi/ZkSyncMailbox.json";
// Arbitrum
import ARBITRUM_ERC20_GATEWAY_ROUTER_L1_ABI from "./abi/ArbitrumErc20GatewayRouterL1.json";
import ARBITRUM_ERC20_GATEWAY_L2_ABI from "./abi/ArbitrumErc20GatewayL2.json";
import ARBITRUM_OUTBOX_ABI from "./abi/ArbitrumOutbox.json";
// Linea
import LINEA_MESSAGE_SERVICE_ABI from "./abi/LineaMessageService.json";
import LINEA_TOKEN_BRIDGE_ABI from "./abi/LineaTokenBridge.json";
import LINEA_USDC_BRIDGE_ABI from "./abi/LineaUsdcBridge.json";
// Scroll
import SCROLL_RELAY_MESSENGER_ABI from "./abi/ScrollRelayMessenger.json";
import BLAST_BRIDGE_ABI from "./abi/BlastBridge.json";

// Constants file exporting hardcoded contract addresses per chain.
export const CONTRACT_ADDRESSES: {
Expand Down Expand Up @@ -93,6 +87,10 @@ export const CONTRACT_ADDRESSES: {
address: "0x735aDBbE72226BD52e818E7181953f42E3b0FF21",
abi: OVM_L1_STANDARD_BRIDGE_ABI,
},
ovmStandardBridge_81457: {
address: "0x697402166Fbf2F22E970df8a6486Ef171dbfc524",
abi: OVM_L1_STANDARD_BRIDGE_ABI,
},
polygonRootChainManager: {
address: "0xA0c68C638235ee32657e8f720a23ceC1bFc77C77",
abi: POLYGON_ROOT_CHAIN_MANAGER_ABI,
Expand Down Expand Up @@ -127,6 +125,10 @@ export const CONTRACT_ADDRESSES: {
address: "0xc186fA914353c44b2E33eBE05f21846F1048bEda",
abi: HUB_POOL_ABI,
},
blastBridge: {
address: "0x3a05E5d33d7Ab3864D53aaEc93c8301C1Fa49115",
abi: BLAST_BRIDGE_ABI,
},
},
10: {
daiOptimismBridge: {
Expand Down Expand Up @@ -231,6 +233,23 @@ export const CONTRACT_ADDRESSES: {
address: "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
},
},
81457: {
ovmStandardBridge: {
address: "0x4200000000000000000000000000000000000010",
abi: OVM_L2_STANDARD_BRIDGE_ABI,
},
weth: {
address: "0x4200000000000000000000000000000000000004",
abi: WETH_ABI,
},
eth: {
address: "0xDeadDeAddeAddEAddeadDEaDDEAdDeaDDeAD0000",
},
blastBridge: {
address: "0x4300000000000000000000000000000000000005",
abi: BLAST_BRIDGE_ABI,
},
},
42161: {
erc20Gateway: {
abi: ARBITRUM_ERC20_GATEWAY_L2_ABI,
Expand Down
Loading

0 comments on commit e4b8b51

Please sign in to comment.