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

WIP: Unichain #259

Draft
wants to merge 8 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ Master list of UniV3 forks:
* Add `DODOV1` action to Mantle
* Add `DODOV1` action to Polygon
* Add `DODOV1` action to Scroll
* Deploy Settler to Unichain network
* Add UniswapV3 UniV3 fork to Unichain

## 2024-12-12

Expand Down
24 changes: 19 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ your integration.

* `0x0000000000001fF3684f28c67538d4D072C22734` on chains supporting the Cancun
hardfork (Ethereum Mainnet, Ethereum Sepolia, Polygon, Base, Optimism,
Arbitrum, Blast, Bnb, Mode, World Chain, Gnosis)
Arbitrum, Blast, Bnb, Mode, World Chain, Gnosis, Unichain)
* `0x0000000000005E88410CcDFaDe4a5EfaE4b49562` on chains supporting the Shanghai
hardfork (Avalanche, Scroll, Mantle, Taiko)
* `0x000000000000175a8b9bC6d539B3708EEd92EA6c` on chains supporting the London
Expand Down Expand Up @@ -1359,26 +1359,40 @@ of its receipt.

</details>

Third, you need have enough native asset in each of the deployer addresses
Third, create a new `src/chains/<CHAIN_DISPLAY_NAME>.sol` file. A good way to
start is by copying [`src/chains/Sepolia.sol`](src/chains/Sepolia.sol). You'll
need to change the names of all the contracts, remove references to missing
liquidity sources (presently MaverickV2), replace the `block.chainid` check in
the constructor, and replace the UniswapV3 forks. When adding new UniswapV3
forks, be sure that the `factory` address is the address of the contract that
`CREATE2`'s the pool. Triple check that the deployed pools aren't upgradeable
proxies and that the `data` argument is passed through the callback
unmodified. _**This is critical for security.**_ Some chains have a form of
sequencer fee sharing or other chain-specific deploy-time setup. Configure this
in the constructor of the Settler (and ideally in the constructor of the
Deployer, remembering that this is complicated by the fact that the Deployer is
a proxy). See the deployments to Blast and to Mode for examples.

Fourth, you need have enough native asset in each of the deployer addresses
listed in [`secrets.json.template`](secrets.json.template) to perform the
deployment. If how much isn't obvious to you, you can run the main deployment
script with `BROADCAST=no` to simulate. This can be a little wonky on L2s, so
beware and overprovision the amount of native asset.

Fourth, deploy `AllowanceHolder`. Obviously, if you're deploying to a
Fifth, deploy `AllowanceHolder`. Obviously, if you're deploying to a
Cancun-supporting chain, you don't need to fund the deployer for the old
`AllowanceHolder` (and vice versa). Run [`./sh/deploy_allowanceholder.sh
<CHAIN_NAME>`](sh/deploy_allowanceholder.sh). Note that
`deploy_allowanceholder.sh` doesn't give you a chance to back out. There is no
prompt, it just deploys `AllowanceHolder`.

Fifth, check that the Safe deployment on the new chain is complete. You can
Sixth, check that the Safe deployment on the new chain is complete. You can
check this by running the main deployment script with `BROADCAST=no`. If it
completes without reverting, you don't need to do anything. If the Safe
deployment on the new chain is incomplete, run [`./sh/deploy_safe_infra.sh
<CHAIN_NAME>`](sh/deploy_safe_infra.sh). You will have to modify this script.

