Skip to content

Commit

Permalink
feat: launch contracts
Browse files Browse the repository at this point in the history
Signed-off-by: james-a-morris <[email protected]>
  • Loading branch information
james-a-morris committed Nov 6, 2024
1 parent e8921d7 commit 74e2db4
Show file tree
Hide file tree
Showing 20 changed files with 5,681 additions and 8 deletions.
30 changes: 30 additions & 0 deletions contracts/AlephZero_SpokePool.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// SPDX-License-Identifier: BUSL-1.1

// Arbitrum only supports v0.8.19
// See https://docs.arbitrum.io/for-devs/concepts/differences-between-arbitrum-ethereum/solidity-support#differences-from-solidity-on-ethereum
pragma solidity ^0.8.19;

import "./Arbitrum_SpokePool.sol";

/**
* @notice AVM specific SpokePool. Uses AVM cross-domain-enabled logic to implement admin only access to functions.
* @custom:security-contact [email protected]
*/
contract AlephZero_SpokePool is Arbitrum_SpokePool {
/// @custom:oz-upgrades-unsafe-allow constructor
constructor(
address _wrappedNativeTokenAddress,
uint32 _depositQuoteTimeBuffer,
uint32 _fillDeadlineBuffer,
IERC20 _l2Usdc,
ITokenMessenger _cctpTokenMessenger
)
Arbitrum_SpokePool(
_wrappedNativeTokenAddress,
_depositQuoteTimeBuffer,
_fillDeadlineBuffer,
_l2Usdc,
_cctpTokenMessenger
)
{} // solhint-disable-line no-empty-blocks
}
252 changes: 252 additions & 0 deletions contracts/external/Multicall3.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0; // Bumped version

/**
* This contract has been copied from the MD1/Multicall repository.
* @dev https://github.com/mds1/multicall/blob/ebd8b64457454fc10037b3a3ea858f9c08dad4d3/src/Multicall3.sol
* @dev changelog: pragma solidity ^0.8.12 -> pragma solidity ^0.8.0
**/

/// @title Multicall3
/// @notice Aggregate results from multiple function calls
/// @dev Multicall & Multicall2 backwards-compatible
/// @dev Aggregate methods are marked `payable` to save 24 gas per call
/// @author Michael Elliot <[email protected]>
/// @author Joshua Levine <[email protected]>
/// @author Nick Johnson <[email protected]>
/// @author Andreas Bigger <[email protected]>
/// @author Matt Solomon <[email protected]>
contract Multicall3 {
struct Call {
address target;
bytes callData;
}

struct Call3 {
address target;
bool allowFailure;
bytes callData;
}

struct Call3Value {
address target;
bool allowFailure;
uint256 value;
bytes callData;
}

struct Result {
bool success;
bytes returnData;
}

/// @notice Backwards-compatible call aggregation with Multicall
/// @param calls An array of Call structs
/// @return blockNumber The block number where the calls were executed
/// @return returnData An array of bytes containing the responses
function aggregate(Call[] calldata calls) public payable returns (uint256 blockNumber, bytes[] memory returnData) {
blockNumber = block.number;
uint256 length = calls.length;
returnData = new bytes[](length);
Call calldata call;
for (uint256 i = 0; i < length; ) {
bool success;
call = calls[i];
(success, returnData[i]) = call.target.call(call.callData);
require(success, "Multicall3: call failed");
unchecked {
++i;
}
}
}

/// @notice Backwards-compatible with Multicall2
/// @notice Aggregate calls without requiring success
/// @param requireSuccess If true, require all calls to succeed
/// @param calls An array of Call structs
/// @return returnData An array of Result structs
function tryAggregate(bool requireSuccess, Call[] calldata calls)
public
payable
returns (Result[] memory returnData)
{
uint256 length = calls.length;
returnData = new Result[](length);
Call calldata call;
for (uint256 i = 0; i < length; ) {
Result memory result = returnData[i];
call = calls[i];
(result.success, result.returnData) = call.target.call(call.callData);
if (requireSuccess) require(result.success, "Multicall3: call failed");
unchecked {
++i;
}
}
}

/// @notice Backwards-compatible with Multicall2
/// @notice Aggregate calls and allow failures using tryAggregate
/// @param calls An array of Call structs
/// @return blockNumber The block number where the calls were executed
/// @return blockHash The hash of the block where the calls were executed
/// @return returnData An array of Result structs
function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls)
public
payable
returns (
uint256 blockNumber,
bytes32 blockHash,
Result[] memory returnData
)
{
blockNumber = block.number;
blockHash = blockhash(block.number);
returnData = tryAggregate(requireSuccess, calls);
}

