Skip to content

Commit

Permalink
Resolve upstream conflicts (#78)
Browse files Browse the repository at this point in the history
### What was the problem?

This PR resolves #LISK-1270

### How was it solved?

- [x] Merge upstream changes to current master branch
- [x] Resolve yarn.lock conflicts
- [x] Reduce fork sync run frequency to once a week

### How was it tested?

```sh
sh ./scripts/lisk/docker/dev/composeStart.sh
sh ./scripts/lisk/docker/dev/composeStop.sh
```
  • Loading branch information
sameersubudhi authored Nov 14, 2024
2 parents 62f1ce8 + 326c287 commit 9c1f9a5
Show file tree
Hide file tree
Showing 68 changed files with 2,474 additions and 630 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/fork-sync.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Sync Fork

on:
schedule:
- cron: "0 0 * * *" # once a day
- cron: "0 0 * * 1" # once a week on Monday
workflow_dispatch: # on button click

jobs:
Expand Down
194 changes: 75 additions & 119 deletions contracts/AtomicWethDepositor.sol
Original file line number Diff line number Diff line change
@@ -1,141 +1,97 @@
// SPDX-License-Identifier: GPL-3.0-only
pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@uma/core/contracts/common/implementation/MultiCaller.sol";
import "@uma/core/contracts/common/implementation/Lockable.sol";

interface Weth {
function withdraw(uint256 _wad) external;

function transferFrom(address _from, address _to, uint256 _wad) external;
}

interface OvmL1Bridge {
function depositETHTo(address _to, uint32 _l2Gas, bytes calldata _data) external payable;
}
/**
* @notice Contract deployed on Ethereum helps relay bots atomically unwrap and bridge WETH over the canonical chain
* bridges for chains that only support bridging of ETH not WETH.
* @dev This contract is ownable so that the owner can update whitelisted bridge addresses and function selectors.
*/
contract AtomicWethDepositor is Ownable, MultiCaller, Lockable {
// The Bridge used to send ETH to another chain. Only the function selector can be used when
// calling the bridge contract.
struct Bridge {
address bridge;
bytes4 funcSelector;
}

interface PolygonL1Bridge {
function depositEtherFor(address _to) external payable;
}
Weth public immutable WETH = Weth(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);

interface ZkSyncL1Bridge {
function requestL2Transaction(
address _contractL2,
uint256 _l2Value,
bytes calldata _calldata,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit,
bytes[] calldata _factoryDeps,
address _refundRecipient
) external payable;

function l2TransactionBaseCost(
uint256 _gasPrice,
uint256 _l2GasLimit,
uint256 _l2GasPerPubdataByteLimit
) external pure returns (uint256);
}
/**
* @notice Mapping of chain ID to whitelisted bridge addresses and function selectors
* that can be called by this contract.
*/
mapping(uint256 => Bridge) public whitelistedBridgeFunctions;

interface LineaL1MessageService {
function sendMessage(address _to, uint256 _fee, bytes calldata _calldata) external payable;
}
///////////////////////////////
// Events //
///////////////////////////////

/**
* @notice Contract deployed on Ethereum helps relay bots atomically unwrap and bridge WETH over the canonical chain
* bridges for Optimism, Base, Boba, ZkSync, Linea, and Polygon. Needed as these chains only support bridging of ETH,
* not WETH.
*/
event AtomicWethDepositInitiated(address indexed from, uint256 indexed chainId, uint256 amount);

contract AtomicWethDepositor {
Weth public immutable weth = Weth(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);
OvmL1Bridge public immutable optimismL1Bridge = OvmL1Bridge(0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1);
OvmL1Bridge public immutable modeL1Bridge = OvmL1Bridge(0x735aDBbE72226BD52e818E7181953f42E3b0FF21);
OvmL1Bridge public immutable bobaL1Bridge = OvmL1Bridge(0xdc1664458d2f0B6090bEa60A8793A4E66c2F1c00);
OvmL1Bridge public immutable baseL1Bridge = OvmL1Bridge(0x3154Cf16ccdb4C6d922629664174b904d80F2C35);
OvmL1Bridge public immutable liskL1Bridge = OvmL1Bridge(0x2658723Bf70c7667De6B25F99fcce13A16D25d08);
OvmL1Bridge public immutable redstoneL1Bridge = OvmL1Bridge(0xc473ca7E02af24c129c2eEf51F2aDf0411c1Df69);
OvmL1Bridge public immutable blastL1Bridge = OvmL1Bridge(0x697402166Fbf2F22E970df8a6486Ef171dbfc524);
OvmL1Bridge public immutable zoraL1Bridge = OvmL1Bridge(0x3e2Ea9B92B7E48A52296fD261dc26fd995284631);
PolygonL1Bridge public immutable polygonL1Bridge = PolygonL1Bridge(0xA0c68C638235ee32657e8f720a23ceC1bFc77C77);
ZkSyncL1Bridge public immutable zkSyncL1Bridge = ZkSyncL1Bridge(0x32400084C286CF3E17e7B677ea9583e60a000324);
LineaL1MessageService public immutable lineaL1MessageService =
LineaL1MessageService(0xd19d4B5d358258f05D7B411E21A1460D11B0876F);

event ZkSyncEthDepositInitiated(address indexed from, address indexed to, uint256 amount);
event LineaEthDepositInitiated(address indexed from, address indexed to, uint256 amount);
event OvmEthDepositInitiated(uint256 indexed chainId, address indexed from, address indexed to, uint256 amount);

function bridgeWethToOvm(address to, uint256 amount, uint32 l2Gas, uint256 chainId) public {
weth.transferFrom(msg.sender, address(this), amount);
weth.withdraw(amount);

if (chainId == 10) {
optimismL1Bridge.depositETHTo{ value: amount }(to, l2Gas, "");
} else if (chainId == 8453) {
baseL1Bridge.depositETHTo{ value: amount }(to, l2Gas, "");
} else if (chainId == 34443) {
modeL1Bridge.depositETHTo{ value: amount }(to, l2Gas, "");
} else if (chainId == 1135) {
liskL1Bridge.depositETHTo{ value: amount }(to, l2Gas, "");
} else if (chainId == 81457) {
blastL1Bridge.depositETHTo{ value: amount }(to, l2Gas, "");
} else if (chainId == 690) {
redstoneL1Bridge.depositETHTo{ value: amount }(to, l2Gas, "");
} else if (chainId == 7777777) {
zoraL1Bridge.depositETHTo{ value: amount }(to, l2Gas, "");
} else if (chainId == 288) {
bobaL1Bridge.depositETHTo{ value: amount }(to, l2Gas, "");
} else {
revert("Invalid OVM chainId");
}

emit OvmEthDepositInitiated(chainId, msg.sender, to, amount);
}
///////////////////////////////
// Errors //
///////////////////////////////

error InvalidBridgeFunction();

///////////////////////////////
// Internal Functions //
///////////////////////////////

function bridgeWethToPolygon(address to, uint256 amount) public {
weth.transferFrom(msg.sender, address(this), amount);
weth.withdraw(amount);
polygonL1Bridge.depositEtherFor{ value: amount }(to);
/**
* @notice Transfers WETH to this contract and withdraws it to ETH.
* @param amount The amount of WETH to withdraw.
*/
function _withdrawWeth(uint256 amount) internal {
WETH.transferFrom(msg.sender, address(this), amount);
WETH.withdraw(amount);
}

function bridgeWethToLinea(address to, uint256 amount) public payable {
weth.transferFrom(msg.sender, address(this), amount);
weth.withdraw(amount);
lineaL1MessageService.sendMessage{ value: amount + msg.value }(to, msg.value, "");
// Emit an event that we can easily track in the Linea-related adapters/finalizers
emit LineaEthDepositInitiated(msg.sender, to, amount);
///////////////////////////////
// Admin Functions //
///////////////////////////////

/**
* @notice Whitelists function selector and bridge contract for chain.
* @param chainId The chain ID of the bridge.
* @param bridge The address of the bridge contract to call to bridge ETH to the chain.
* @param funcSelector The function selector of the bridge contract.
*/
function whitelistBridge(uint256 chainId, address bridge, bytes4 funcSelector) public onlyOwner {
whitelistedBridgeFunctions[chainId] = Bridge({ bridge: bridge, funcSelector: funcSelector });
}

function bridgeWethToZkSync(
address to,
uint256 amount,
uint256 l2GasLimit,
uint256 l2GasPerPubdataByteLimit,
address refundRecipient
) public {
// The ZkSync Mailbox contract checks that the msg.value of the transaction is enough to cover the transaction base
// cost. The transaction base cost can be queried from the Mailbox by passing in an L1 "executed" gas price,
// which is the priority fee plus base fee. This is the same as calling tx.gasprice on-chain as the Mailbox
// contract does here:
// https://github.com/matter-labs/era-contracts/blob/3a4506522aaef81485d8abb96f5a6394bd2ba69e/ethereum/contracts/zksync/facets/Mailbox.sol#L287
uint256 l2TransactionBaseCost = zkSyncL1Bridge.l2TransactionBaseCost(
tx.gasprice,
l2GasLimit,
l2GasPerPubdataByteLimit
);
uint256 valueToSubmitXChainMessage = l2TransactionBaseCost + amount;
weth.transferFrom(msg.sender, address(this), valueToSubmitXChainMessage);
weth.withdraw(valueToSubmitXChainMessage);
zkSyncL1Bridge.requestL2Transaction{ value: valueToSubmitXChainMessage }(
to,
amount,
"",
l2GasLimit,
l2GasPerPubdataByteLimit,
new bytes[](0),
refundRecipient
);

// Emit an event that we can easily track in the ZkSyncAdapter because otherwise there is no easy event to
// track ETH deposit initiations.
emit ZkSyncEthDepositInitiated(msg.sender, to, amount);
///////////////////////////////
// Public Functions //
///////////////////////////////

/**
* @notice Initiates a WETH deposit to a whitelisted bridge for a specified chain with user calldata.
* @dev Requires that the owner of this contract has whitelisted the bridge contract and function
* selector for the chainId that the user wants to send ETH to.
* @param value The amount of WETH to deposit.
* @param chainId The chain to send ETH to.
* @param bridgeCallData The calldata to pass to the bridge contract. The first 4 bytes should be equal
* to the whitelisted function selector of the bridge contract.
*/
function bridgeWeth(uint256 chainId, uint256 value, bytes calldata bridgeCallData) public nonReentrant {
_withdrawWeth(value);
Bridge memory bridge = whitelistedBridgeFunctions[chainId];
if (bridge.funcSelector != bytes4(bridgeCallData)) revert InvalidBridgeFunction();
// solhint-disable-next-line avoid-low-level-calls
(bool success, bytes memory result) = bridge.bridge.call{ value: value }(bridgeCallData);
require(success, string(result));
emit AtomicWethDepositInitiated(msg.sender, chainId, value);
}

fallback() external payable {}
Expand Down
41 changes: 27 additions & 14 deletions deployments/mainnet/AtomicWethDepositor.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"language": "Solidity",
"sources": {
"contracts/AtomicWethDepositor.sol": {
"content": "// SPDX-License-Identifier: GPL-3.0-only\npragma solidity ^0.8.0;\n\ninterface Weth {\n function withdraw(uint256 _wad) external;\n\n function transferFrom(address _from, address _to, uint256 _wad) external;\n}\n\ninterface OvmL1Bridge {\n function depositETHTo(address _to, uint32 _l2Gas, bytes calldata _data) external payable;\n}\n\ninterface PolygonL1Bridge {\n function depositEtherFor(address _to) external payable;\n}\n\ninterface ZkSyncL1Bridge {\n function requestL2Transaction(\n address _contractL2,\n uint256 _l2Value,\n bytes calldata _calldata,\n uint256 _l2GasLimit,\n uint256 _l2GasPerPubdataByteLimit,\n bytes[] calldata _factoryDeps,\n address _refundRecipient\n ) external payable;\n\n function l2TransactionBaseCost(\n uint256 _gasPrice,\n uint256 _l2GasLimit,\n uint256 _l2GasPerPubdataByteLimit\n ) external pure returns (uint256);\n}\n\ninterface LineaL1MessageService {\n function sendMessage(address _to, uint256 _fee, bytes calldata _calldata) external payable;\n}\n\n/**\n * @notice Contract deployed on Ethereum helps relay bots atomically unwrap and bridge WETH over the canonical chain\n * bridges for Optimism, Base, Boba, ZkSync, Linea, and Polygon. Needed as these chains only support bridging of ETH,\n * not WETH.\n */\n\ncontract AtomicWethDepositor {\n Weth public immutable weth = Weth(0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2);\n OvmL1Bridge public immutable optimismL1Bridge = OvmL1Bridge(0x99C9fc46f92E8a1c0deC1b1747d010903E884bE1);\n OvmL1Bridge public immutable modeL1Bridge = OvmL1Bridge(0x735aDBbE72226BD52e818E7181953f42E3b0FF21);\n OvmL1Bridge public immutable bobaL1Bridge = OvmL1Bridge(0xdc1664458d2f0B6090bEa60A8793A4E66c2F1c00);\n OvmL1Bridge public immutable baseL1Bridge = OvmL1Bridge(0x3154Cf16ccdb4C6d922629664174b904d80F2C35);\n OvmL1Bridge public immutable liskL1Bridge = OvmL1Bridge(0x2658723Bf70c7667De6B25F99fcce13A16D25d08);\n OvmL1Bridge public immutable redstoneL1Bridge = OvmL1Bridge(0xc473ca7E02af24c129c2eEf51F2aDf0411c1Df69);\n OvmL1Bridge public immutable blastL1Bridge = OvmL1Bridge(0x697402166Fbf2F22E970df8a6486Ef171dbfc524);\n OvmL1Bridge public immutable worldChainL1Bridge = OvmL1Bridge(0x470458C91978D2d929704489Ad730DC3E3001113);\n OvmL1Bridge public immutable zoraL1Bridge = OvmL1Bridge(0x3e2Ea9B92B7E48A52296fD261dc26fd995284631);\n PolygonL1Bridge public immutable polygonL1Bridge = PolygonL1Bridge(0xA0c68C638235ee32657e8f720a23ceC1bFc77C77);\n ZkSyncL1Bridge public immutable zkSyncL1Bridge = ZkSyncL1Bridge(0x32400084C286CF3E17e7B677ea9583e60a000324);\n LineaL1MessageService public immutable lineaL1MessageService =\n LineaL1MessageService(0xd19d4B5d358258f05D7B411E21A1460D11B0876F);\n\n event ZkSyncEthDepositInitiated(address indexed from, address indexed to, uint256 amount);\n event LineaEthDepositInitiated(address indexed from, address indexed to, uint256 amount);\n event OvmEthDepositInitiated(uint256 indexed chainId, address indexed from, address indexed to, uint256 amount);\n\n function bridgeWethToOvm(address to, uint256 amount, uint32 l2Gas, uint256 chainId) public {\n weth.transferFrom(msg.sender, address(this), amount);\n weth.withdraw(amount);\n\n if (chainId == 10) {\n optimismL1Bridge.depositETHTo{ value: amount }(to, l2Gas, \"\");\n } else if (chainId == 8453) {\n baseL1Bridge.depositETHTo{ value: amount }(to, l2Gas, \"\");\n } else if (chainId == 34443) {\n modeL1Bridge.depositETHTo{ value: amount }(to, l2Gas, \"\");\n } else if (chainId == 480) {\n worldChainL1Bridge.depositETHTo{ value: amount }(to, l2Gas, \"\");\n } else if (chainId == 1135) {\n liskL1Bridge.depositETHTo{ value: amount }(to, l2Gas, \"\");\n } else if (chainId == 81457) {\n blastL1Bridge.depositETHTo{ value: amount }(to, l2Gas, \"\");\n } else if (chainId == 690) {\n redstoneL1Bridge.depositETHTo{ value: amount }(to, l2Gas, \"\");\n } else if (chainId == 7777777) {\n zoraL1Bridge.depositETHTo{ value: amount }(to, l2Gas, \"\");\n } else if (chainId == 288) {\n bobaL1Bridge.depositETHTo{ value: amount }(to, l2Gas, \"\");\n } else {\n revert(\"Invalid OVM chainId\");\n }\n\n emit OvmEthDepositInitiated(chainId, msg.sender, to, amount);\n }\n\n function bridgeWethToPolygon(address to, uint256 amount) public {\n weth.transferFrom(msg.sender, address(this), amount);\n weth.withdraw(amount);\n polygonL1Bridge.depositEtherFor{ value: amount }(to);\n }\n\n function bridgeWethToLinea(address to, uint256 amount) public payable {\n weth.transferFrom(msg.sender, address(this), amount);\n weth.withdraw(amount);\n lineaL1MessageService.sendMessage{ value: amount + msg.value }(to, msg.value, \"\");\n // Emit an event that we can easily track in the Linea-related adapters/finalizers\n emit LineaEthDepositInitiated(msg.sender, to, amount);\n }\n\n function bridgeWethToZkSync(\n address to,\n uint256 amount,\n uint256 l2GasLimit,\n uint256 l2GasPerPubdataByteLimit,\n address refundRecipient\n ) public {\n // The ZkSync Mailbox contract checks that the msg.value of the transaction is enough to cover the transaction base\n // cost. The transaction base cost can be queried from the Mailbox by passing in an L1 \"executed\" gas price,\n // which is the priority fee plus base fee. This is the same as calling tx.gasprice on-chain as the Mailbox\n // contract does here:\n // https://github.com/matter-labs/era-contracts/blob/3a4506522aaef81485d8abb96f5a6394bd2ba69e/ethereum/contracts/zksync/facets/Mailbox.sol#L287\n uint256 l2TransactionBaseCost = zkSyncL1Bridge.l2TransactionBaseCost(\n tx.gasprice,\n l2GasLimit,\n l2GasPerPubdataByteLimit\n );\n uint256 valueToSubmitXChainMessage = l2TransactionBaseCost + amount;\n weth.transferFrom(msg.sender, address(this), valueToSubmitXChainMessage);\n weth.withdraw(valueToSubmitXChainMessage);\n zkSyncL1Bridge.requestL2Transaction{ value: valueToSubmitXChainMessage }(\n to,\n amount,\n \"\",\n l2GasLimit,\n l2GasPerPubdataByteLimit,\n new bytes[](0),\n refundRecipient\n );\n\n // Emit an event that we can easily track in the ZkSyncAdapter because otherwise there is no easy event to\n // track ETH deposit initiations.\n emit ZkSyncEthDepositInitiated(msg.sender, to, amount);\n }\n\n fallback() external payable {}\n\n // Included to remove a compilation warning.\n // NOTE: this should not affect behavior.\n receive() external payable {}\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 1000000
},
"viaIR": true,
"outputSelection": {
"*": {
"*": ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "metadata"],
"": ["ast"]
}
}
}
}
17 changes: 13 additions & 4 deletions index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import minimist from "minimist";
import { config, delay, exit, retrieveSignerFromCLIArgs, help, Logger, usage, waitForLogger } from "./src/utils";
import {
config,
delay,
exit,
retrieveSignerFromCLIArgs,
help,
Logger,
usage,
waitForLogger,
stringifyThrownValue,
} from "./src/utils";
import { runRelayer } from "./src/relayer";
import { runDataworker } from "./src/dataworker";
import { runMonitor } from "./src/monitor";
Expand Down Expand Up @@ -61,12 +71,11 @@ if (require.main === module) {
run(args)
.catch(async (error) => {
exitCode = 1;
const stringifiedError = stringifyThrownValue(error);
logger.error({
at: cmd ?? "unknown process",
message: "There was an execution error!",
reason: error,
e: error,
error,
error: stringifiedError,
args,
notificationPath: "across-error",
});
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@
"node": ">=20"
},
"dependencies": {
"@across-protocol/constants": "^3.1.14",
"@across-protocol/contracts": "^3.0.10",
"@across-protocol/sdk": "^3.2.0",
"@across-protocol/constants": "^3.1.19",
"@across-protocol/contracts": "^3.0.16",
"@across-protocol/sdk": "^3.2.13",
"@arbitrum/sdk": "^3.1.3",
"@aws-sdk/client-kms": "^3.592.0",
"@aws-sdk/client-s3": "^3.592.0",
Expand Down Expand Up @@ -43,6 +43,7 @@
"redis4": "npm:redis@^4.1.0",
"superstruct": "^1.0.3",
"ts-node": "^10.9.1",
"viem": "^2.21.18",
"winston": "^3.10.0",
"zksync-ethers": "^5.7.2"
},
Expand Down
Loading

0 comments on commit 9c1f9a5

Please sign in to comment.