Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge upstream - 18-09-2024 #65

Merged
merged 7 commits into from
Sep 19, 2024
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions .github/workflows/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,4 @@ jobs:
context: ./
file: ./Dockerfile
push: true
tags:
- latest
- ${{ steps.docker-image.outputs.image }}
tags: latest,${{ steps.docker-image.outputs.image }}
5 changes: 4 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,7 @@ dist/
*.txt

# env example files
*.env.example
*.env.example

# local files
.secret
31 changes: 31 additions & 0 deletions contracts/MockPolygonEvents.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// This file contains contracts that can be used to unit test the src/clients/bridges/ZkSyncAdapter.ts
// code which reads events from zkSync contracts facilitating cross chain transfers.

pragma solidity ^0.8.0;

contract Polygon_L1Bridge {
event LockedERC20(
address indexed depositor,
address indexed depositReceiver,
address indexed rootToken,
uint256 amount
);

event LockedEther(address indexed depositor, address indexed depositReceiver, uint256 amount);

function depositFor(address depositor, address depositReceiver, address rootToken, uint256 amount) external {
emit LockedERC20(depositor, depositReceiver, rootToken, amount);
}

function depositEtherFor(address depositor, address depositReceiver, uint256 amount) external {
emit LockedEther(depositor, depositReceiver, amount);
}
}

contract Polygon_L2Bridge {
event Transfer(address indexed from, address indexed to, uint256 value);

function transfer(address from, address to, uint256 value) external {
emit Transfer(from, to, value);
}
}
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"dependencies": {
"@across-protocol/constants": "^3.1.14",
"@across-protocol/contracts": "^3.0.10",
"@across-protocol/sdk": "^3.1.31",
"@across-protocol/sdk": "^3.1.36",
"@arbitrum/sdk": "^3.1.3",
"@aws-sdk/client-kms": "^3.592.0",
"@aws-sdk/client-s3": "^3.592.0",
Expand All @@ -30,7 +30,7 @@
"@types/express": "^4.17.21",
"@uma/common": "2.33.0",
"@uma/logger": "^1.3.0",
"axios": "^1.6.1",
"axios": "^1.7.4",
"dotenv": "^16.3.1",
"ethers": "^5.7.2",
"express": "^4.19.2",
Expand Down
3 changes: 3 additions & 0 deletions scripts/runMainnet.sh
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ echo "SLACK_CONFIG=$SLACK_CONFIG" >> ${app_dir}/.env

echo "All env vars from secrets are set."

# Set the bot identifier
echo "BOT_IDENTIFIER=LISK_ACROSS_RELAYER" >> ${app_dir}/.env

# Simulation mode OFF
echo "SEND_RELAYS=true" >> ${app_dir}/.env
echo "SEND_REBALANCES=true" >> ${app_dir}/.env
Expand Down
6 changes: 6 additions & 0 deletions scripts/runSepolia.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,12 @@ echo "RPC_PROVIDER_GELATO_4202=$RPC_PROVIDER_GELATO_4202" >> ${app_dir}/.env

echo "All env vars from secrets are set."

# Set the bot identifier
echo "BOT_IDENTIFIER=LISK_ACROSS_RELAYER" >> ${app_dir}/.env

# Simulation mode ON
echo "SEND_RELAYS=true" >> ${app_dir}/.env

# RPC provider configuration
echo "RPC_PROVIDERS=TENDERLY,GELATO,DRPC" >> ${app_dir}/.env
echo "RPC_PROVIDERS_11155111=TENDERLY,DRPC" >> ${app_dir}/.env
Expand All @@ -42,8 +46,10 @@ echo "RELAYER_IGNORE_LIMITS=true" >> ${app_dir}/.env
echo "HUB_CHAIN_ID=11155111" >> ${app_dir}/.env
echo "RELAYER_ORIGIN_CHAINS=[11155111,4202]" >> ${app_dir}/.env
echo "RELAYER_DESTINATION_CHAINS=[11155111,4202]" >> ${app_dir}/.env

# Redis settings
echo "REDIS_URL='redis://127.0.0.1:6379'" >> ${app_dir}/.env

# Supported token settings
echo RELAYER_TOKENS=\'[\"0x16B840bA01e2b05fc2268eAf6d18892a11EC29D6\", \"0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0\", \"0xfFf9976782d46CC05630D1f6eBAb18b2324d6B14\"]\' >> ${app_dir}/.env
echo MIN_DEPOSIT_CONFIRMATIONS=\'{ \"1000000\": { \"919\": 1, \"4202\": 1, \"80002\": 1, \"84532\": 1, \"421614\": 1, \"11155111\": 1, \"11155420\": 1 } }\' >> ${app_dir}/.env
Expand Down
10 changes: 6 additions & 4 deletions scripts/spokepool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ async function deposit(args: Record<string, number | string>, signer: Signer): P
}