/// @notice Backwards-compatible with Multicall2
/// @notice Aggregate calls and allow failures using tryAggregate
/// @param calls An array of Call structs
/// @return blockNumber The block number where the calls were executed
/// @return blockHash The hash of the block where the calls were executed
/// @return returnData An array of Result structs
function blockAndAggregate(Call[] calldata calls)
public
payable
returns (
uint256 blockNumber,
bytes32 blockHash,
Result[] memory returnData
)
{
(blockNumber, blockHash, returnData) = tryBlockAndAggregate(true, calls);
}

/// @notice Aggregate calls, ensuring each returns success if required
/// @param calls An array of Call3 structs
/// @return returnData An array of Result structs
function aggregate3(Call3[] calldata calls) public payable returns (Result[] memory returnData) {
uint256 length = calls.length;
returnData = new Result[](length);
Call3 calldata calli;
for (uint256 i = 0; i < length; ) {
Result memory result = returnData[i];
calli = calls[i];
(result.success, result.returnData) = calli.target.call(calli.callData);
assembly {
// Revert if the call fails and failure is not allowed
// `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)`
if iszero(or(calldataload(add(calli, 0x20)), mload(result))) {
// set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)")))
mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
// set data offset
mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
// set length of revert string
mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017)
// set revert string: bytes32(abi.encodePacked("Multicall3: call failed"))
mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000)
revert(0x00, 0x64)
}
}
unchecked {
++i;
}
}
}

/// @notice Aggregate calls with a msg value
/// @notice Reverts if msg.value is less than the sum of the call values
/// @param calls An array of Call3Value structs
/// @return returnData An array of Result structs
function aggregate3Value(Call3Value[] calldata calls) public payable returns (Result[] memory returnData) {
uint256 valAccumulator;
uint256 length = calls.length;
returnData = new Result[](length);
Call3Value calldata calli;
for (uint256 i = 0; i < length; ) {
Result memory result = returnData[i];
calli = calls[i];
uint256 val = calli.value;
// Humanity will be a Type V Kardashev Civilization before this overflows - andreas
// ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256
unchecked {
valAccumulator += val;
}
(result.success, result.returnData) = calli.target.call{ value: val }(calli.callData);
assembly {
// Revert if the call fails and failure is not allowed
// `allowFailure := calldataload(add(calli, 0x20))` and `success := mload(result)`
if iszero(or(calldataload(add(calli, 0x20)), mload(result))) {
// set "Error(string)" signature: bytes32(bytes4(keccak256("Error(string)")))
mstore(0x00, 0x08c379a000000000000000000000000000000000000000000000000000000000)
// set data offset
mstore(0x04, 0x0000000000000000000000000000000000000000000000000000000000000020)
// set length of revert string
mstore(0x24, 0x0000000000000000000000000000000000000000000000000000000000000017)
// set revert string: bytes32(abi.encodePacked("Multicall3: call failed"))
mstore(0x44, 0x4d756c746963616c6c333a2063616c6c206661696c6564000000000000000000)
revert(0x00, 0x84)
}
}
unchecked {
++i;
}
}
// Finally, make sure the msg.value = SUM(call[0...i].value)
require(msg.value == valAccumulator, "Multicall3: value mismatch");
}

