Skip to content

Commit 7a2c767

Browse files
shahtheprosparrowDomnaddison36
authored
Cross-chain Strategy (#2715)
* some scaffolding * add basic necessities for unit tests * checkpoint * Fix compiling issues * Add fork test scaffolding * Fix stuffs * Prettify and change salt * Add auto-verification * Fix checkBalance * Make CCTPHookWrapper more resilient * refactor message version and type checks * add some comments * add comment * fix compile errors * Change addresses * Cross chain changes (#2718) * fix deploy files * minor rename * add calls to Morpho Vault into a try catch * refactor hook wrapper * don't revert if withdraw from underlying fails * use checkBalance for deposit/withdrawal acknowledgment * update message in remote strategy * remove unneeded functions * Fix compilation issues * Fix deployment files a bit * Fix Message relayer * Clean up master strategy * Fix deployment file name * move around stuff * Fix CCTP Integrator * clean up fork * Fix race condition (#2720) * Fix race condition * Transfer everything on wtihdrawal * Move destination domain one step above * Cleanup code * decode payloads in fork tests * Add library for message handling * More changes * Add comments and prettify * WIP Unit test setup (#2722) * add cross chain unit test basic files * add basic unit test setup * add header encoding * more tests * Add more fork tests * Add token transfer tests * WIP Unit tests for OUSD Simplified strategy (#2724) * more unit test integration * more tying up ends * fix bug * cleanup * add full round-trip test * cleanup * Fix approve all and prettify --------- Co-authored-by: Shahul Hameed <10547529+shahthepro@users.noreply.github.com> * Fix master fork tests * linter * add direct withdrawal paths and additional checks * Fix Remote strategy tests * Update comments and clean up code * Fix comment * Fix failing unit test * fix: withdraw only if balance is lower than requested amount * Document crosschain strategy * Update deployment file numbers * adjust the charts * change the function visibility to pure * fix: create2 proxy without using deployer address * fix: impersonate a single deployer on fork * deploy script bug fix * Store create2 proxy addresses * fix: await * more logging * fix opts * Fix env for deploy action * Change writeFileSync to writeFile * add log * Add more logs * fix callback * Add empty file * Cleanup logs * withdraw funds according to the spec * Address Code Review comments (#2732) * Address Code Review comments * Fix initialize method * Fix initialize method * fix remote strat initialize method * Revert 999 * fix comments * add a test that uncovers a withdrawal error (#2733) * remove transferType * correct spelling * rename baseToken to usdcToken * improve error message * simplify code * fix: min withdraw amount is 1e6 * add validations for config * fix: require a min deposit amount of 1e6 * fix: withdrawAll caps withdraw amount * Move around constants * Move decode message header function * fix fork tests * prettify * adjust some comments * have consistent event names * fix: remove redundant check * simplify stuff * adjust comment * fix: variable name * Add TokensBridged and MessageTransmitted events * Add finality threshold checks * add comment regarding fast transfers * Add analytics info * Change error message * Set 1 USDC as min allowed value for deposits * Change comment * Change comment * Update max transfer amount comment * Set nonce(0) as processed during initialization * Use Strategizable for strategist functionality (#2740) * use Strategizable * Add comment --------- Co-authored-by: Shahul Hameed <10547529+shahthepro@users.noreply.github.com> * set vault address to zero (#2742) * remove unnecessary comments * Add comment * Add nonReentrant for deposit and withdraw methods * Add more checks in constructor * Fix withdrawAll * Update deploy numbers * simplify _withdraw (#2741) * address verification (#2749) * add address verification * remove operator check * Fix merge issue * small adjustement * fix unit test * Bumped the deploy script numbers * remove unused parameter (#2754) * Add unit tests (#2751) * fix unit test * add more unit tests * add more unit tests * prettier * add some more unit tests * add thorough unit test support * Default to Timelock governance * lint * Fix VaultAddress in deployment scripts * Add events for nonce updates (#2755) * Sparrow dom/cctp defender action (#2770) * Add unit tests (#2751) * fix unit test * add more unit tests * add more unit tests * prettier * add some more unit tests * add thorough unit test support * add comment * create a defender task and cleanup * small change * add the ability for the defender relay action to store already processed transactions * update gitignore * prettier * put into a better place * ... * add dry run option, also fix issues with cross chain providers * read cctp domain ids from config * make api a constant * remove finality checks * add custom per chain block lookback * readme change * move all configuration out of cross-chain source file, to more easily support multiple networks and relaying directions * clear the testing addresses * prettier * add test address * add the option not to initialize the implementation contract * Prettify * add comment (#2787) * ignore messages that are too old (#2786) * [OUSD-09] Check burnToken in relay method (#2782) * [OUSD-09] Check burnToken in relay method * Fix: Check burn token is usdc on remote chain * Add tests * Make min transfer amount a constant (#2780) * [OUSD-15] Emit event when withdrawAll is skipped (#2781) --------- Co-authored-by: Domen Grabec <grabec@gmail.com> Co-authored-by: Nicholas Addison <nick@addisonbrown.com.au>
1 parent 766c645 commit 7a2c767

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+6466
-9
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ contracts/dist/
6363
contracts/.localKeyValueStorage
6464
contracts/.localKeyValueStorage.mainnet
6565
contracts/.localKeyValueStorage.holesky
66+
contracts/.localKeyValueStorage.base
6667
contracts/scripts/defender-actions/dist/
6768

6869
contracts/lib/defender-actions/dist/

contracts/.solhintignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
node_modules
2-
contracts/interfaces/morpho/Types.sol
2+
contracts/interfaces/morpho/Types.sol
3+
contracts/mocks/**/*.sol

contracts/README.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,12 @@ pnpm hardhat updateAction --id f92ea662-fc34-433b-8beb-b34e9ab74685 --file sonic
370370
pnpm hardhat updateAction --id b1d831f1-29d4-4943-bb2e-8e625b76e82c --file claimBribes
371371
pnpm hardhat updateAction --id 6567d7c6-7ec7-44bd-b95b-470dd1ff780b --file manageBribeOnSonic
372372
pnpm hardhat updateAction --id 6a633bb0-aff8-4b37-aaae-b4c6f244ed87 --file managePassThrough
373-
pnpm hardhat updateAction --id 076c59e4-4150-42c7-9ba0-9962069ac353 --file manageBribes
373+
pnpm hardhat updateAction --id 076c59e4-4150-42c7-9ba0-9962069ac353 --file manageBribes
374+
# These are Base -> Mainnet & Mainnet -> Base actions
375+
# they share the codebase. The direction of relaying attestations is defined by the
376+
# network of the relayer that is attached to the action
377+
pnpm hardhat updateAction --id bb43e5da-f936-4185-84da-253394583665 --file crossChainRelay
378+
pnpm hardhat updateAction --id e571409b-5399-48e4-bfb2-50b7af9903aa --file crossChainRelay
374379
```
375380

376381
`rollup` can be installed globally to avoid the `npx` prefix.

contracts/abi/createx.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,30 @@
2323
"stateMutability": "payable",
2424
"type": "function"
2525
},
26+
{
27+
"inputs": [
28+
{
29+
"internalType": "bytes32",
30+
"name": "salt",
31+
"type": "bytes32"
32+
},
33+
{
34+
"internalType": "bytes",
35+
"name": "initCode",
36+
"type": "bytes"
37+
}
38+
],
39+
"name": "deployCreate3",
40+
"outputs": [
41+
{
42+
"internalType": "address",
43+
"name": "newContract",
44+
"type": "address"
45+
}
46+
],
47+
"stateMutability": "payable",
48+
"type": "function"
49+
},
2650
{
2751
"inputs": [
2852
{

contracts/contracts/governance/Strategizable.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ contract Strategizable is Governable {
1515
/**
1616
* @dev Verifies that the caller is either Governor or Strategist.
1717
*/
18-
modifier onlyGovernorOrStrategist() {
18+
modifier onlyGovernorOrStrategist() virtual {
1919
require(
2020
msg.sender == strategistAddr || isGovernor(),
2121
"Caller is not the Strategist or Governor"
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.0;
3+
4+
interface ICCTPTokenMessenger {
5+
function depositForBurn(
6+
uint256 amount,
7+
uint32 destinationDomain,
8+
bytes32 mintRecipient,
9+
address burnToken,
10+
bytes32 destinationCaller,
11+
uint256 maxFee,
12+
uint32 minFinalityThreshold
13+
) external;
14+
15+
function depositForBurnWithHook(
16+
uint256 amount,
17+
uint32 destinationDomain,
18+
bytes32 mintRecipient,
19+
address burnToken,
20+
bytes32 destinationCaller,
21+
uint256 maxFee,
22+
uint32 minFinalityThreshold,
23+
bytes memory hookData
24+
) external;
25+
26+
function getMinFeeAmount(uint256 amount) external view returns (uint256);
27+
}
28+
29+
interface ICCTPMessageTransmitter {
30+
function sendMessage(
31+
uint32 destinationDomain,
32+
bytes32 recipient,
33+
bytes32 destinationCaller,
34+
uint32 minFinalityThreshold,
35+
bytes memory messageBody
36+
) external;
37+
38+
function receiveMessage(bytes calldata message, bytes calldata attestation)
39+
external
40+
returns (bool);
41+
}
42+
43+
interface IMessageHandlerV2 {
44+
/**
45+
* @notice Handles an incoming finalized message from an IReceiverV2
46+
* @dev Finalized messages have finality threshold values greater than or equal to 2000
47+
* @param sourceDomain The source domain of the message
48+
* @param sender The sender of the message
49+
* @param finalityThresholdExecuted the finality threshold at which the message was attested to
50+
* @param messageBody The raw bytes of the message body
51+
* @return success True, if successful; false, if not.
52+
*/
53+
function handleReceiveFinalizedMessage(
54+
uint32 sourceDomain,
55+
bytes32 sender,
56+
uint32 finalityThresholdExecuted,
57+
bytes calldata messageBody
58+
) external returns (bool);
59+
60+
/**
61+
* @notice Handles an incoming unfinalized message from an IReceiverV2
62+
* @dev Unfinalized messages have finality threshold values less than 2000
63+
* @param sourceDomain The source domain of the message
64+
* @param sender The sender of the message
65+
* @param finalityThresholdExecuted The finality threshold at which the message was attested to
66+
* @param messageBody The raw bytes of the message body
67+
* @return success True, if successful; false, if not.
68+
*/
69+
function handleReceiveUnfinalizedMessage(
70+
uint32 sourceDomain,
71+
bytes32 sender,
72+
uint32 finalityThresholdExecuted,
73+
bytes calldata messageBody
74+
) external returns (bool);
75+
}
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
// SPDX-License-Identifier: BUSL-1.1
2+
pragma solidity ^0.8.0;
3+
4+
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
5+
import { IERC4626 } from "../../lib/openzeppelin/interfaces/IERC4626.sol";
6+
import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
7+
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
8+
9+
contract MockERC4626Vault is IERC4626, ERC20 {
10+
using SafeERC20 for IERC20;
11+
12+
address public asset;
13+
uint8 public constant DECIMALS = 18;
14+
15+
constructor(address _asset) ERC20("Mock Vault Share", "MVS") {
16+
asset = _asset;
17+
}
18+
19+
// ERC20 totalSupply is inherited
20+
21+
// ERC20 balanceOf is inherited
22+
23+
function deposit(uint256 assets, address receiver)
24+
public
25+
override
26+
returns (uint256 shares)
27+
{
28+
shares = previewDeposit(assets);
29+
IERC20(asset).safeTransferFrom(msg.sender, address(this), assets);
30+
_mint(receiver, shares);
31+
return shares;
32+
}
33+
34+
function mint(uint256 shares, address receiver)
35+
public
36+
override
37+
returns (uint256 assets)
38+
{
39+
assets = previewMint(shares);
40+
IERC20(asset).safeTransferFrom(msg.sender, address(this), assets);
41+
_mint(receiver, shares);
42+
return assets;
43+
}
44+
45+
function withdraw(
46+
uint256 assets,
47+
address receiver,
48+
address owner
49+
) public override returns (uint256 shares) {
50+
shares = previewWithdraw(assets);
51+
if (msg.sender != owner) {
52+
// No approval check for mock
53+
}
54+
_burn(owner, shares);
55+
IERC20(asset).safeTransfer(receiver, assets);
56+
return shares;
57+
}
58+
59+
function redeem(
60+
uint256 shares,
61+
address receiver,
62+
address owner
63+
) public override returns (uint256 assets) {
64+
assets = previewRedeem(shares);
65+
if (msg.sender != owner) {
66+
// No approval check for mock
67+
}
68+
_burn(owner, shares);
69+
IERC20(asset).safeTransfer(receiver, assets);
70+
return assets;
71+
}
72+
73+
function totalAssets() public view override returns (uint256) {
74+
return IERC20(asset).balanceOf(address(this));
75+
}
76+
77+
function convertToShares(uint256 assets)
78+
public
79+
view
80+
override
81+
returns (uint256 shares)
82+
{
83+
uint256 supply = totalSupply(); // Use ERC20 totalSupply
84+
return
85+
supply == 0 || assets == 0
86+
? assets
87+
: (assets * supply) / totalAssets();
88+
}
89+
90+
function convertToAssets(uint256 shares)
91+
public
92+
view
93+
override
94+
returns (uint256 assets)
95+
{
96+
uint256 supply = totalSupply(); // Use ERC20 totalSupply
97+
return supply == 0 ? shares : (shares * totalAssets()) / supply;
98+
}
99+
100+
function maxDeposit(address receiver)
101+
public
102+
view
103+
override
104+
returns (uint256)
105+
{
106+
return type(uint256).max;
107+
}
108+
109+
function maxMint(address receiver) public view override returns (uint256) {
110+
return type(uint256).max;
111+
}
112+
113+
function maxWithdraw(address owner) public view override returns (uint256) {
114+
return convertToAssets(balanceOf(owner));
115+
}
116+
117+
function maxRedeem(address owner) public view override returns (uint256) {
118+
return balanceOf(owner);
119+
}
120+
121+
function previewDeposit(uint256 assets)
122+
public
123+
view
124+
override
125+
returns (uint256 shares)
126+
{
127+
return convertToShares(assets);
128+
}
129+
130+
function previewMint(uint256 shares)
131+
public
132+
view
133+
override
134+
returns (uint256 assets)
135+
{
136+
return convertToAssets(shares);
137+
}
138+
139+
function previewWithdraw(uint256 assets)
140+
public
141+
view
142+
override
143+
returns (uint256 shares)
144+
{
145+
return convertToShares(assets);
146+
}
147+
148+
function previewRedeem(uint256 shares)
149+
public
150+
view
151+
override
152+
returns (uint256 assets)
153+
{
154+
return convertToAssets(shares);
155+
}
156+
157+
function _mint(address account, uint256 amount) internal override {
158+
super._mint(account, amount);
159+
}
160+
161+
function _burn(address account, uint256 amount) internal override {
162+
super._burn(account, amount);
163+
}
164+
165+
// Inherited from ERC20
166+
}

0 commit comments

Comments
 (0)