Skip to content

Commit

Permalink
Merge upstream - 16-09-2024 (#63)
Browse files Browse the repository at this point in the history
### What was the problem?

This PR resolves LISK-1099

### How was it solved?

- [x] `git merge -S upstream/master -X theirs`
- [x] Explicitly added the API server start commit
- [x] Fix docker GHA workflow file

### How was it tested?

`yarn install && yarn eslint && yarn format && yarn build`
`yarn relay --wallet void --address <ADDRESS>`
  • Loading branch information
sameersubudhi authored Sep 16, 2024
2 parents e397e24 + 1bd2da4 commit 3dcd777
Show file tree
Hide file tree
Showing 47 changed files with 1,830 additions and 3,314 deletions.
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.34",
"@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
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

0 comments on commit 3dcd777

Please sign in to comment.