Skip to content
This repository was archived by the owner on Oct 11, 2023. It is now read-only.

Commit 864546a

Browse files
committed
feat: daughter safe script
1 parent 76a0fa3 commit 864546a

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed

.env.example

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,15 @@ SAFE_SIGN_MESSAGE_LIB=0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2
1010
SAFE_MULTI_SEND=0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761
1111
DAI=0x6B175474E89094C44Da98b954EedeAC495271d0F
1212
WETH=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
13-
ETH_RPC_URL=http://erigon.dappnode:8545
13+
ETH_RPC_URL=http://erigon.dappnode:8545
14+
15+
SENDING_SAFE=0xA03be496e67Ec29bC62F01a428683D7F9c204930
16+
TARGET_SAFE=0x894BE31189AbDbf7491c5142b4BB0eAc04E932f3
17+
TWAP_TOTAL_SELL_AMOUNT=166183000000
18+
TWAP_TOTAL_MIN_BUY_AMOUNT=94892271000000000000
19+
TWAP_NUM_PARTS=5
20+
TWAP_SELL_TOKEN=0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
21+
TWAP_BUY_TOKEN=0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
22+
TWAP_RECEIVER=0xA03be496e67Ec29bC62F01a428683D7F9c204930
23+
TWAP_START_TIME=1677585900
24+
TWAP_FREQUENCY=3600

script/adhoc_DaughterSafeTWAP.sol

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
pragma solidity >=0.8.0 <0.9.0;
3+
4+
import "forge-std/Script.sol";
5+
6+
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7+
8+
import {CoWTWAPFallbackHandler} from "../src/CoWTWAPFallbackHandler.sol";
9+
import {GnosisSafe} from "safe/GnosisSafe.sol";
10+
import {Enum} from "safe/common/Enum.sol";
11+
import {FallbackManager} from "safe/base/FallbackManager.sol";
12+
import {SignMessageLib} from "safe/libraries/SignMessageLib.sol";
13+
import {MultiSend} from "safe/libraries/MultiSend.sol";
14+
15+
import {TWAPOrder} from "../src/libraries/TWAPOrder.sol";
16+
import {ConditionalOrderLib} from "../src/libraries/ConditionalOrderLib.sol";
17+
18+
import {CoWTWAPFallbackHandler} from "../src/CoWTWAPFallbackHandler.sol";
19+
20+
address constant FALLBACK_HANDLER = 0x87b52eD635DF746cA29651581B4d87517AAa9a9F; // deployer cow twap fallback handler
21+
22+
bytes32 constant DOMAIN_SEPARATOR = 0xc078f884a2676e1345748b1feace7b0abee5d00ecadb6e574dcdd109a63e8943; // settlement domain separator
23+
24+
contract DaughterSafeTWAP is Script {
25+
26+
address TARGET_SAFE = vm.envAddress("TARGET_SAFE");
27+
uint256 TOTAL_SELL_AMOUNT = vm.envUint("TWAP_TOTAL_SELL_AMOUNT");
28+
uint256 TOTAL_MIN_BUY_AMOUNT = vm.envUint("TWAP_TOTAL_MIN_BUY_AMOUNT");
29+
uint256 TWAP_NUM_PARTS = vm.envUint("TWAP_NUM_PARTS");
30+
31+
IERC20 TWAP_SELL_TOKEN = IERC20(vm.envAddress("TWAP_SELL_TOKEN"));
32+
33+
function run() external {
34+
address SENDING_SAFE = vm.envAddress("SENDING_SAFE");
35+
36+
TWAPOrder.Data memory twap = TWAPOrder.Data({
37+
sellToken: TWAP_SELL_TOKEN,
38+
buyToken: IERC20(vm.envAddress("TWAP_BUY_TOKEN")),
39+
receiver: address(vm.envOr("TWAP_RECEIVER", address(0))),
40+
partSellAmount: TOTAL_SELL_AMOUNT / TWAP_NUM_PARTS,
41+
minPartLimit: TOTAL_MIN_BUY_AMOUNT / TWAP_NUM_PARTS,
42+
t0: vm.envOr("TWAP_START_TIME", block.timestamp),
43+
n: TWAP_NUM_PARTS,
44+
t: vm.envOr("TWAP_FREQUENCY", uint256(3600)),
45+
span: 0
46+
});
47+
48+
bytes memory conditionalOrder = abi.encode(twap);
49+
// hash of the conditional order to sign
50+
bytes32 typedHash = ConditionalOrderLib.hash(conditionalOrder, DOMAIN_SEPARATOR);
51+
52+
bytes memory fallbackHandlerTx = abi.encodeWithSelector(
53+
FallbackManager.setFallbackHandler.selector,
54+
FALLBACK_HANDLER
55+
);
56+
57+
bytes memory signMessageTx = abi.encodeWithSelector(SignMessageLib.signMessage.selector, abi.encode(typedHash));
58+
59+
bytes memory approveTx = abi.encodeWithSelector(TWAP_SELL_TOKEN.approve.selector, vm.envAddress("RELAYER"), TOTAL_SELL_AMOUNT);
60+
61+
bytes memory dispatchTx = abi.encodeWithSelector(CoWTWAPFallbackHandler(address(TARGET_SAFE)).dispatch.selector, conditionalOrder);
62+
63+
// calldata to send multisend
64+
bytes memory cd = abi.encodeWithSelector(
65+
MultiSend.multiSend.selector,
66+
abi.encodePacked(
67+
// 1. sign the conditional order
68+
abi.encodePacked(
69+
uint8(Enum.Operation.DelegateCall),
70+
address(vm.envAddress("SAFE_SIGN_MESSAGE_LIB")),
71+
uint256(0), // value 0
72+
signMessageTx.length,
73+
signMessageTx
74+
),
75+
// 2. approve the tokens to be spent by the settlement contract
76+
abi.encodePacked(Enum.Operation.Call, address(TWAP_SELL_TOKEN), uint256(0), approveTx.length, approveTx),
77+
// 3. dispatch the conditional order
78+
abi.encodePacked(Enum.Operation.Call, address(TARGET_SAFE), uint256(0), dispatchTx.length, dispatchTx)
79+
)
80+
);
81+
82+
// declare a 65 byte array to store the signature
83+
bytes memory signature = new bytes(65);
84+
// set the first 32 bytes to the SENDING_SAFE address and set the last byte to 1
85+
assembly {
86+
mstore(add(signature, 32), SENDING_SAFE)
87+
mstore8(add(signature, 96), 1)
88+
}
89+
90+
bytes memory fallbackCd = abi.encodeWithSelector(
91+
GnosisSafe(payable(address(TARGET_SAFE))).execTransaction.selector,
92+
address(TARGET_SAFE),
93+
0,
94+
fallbackHandlerTx,
95+
Enum.Operation.Call,
96+
0,
97+
0,
98+
0,
99+
address(0),
100+
address(0),
101+
signature
102+
);
103+
104+
// get the calldata to send to the safe
105+
bytes memory safeCd = abi.encodeWithSelector(
106+
GnosisSafe(payable(address(TARGET_SAFE))).execTransaction.selector,
107+
address(vm.envAddress("SAFE_MULTI_SEND")),
108+
0,
109+
cd,
110+
Enum.Operation.DelegateCall,
111+
0,
112+
0,
113+
0,
114+
address(0),
115+
address(0),
116+
signature
117+
);
118+
119+
console.logString("setFallbackHandler calldata:");
120+
console.logBytes(fallbackCd);
121+
console.logString("multiSend calldata:");
122+
console.logBytes(safeCd);
123+
}
124+
}

0 commit comments

Comments
 (0)