Sixth, make _damn_ sure that you've got the correct configuration in
Seventh, make _damn_ sure that you've got the correct configuration in
[`chain_config.json`](chain_config.json). If you screw this up, you'll burn the
vanity address. Run [`BROADCAST=no ./sh/deploy_new_chain.sh
<CHAIN_NAME>`](sh/deploy_new_chain.sh) a bunch of times. Deploy to a
Expand Down
4 changes: 4 additions & 0 deletions api_secrets.json.template
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,9 @@
"gnosis": {
"rpcUrl": "",
"etherscanKey": ""
},
"unichain": {
"etherscanKey": "",
"rpcUrl": ""
}
}
26 changes: 26 additions & 0 deletions chain_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -414,5 +414,31 @@
"allowanceHolder": "0x0000000000001fF3684f28c67538d4D072C22734"
},
"etherscanApi": "https://api.gnosisscan.io/api"
},
"unichain": {
"chainId": 130,
"displayName": "Unichain",
"isShanghai": true,
"isCancun": true,
"extraFlags": "--legacy",
"gasMultiplierPercent": 200,
"minGasPriceGwei": 1,
"safe": {
"singleton": null,
"factory": null,
"fallback": null,
"multiCall": null,
"apiUrl": "NOT SUPPORTED"
},
"governance": {
"upgradeSafe": null,
"deploymentSafe": null,
"pause": "0x1CeC01DC0fFEE5eB5aF47DbEc1809F2A7c601C30"
},
"deployment": {
"allowanceHolder": "0x0000000000001fF3684f28c67538d4D072C22734",
"deployer": "0x00000000000004533Fe15556B1E086BB1A72cEae"
},
"etherscanApi": "https://api.uniscan.xyz/api"
}
}
2 changes: 2 additions & 0 deletions script/SafeConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ library SafeConfig {
|| block.chainid == 10 // optimism
|| block.chainid == 56 // bnb
|| block.chainid == 100 // gnosis
|| block.chainid == 130 // unichain
|| block.chainid == 137 // polygon
|| block.chainid == 480 // worldchain
|| block.chainid == 5000 // mantle
Expand All @@ -40,6 +41,7 @@ library SafeConfig {
block.chainid == 10 // optimism
|| block.chainid == 56 // bnb
|| block.chainid == 100 // gnosis
|| block.chainid == 130 // unichain
|| block.chainid == 137 // polygon
|| block.chainid == 480 // worldchain
|| block.chainid == 5000 // mantle
Expand Down
57 changes: 57 additions & 0 deletions src/chains/Unichain/Common.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.8.25;

import {SettlerBase} from "../../SettlerBase.sol";

import {IERC20} from "@forge-std/interfaces/IERC20.sol";
import {FreeMemory} from "../../utils/FreeMemory.sol";

import {ISettlerActions} from "../../ISettlerActions.sol";
import {ISignatureTransfer} from "@permit2/interfaces/ISignatureTransfer.sol";
import {UnknownForkId} from "../../core/SettlerErrors.sol";

import {
uniswapV3UnichainFactory,
uniswapV3InitHash,
uniswapV3ForkId,
IUniswapV3Callback
} from "../../core/univ3forks/UniswapV3.sol";

// Solidity inheritance is stupid
//import {SettlerAbstract} from "../../SettlerAbstract.sol";

abstract contract UnichainMixin is FreeMemory, SettlerBase {
constructor() {
assert(block.chainid == 130 || block.chainid == 31337);
}

function _dispatch(uint256 i, uint256 action, bytes calldata data)
internal
virtual
override(/* SettlerAbstract, */SettlerBase)
DANGEROUS_freeMemory
returns (bool)
{
if (super._dispatch(i, action, data)) {
return true;
} else {
return false;
}
return true;
}

function _uniV3ForkInfo(uint8 forkId)
internal
pure
override
returns (address factory, bytes32 initHash, uint32 callbackSelector)
{
if (forkId == uniswapV3ForkId) {
factory = uniswapV3UnichainFactory;
initHash = uniswapV3InitHash;
callbackSelector = uint32(IUniswapV3Callback.uniswapV3SwapCallback.selector);
} else {
revert UnknownForkId(forkId);
}
}
}
46 changes: 46 additions & 0 deletions src/chains/Unichain/MetaTxn.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.8.25;

import {UnichainMixin} from "./Common.sol";
import {SettlerMetaTxn} from "../../SettlerMetaTxn.sol";

import {IERC20} from "@forge-std/interfaces/IERC20.sol";
import {ISignatureTransfer} from "@permit2/interfaces/ISignatureTransfer.sol";
import {ISettlerActions} from "../../ISettlerActions.sol";

// Solidity inheritance is stupid
import {SettlerAbstract} from "../../SettlerAbstract.sol";
import {SettlerBase} from "../../SettlerBase.sol";
import {AbstractContext} from "../../Context.sol";

/// @custom:security-contact [email protected]
contract UnichainSettlerMetaTxn is SettlerMetaTxn, UnichainMixin {
constructor(bytes20 gitCommit) SettlerMetaTxn(gitCommit) {}

function _dispatchVIP(uint256 action, bytes calldata data, bytes calldata sig)
internal
override
DANGEROUS_freeMemory
returns (bool)
{
if (super._dispatchVIP(action, data, sig)) {
return true;
} else {
return false;
}
return true;
}

// Solidity inheritance is stupid
function _dispatch(uint256 i, uint256 action, bytes calldata data)
internal
override(SettlerAbstract, SettlerBase, UnichainMixin)
returns (bool)
{
return super._dispatch(i, action, data);
}

function _msgSender() internal view override(SettlerMetaTxn, AbstractContext) returns (address) {
return super._msgSender();
}
}
51 changes: 51 additions & 0 deletions src/chains/Unichain/TakerSubmitted.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// SPDX-License-Identifier: MIT
pragma solidity =0.8.25;

import {UnichainMixin} from "./Common.sol";
import {Settler} from "../../Settler.sol";

import {IERC20} from "@forge-std/interfaces/IERC20.sol";
import {ISignatureTransfer} from "@permit2/interfaces/ISignatureTransfer.sol";
import {ISettlerActions} from "../../ISettlerActions.sol";

// Solidity inheritance is stupid
import {SettlerAbstract} from "../../SettlerAbstract.sol";
import {SettlerBase} from "../../SettlerBase.sol";
import {Permit2PaymentAbstract} from "../../core/Permit2PaymentAbstract.sol";
import {AbstractContext} from "../../Context.sol";

/// @custom:security-contact [email protected]
contract UnichainSettler is Settler, UnichainMixin {
constructor(bytes20 gitCommit) Settler(gitCommit) {}

function _dispatchVIP(uint256 action, bytes calldata data) internal override DANGEROUS_freeMemory returns (bool) {
if (super._dispatchVIP(action, data)) {
return true;
} else {
return false;
}
return true;
}

// Solidity inheritance is stupid
function _isRestrictedTarget(address target)
internal
pure
override(Settler, Permit2PaymentAbstract)
returns (bool)
{
return super._isRestrictedTarget(target);
}

function _dispatch(uint256 i, uint256 action, bytes calldata data)
internal
override(SettlerAbstract, SettlerBase, UnichainMixin)
returns (bool)
{
return super._dispatch(i, action, data);
}

function _msgSender() internal view override(Settler, AbstractContext) returns (address) {
return super._msgSender();
}
}
1 change: 1 addition & 0 deletions src/core/univ3forks/UniswapV3.sol
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ address constant uniswapV3MantleFactory = 0x0d922Fb1Bc191F64970ac40376643808b4B7
address constant uniswapV3TaikoFactory = 0x75FC67473A91335B5b8F8821277262a13B38c9b3;
address constant uniswapV3WorldChainFactory = 0x7a5028BDa40e7B173C278C5342087826455ea25a;
address constant uniswapV3GnosisFactory = 0xe32F7dD7e3f098D518ff19A22d5f028e076489B1;
address constant uniswapV3UnichainFactory = 0x0000000000000000000000000000000000000000; // TODO: likely 0x1F98431c8aD98523631AE4a59f267346ea31F984, in which case remove this line and replace references with `uniswapV3MainnetFactory`
bytes32 constant uniswapV3InitHash = 0xe34f199b19b2b4f47f68442619d555527d244f78a3297ea89325f843f87b8b54;
uint8 constant uniswapV3ForkId = 0;

Expand Down
Loading