/// @notice Returns the block hash for the given block number
/// @param blockNumber The block number
function getBlockHash(uint256 blockNumber) public view returns (bytes32 blockHash) {
blockHash = blockhash(blockNumber);
}

/// @notice Returns the block number
function getBlockNumber() public view returns (uint256 blockNumber) {
blockNumber = block.number;
}

/// @notice Returns the block coinbase
function getCurrentBlockCoinbase() public view returns (address coinbase) {
coinbase = block.coinbase;
}

/// @notice Returns the block difficulty
function getCurrentBlockDifficulty() public view returns (uint256 difficulty) {
difficulty = block.difficulty;
}

/// @notice Returns the block gas limit
function getCurrentBlockGasLimit() public view returns (uint256 gaslimit) {
gaslimit = block.gaslimit;
}

/// @notice Returns the block timestamp
function getCurrentBlockTimestamp() public view returns (uint256 timestamp) {
timestamp = block.timestamp;
}

/// @notice Returns the (ETH) balance of a given address
function getEthBalance(address addr) public view returns (uint256 balance) {
balance = addr.balance;
}

/// @notice Returns the block hash of the last block
function getLastBlockHash() public view returns (bytes32 blockHash) {
unchecked {
blockHash = blockhash(block.number - 1);
}
}

/// @notice Gets the base fee of the given block
/// @notice Can revert if the BASEFEE opcode is not implemented by the given chain
function getBasefee() public view returns (uint256 basefee) {
basefee = block.basefee;
}

/// @notice Returns the chain id
function getChainId() public view returns (uint256 chainid) {
chainid = block.chainid;
}
}
30 changes: 30 additions & 0 deletions deploy/054_deploy_alephzero_spokepool.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { DeployFunction } from "hardhat-deploy/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";
import { deployNewProxy, getSpokePoolDeploymentInfo } from "../utils/utils.hre";
import { FILL_DEADLINE_BUFFER, L2_ADDRESS_MAP, QUOTE_TIME_BUFFER, WAZERO, ZERO_ADDRESS } from "./consts";

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { hubPool, spokeChainId } = await getSpokePoolDeploymentInfo(hre);

const initArgs = [
0,
L2_ADDRESS_MAP[spokeChainId].l2GatewayRouter,
// Set hub pool as cross domain admin since it delegatecalls the Adapter logic.
hubPool.address,
hubPool.address,
];

const constructorArgs = [
WAZERO[spokeChainId],
QUOTE_TIME_BUFFER,
FILL_DEADLINE_BUFFER,
ZERO_ADDRESS,
// L2_ADDRESS_MAP[spokeChainId].cctpTokenMessenger,
// For now, we are not using the CCTP bridge and can disable by setting
// the cctpTokenMessenger to the zero address.
ZERO_ADDRESS,
];
await deployNewProxy("AlephZero_SpokePool", constructorArgs, initArgs);
};
module.exports = func;
func.tags = ["AlephZeroSpokePool", "alephzero"];
19 changes: 19 additions & 0 deletions deploy/055_deploy_multicall3.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { DeployFunction } from "hardhat-deploy/types";
import { HardhatRuntimeEnvironment } from "hardhat/types";

const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const { deployer } = await hre.getNamedAccounts();

// @note if deploying this contract on a chain like Linea that only supports up to
// solc 0.8.19, the hardhat.config solc version needs to be overridden and this
// contract needs to be recompiled.
await hre.deployments.deploy("Multicall3", {
contract: "Multicall3",
from: deployer,
log: true,
skipIfAlreadyDeployed: true,
args: [],
});
};
module.exports = func;
func.tags = ["Multicall3"];
7 changes: 5 additions & 2 deletions deploy/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { CHAIN_IDs, TOKEN_SYMBOLS_MAP } from "../utils";
export const USDC = TOKEN_SYMBOLS_MAP.USDC.addresses;
export const WETH = TOKEN_SYMBOLS_MAP.WETH.addresses;
export const WMATIC = TOKEN_SYMBOLS_MAP.WMATIC.addresses;
export const WAZERO = TOKEN_SYMBOLS_MAP.WAZERO.addresses;
export const AZERO = TOKEN_SYMBOLS_MAP.AZERO;