async function fillDeposit(args: Record<string, number | string | boolean>, signer: Signer): Promise<boolean> {
const { txnHash, depositId: depositIdArg, execute } = args;
const { txnHash, depositId: depositIdArg, execute, slow } = args;
const originChainId = Number(args.chainId);

if (txnHash === undefined || typeof txnHash !== "string" || txnHash.length != 66 || !txnHash.startsWith("0x")) {
Expand Down Expand Up @@ -295,7 +295,9 @@ async function fillDeposit(args: Record<string, number | string | boolean>, sign
fromLiteChain: false, // Not relevant
toLiteChain: false, // Not relevant
};
const fill = await sdkUtils.populateV3Relay(destSpokePool, deposit, relayer);
const fill = isDefined(slow)
? await destSpokePool.populateTransaction.requestV3SlowFill(deposit)
: await sdkUtils.populateV3Relay(destSpokePool, deposit, relayer);

console.group("Fill Txn Info");
console.log(`to: ${fill.to}`);
Expand Down Expand Up @@ -459,7 +461,7 @@ function usage(badInput?: string): boolean {

const dumpConfigArgs = "--chainId";
const fetchArgs = "--chainId <chainId> [--depositId <depositId> | --txnHash <txnHash>]";
const fillArgs = "--chainId <originChainId> --txnHash <depositHash> [--depositId <depositId>] [--execute]";
const fillArgs = "--chainId <originChainId> --txnHash <depositHash> [--depositId <depositId>] [--slow] [--execute]";

const pad = "deposit".length;
usageStr += `
Expand Down Expand Up @@ -491,7 +493,7 @@ async function run(argv: string[]): Promise<number> {
const fetchDepositOpts = ["chainId", "depositId"];
const opts = {
string: ["wallet", ...configOpts, ...depositOpts, ...fetchOpts, ...fillOpts, ...fetchDepositOpts],
boolean: ["decimals", "execute"], // @dev tbd whether this is good UX or not...may need to change.
boolean: ["decimals", "execute", "slow"], // @dev tbd whether this is good UX or not...may need to change.
default: {
wallet: "secret",
decimals: false,
Expand Down
7 changes: 6 additions & 1 deletion src/adapter/BaseChainAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,12 @@ export class BaseChainAdapter {
const augmentedTxn = { contract, chainId: this.chainId, method, args: [], value, mrkdwn, message };
if (simMode) {
const { succeed, reason } = (await this.transactionClient.simulate([augmentedTxn]))[0];
this.log("Simulation result", { succeed, reason, contract, value }, "debug", "wrapEthIfAboveThreshold");
this.log(
"Simulation result",
{ succeed, reason, contract: contract.address, value },
"debug",
"wrapEthIfAboveThreshold"
);
return { hash: ZERO_ADDRESS } as TransactionResponse;
} else {
(await this.transactionClient.submit(this.chainId, [augmentedTxn]))[0];
Expand Down
4 changes: 2 additions & 2 deletions src/adapter/bridges/LineaBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class LineaBridge extends BaseBridgeAdapter {
): Promise<BridgeEvents> {
const events = await paginatedEventQuery(
this.getL1Bridge(),
this.getL1Bridge().filters.BridgingInitiatedV2(undefined, fromAddress, l1Token),
this.getL1Bridge().filters.BridgingInitiatedV2(undefined, toAddress, l1Token),
eventConfig
);
return {
Expand All @@ -60,7 +60,7 @@ export class LineaBridge extends BaseBridgeAdapter {
): Promise<BridgeEvents> {
const events = await paginatedEventQuery(
this.getL2Bridge(),
this.getL2Bridge().filters.BridgingFinalizedV2(l1Token, undefined, undefined, fromAddress),
this.getL2Bridge().filters.BridgingFinalizedV2(l1Token, undefined, undefined, toAddress),
eventConfig
);
// There is no "from" field in this event, so we set it to the L2 token received.
Expand Down
4 changes: 2 additions & 2 deletions src/adapter/bridges/LineaUSDCBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export class LineaUSDCBridge extends BaseBridgeAdapter {
): Promise<BridgeEvents> {
const events = await paginatedEventQuery(
this.getL1Bridge(),
this.getL1Bridge().filters.Deposited(undefined, undefined, fromAddress),
this.getL1Bridge().filters.Deposited(undefined, undefined, toAddress),
eventConfig
);
return {
Expand All @@ -58,7 +58,7 @@ export class LineaUSDCBridge extends BaseBridgeAdapter {
): Promise<BridgeEvents> {
const events = await paginatedEventQuery(
this.getL2Bridge(),
this.getL2Bridge().filters.ReceivedFromOtherLayer(fromAddress),
this.getL2Bridge().filters.ReceivedFromOtherLayer(toAddress),
eventConfig
);
// There is no "from" address in this event.
Expand Down
71 changes: 59 additions & 12 deletions src/adapter/bridges/LineaWethBridge.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import { Contract, BigNumber, paginatedEventQuery, bnZero, Signer, EventSearchConfig, Provider } from "../../utils";
import {
Contract,
BigNumber,
paginatedEventQuery,
bnZero,
Signer,
EventSearchConfig,
Provider,
getBlockForTimestamp,
BlockFinder,
isDefined,
} from "../../utils";
import { CONTRACT_ADDRESSES } from "../../common";
import { BridgeTransactionDetails, BaseBridgeAdapter, BridgeEvents } from "./BaseBridgeAdapter";
import { processEvent } from "../utils";

export class LineaWethBridge extends BaseBridgeAdapter {
protected atomicDepositor: Contract;
protected blockFinder: BlockFinder;

constructor(
l2chainId: number,
Expand Down Expand Up @@ -46,9 +58,12 @@ export class LineaWethBridge extends BaseBridgeAdapter {
): Promise<BridgeEvents> {
const events = await paginatedEventQuery(
this.getL1Bridge(),
this.getL1Bridge().filters.MessageSent(undefined, fromAddress),
this.getL1Bridge().filters.MessageSent(undefined, toAddress),
eventConfig
);

// @dev There will be a MessageSent to the SpokePool address for each RelayedRootBundle so remove
// those with 0 value.
return {
[this.resolveL2TokenAddress(l1Token)]: events
.map((event) => processEvent(event, "_value", "_to", "_from"))
Expand All @@ -62,16 +77,33 @@ export class LineaWethBridge extends BaseBridgeAdapter {
toAddress: string,
eventConfig: EventSearchConfig
): Promise<BridgeEvents> {
// TODO: This can probably be refactored to save an RPC call since this is called in parallel with
// queryL1BridgeInitiationEvents in the BaseChainAdapter class.
const l2Provider = this.getL2Bridge().provider;

const [fromBlock, toBlock] = await Promise.all([
l2Provider.getBlock(eventConfig.fromBlock),
l2Provider.getBlock(eventConfig.toBlock),
]);

const [l1FromBlock, l1ToBlock] = [
await getBlockForTimestamp(this.hubChainId, fromBlock.timestamp, this.blockFinder),
await getBlockForTimestamp(this.hubChainId, toBlock.timestamp, this.blockFinder),
];
const l1SearchConfig = {
fromBlock: l1FromBlock,
toBlock: l1ToBlock,
};
const initiatedQueryResult = await paginatedEventQuery(
this.getL1Bridge(),
this.getL1Bridge().filters.MessageSent(undefined, fromAddress),
eventConfig
this.getL1Bridge().filters.MessageSent(undefined, toAddress),
l1SearchConfig
);

// @dev There will be a MessageSent to the SpokePool address for each RelayedRootBundle so remove
// those with 0 value.
// If there are no initiations, then exit early, since there will be no finalized events to match.
// This can happen if the from/toAddress is the hub pool.
if (initiatedQueryResult.length === 0) {
return Promise.resolve({});
}

const internalMessageHashes = initiatedQueryResult
.filter(({ args }) => args._value.gt(0))
.map(({ args }) => args._messageHash);
Expand All @@ -80,11 +112,26 @@ export class LineaWethBridge extends BaseBridgeAdapter {
this.getL2Bridge().filters.MessageClaimed(internalMessageHashes),
eventConfig
);
const finalizedHashes = events.map(({ args }) => args._messageHash);
const matchedEvents = events
.map((finalized) => {
const queryEvent = initiatedQueryResult.find(
(initiated) => initiated.args._messageHash === finalized.args._messageHash
);
// It is possible for a finalized event to be observed without the corresponding initiation event
// when the finalization event approaches the max look back value. In this case, we filter those out.
return isDefined(queryEvent)
? {
...processEvent(queryEvent, "_value", "_to", "_from"),
blockNumber: finalized.blockNumber,
transactionIndex: finalized.transactionIndex,
logIndex: finalized.logIndex,
transactionHash: finalized.transactionHash,
}
: undefined;
})
.filter(isDefined);
return {
[this.resolveL2TokenAddress(l1Token)]: initiatedQueryResult
.filter(({ args }) => finalizedHashes.includes(args._messageHash))
.map((event) => processEvent(event, "_value", "_to", "_from")),
[this.resolveL2TokenAddress(l1Token)]: matchedEvents,
};
}
}
11 changes: 5 additions & 6 deletions src/adapter/bridges/PolygonERC20Bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
Provider,
bnToHex,
ZERO_ADDRESS,
getL2TokenAddresses,
} from "../../utils";
import { CONTRACT_ADDRESSES } from "../../common";
import { BridgeTransactionDetails, BaseBridgeAdapter, BridgeEvents } from "./BaseBridgeAdapter";
Expand All @@ -31,7 +30,6 @@ export class PolygonERC20Bridge extends BaseBridgeAdapter {
// TOKEN_SYMBOLS_MAP. This constructor will therefore break if
// either the SDK, or the constants dependency in the SDK, is not
// up-to-date.
const l2TokenAddresses = getL2TokenAddresses(l1Token);
const { address: l1Address, abi: l1Abi } = CONTRACT_ADDRESSES[hubChainId].polygonBridge;
const { address: l1GatewayAddress, abi: l1GatewayAbi } = CONTRACT_ADDRESSES[hubChainId].polygonRootChainManager;
super(l2chainId, hubChainId, l1Signer, l2SignerOrProvider, [l1Address]);
Expand All @@ -41,7 +39,8 @@ export class PolygonERC20Bridge extends BaseBridgeAdapter {

// For Polygon, we look for mint events triggered by the L2 token, not the L2 Bridge.
const l2Abi = CONTRACT_ADDRESSES[l2chainId].withdrawableErc20.abi;
this.l2Bridge = new Contract(l2TokenAddresses[l2chainId], l2Abi, l2SignerOrProvider);
const l2TokenAddress = this.resolveL2TokenAddress(l1Token);
this.l2Bridge = new Contract(l2TokenAddress, l2Abi, l2SignerOrProvider);
}

async constructL1ToL2Txn(
Expand All @@ -65,12 +64,12 @@ export class PolygonERC20Bridge extends BaseBridgeAdapter {
): Promise<BridgeEvents> {
const events = await paginatedEventQuery(
this.getL1Bridge(),
this.getL1Bridge().filters.LockedERC20(undefined, fromAddress, l1Token),
this.getL1Bridge().filters.LockedERC20(undefined, toAddress, l1Token),
eventConfig
);
return {
[this.resolveL2TokenAddress(l1Token)]: events.map((event) =>
processEvent(event, "amount", "depositorReceiver", "depositor")
processEvent(event, "amount", "depositReceiver", "depositor")
),
};
}
Expand All @@ -83,7 +82,7 @@ export class PolygonERC20Bridge extends BaseBridgeAdapter {
): Promise<BridgeEvents> {
const events = await paginatedEventQuery(
this.getL2Bridge(),
this.getL2Bridge().filters.Transfer(ZERO_ADDRESS, fromAddress),
this.getL2Bridge().filters.Transfer(ZERO_ADDRESS, toAddress),
eventConfig
);
return {
Expand Down
4 changes: 2 additions & 2 deletions src/adapter/bridges/PolygonWethBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class PolygonWethBridge extends BaseBridgeAdapter {
): Promise<BridgeEvents> {
const events = await paginatedEventQuery(
this.getL1Bridge(),
this.getL1Bridge().filters.LockedEther(undefined, fromAddress),
this.getL1Bridge().filters.LockedEther(undefined, toAddress),
eventConfig
);
return {
Expand All @@ -82,7 +82,7 @@ export class PolygonWethBridge extends BaseBridgeAdapter {
): Promise<BridgeEvents> {
const events = await paginatedEventQuery(
this.getL2Bridge(),
this.getL2Bridge().filters.Transfer(ZERO_ADDRESS, fromAddress),
this.getL2Bridge().filters.Transfer(ZERO_ADDRESS, toAddress),
eventConfig
);
return {
Expand Down
Loading
Loading