export const QUOTE_TIME_BUFFER = 3600;
export const FILL_DEADLINE_BUFFER = 6 * 3600;
export const ARBITRUM_MAX_SUBMISSION_COST = "10000000000000000";
export const AZERO_GAS_PRICE = "240000000000";
export const MOCK_ADMIN = "0x9A8f92a830A5cB89a3816e3D267CB7791c16b04D";

export const L1_ADDRESS_MAP: { [key: number]: { [contractName: string]: string } } = {
[CHAIN_IDs.MAINNET]: {
Expand Down Expand Up @@ -54,7 +54,7 @@ export const L1_ADDRESS_MAP: { [key: number]: { [contractName: string]: string }
worldChainStandardBridge: "0x470458C91978D2d929704489Ad730DC3E3001113",
l1AlephZeroInbox: "0x56D8EC76a421063e1907503aDd3794c395256AEb",
l1AlephZeroERC20GatewayRouter: "0xeBb17f398ed30d02F2e8733e7c1e5cf566e17812",
donationBox: "0x90285a96F5955A7279EF0C1e89A1B4f66d8E4dA7",
donationBox: "0x0d57392895Db5aF3280e9223323e20F3951E81B1",
},
[CHAIN_IDs.SEPOLIA]: {
optimismCrossDomainMessenger: "0x58Cc85b8D04EA49cC6DBd3CbFFd00B4B8D6cb3ef",
Expand Down Expand Up @@ -97,6 +97,9 @@ export const L1_ADDRESS_MAP: { [key: number]: { [contractName: string]: string }
};

export const L2_ADDRESS_MAP: { [key: number]: { [contractName: string]: string } } = {
[CHAIN_IDs.ALEPH_ZERO]: {
l2GatewayRouter: "0xD296d45171B97720D3aBdb68B0232be01F1A9216",
},
[CHAIN_IDs.ARBITRUM_SEPOLIA]: {
l2GatewayRouter: "0x9fDD1C4E4AA24EEc1d913FABea925594a20d43C7",
cctpTokenMessenger: "0x9f3B8679c73C2Fef8b59B4f3444d4e156fb70AA5",
Expand Down
7 changes: 7 additions & 0 deletions deployments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,10 @@ This is because this `deployments.json` file is used by bots in [`@across-protoc
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| WorldChain_SpokePool | [0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64](https://worldchain-mainnet.explorer.alchemy.com/address/0x09aea4b2242abC8bb4BB78D537A67a245A7bEC64) |
| MulticallHandler | [0x924a9f036260DdD5808007E1AA95f08eD08aA569](https://worldchain-mainnet.explorer.alchemy.com/address/0x924a9f036260DdD5808007E1AA95f08eD08aA569) |

## AlephZero mainnet (41455)

| Contract Name | Address |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| AlephZero_SpokePool | [0x13fDac9F9b4777705db45291bbFF3c972c6d1d97](https://evm-explorer.alephzero.org/address/0x13fDac9F9b4777705db45291bbFF3c972c6d1d97) |
| MulticallHandler | [0x924a9f036260DdD5808007E1AA95f08eD08aA569](https://evm-explorer.alephzero.org/address/0x924a9f036260DdD5808007E1AA95f08eD08aA569) |
1 change: 1 addition & 0 deletions deployments/alephzero/.chainId
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
41455
Loading

0 comments on commit 74e2db4

Please sign in to comment.