1+ import { expect } from "chai" ;
2+ import hre , { deployments , waffle } from "hardhat" ;
3+ import "@nomiclabs/hardhat-ethers" ;
4+ import { deployContract , getMock , getMultiSendCallOnly , getSafeWithOwners } from "../utils/setup" ;
5+ import { buildContractCall , buildSafeTransaction , executeTx , MetaTransaction , safeApproveHash } from "../utils/execution" ;
6+ import { buildMultiSendSafeTx } from "../utils/multisend" ;
7+ import { parseEther } from "@ethersproject/units" ;
8+
9+ describe ( "MultiSendCallOnly" , async ( ) => {
10+
11+ const [ user1 , user2 ] = waffle . provider . getWallets ( ) ;
12+
13+ const setupTests = deployments . createFixture ( async ( { deployments } ) => {
14+ await deployments . fixture ( ) ;
15+ const setterSource = `
16+ contract StorageSetter {
17+ function setStorage(bytes3 data) public {
18+ bytes32 slot = 0x4242424242424242424242424242424242424242424242424242424242424242;
19+ // solium-disable-next-line security/no-inline-assembly
20+ assembly {
21+ sstore(slot, data)
22+ }
23+ }
24+ }`
25+ const storageSetter = await deployContract ( user1 , setterSource ) ;
26+ return {
27+ safe : await getSafeWithOwners ( [ user1 . address ] ) ,
28+ multiSend : await getMultiSendCallOnly ( ) ,
29+ mock : await getMock ( ) ,
30+ storageSetter
31+ }
32+ } )
33+
34+ describe ( "multiSend" , async ( ) => {
35+
36+ it ( 'Should fail when using invalid operation' , async ( ) => {
37+ const { safe, multiSend } = await setupTests ( )
38+
39+ const txs = [ buildSafeTransaction ( { to : user2 . address , operation : 2 , nonce : 0 } ) ]
40+ const safeTx = buildMultiSendSafeTx ( multiSend , txs , await safe . nonce ( ) )
41+ await expect (
42+ executeTx ( safe , safeTx , [ await safeApproveHash ( user1 , safe , safeTx , true ) ] )
43+ ) . to . revertedWith ( "GS013" )
44+ } )
45+
46+ it ( 'Should fail when using delegatecall operation' , async ( ) => {
47+ const { safe, multiSend } = await setupTests ( )
48+
49+ const txs = [ buildSafeTransaction ( { to : user2 . address , operation : 1 , nonce : 0 } ) ]
50+ const safeTx = buildMultiSendSafeTx ( multiSend , txs , await safe . nonce ( ) )
51+ await expect (
52+ executeTx ( safe , safeTx , [ await safeApproveHash ( user1 , safe , safeTx , true ) ] )
53+ ) . to . revertedWith ( "GS013" )
54+ } )
55+
56+ it ( 'Can execute empty multisend' , async ( ) => {
57+ const { safe, multiSend } = await setupTests ( )
58+
59+ const txs : MetaTransaction [ ] = [ ]
60+ const safeTx = buildMultiSendSafeTx ( multiSend , txs , await safe . nonce ( ) )
61+ await expect (
62+ executeTx ( safe , safeTx , [ await safeApproveHash ( user1 , safe , safeTx , true ) ] )
63+ ) . to . emit ( safe , "ExecutionSuccess" )
64+ } )
65+
66+ it ( 'Can execute single ether transfer' , async ( ) => {
67+ const { safe, multiSend } = await setupTests ( )
68+ await user1 . sendTransaction ( { to : safe . address , value : parseEther ( "1" ) } )
69+ const userBalance = await hre . ethers . provider . getBalance ( user2 . address )
70+ await expect ( await hre . ethers . provider . getBalance ( safe . address ) ) . to . be . deep . eq ( parseEther ( "1" ) )
71+
72+ const txs : MetaTransaction [ ] = [ buildSafeTransaction ( { to : user2 . address , value : parseEther ( "1" ) , nonce : 0 } ) ]
73+ const safeTx = buildMultiSendSafeTx ( multiSend , txs , await safe . nonce ( ) )
74+ await expect (
75+ executeTx ( safe , safeTx , [ await safeApproveHash ( user1 , safe , safeTx , true ) ] )
76+ ) . to . emit ( safe , "ExecutionSuccess" )
77+
78+ await expect ( await hre . ethers . provider . getBalance ( safe . address ) ) . to . be . deep . eq ( parseEther ( "0" ) )
79+ await expect ( await hre . ethers . provider . getBalance ( user2 . address ) ) . to . be . deep . eq ( userBalance . add ( parseEther ( "1" ) ) )
80+ } )
81+
82+ it ( 'reverts all tx if any fails' , async ( ) => {
83+ const { safe, multiSend } = await setupTests ( )
84+ await user1 . sendTransaction ( { to : safe . address , value : parseEther ( "1" ) } )
85+ const userBalance = await hre . ethers . provider . getBalance ( user2 . address )
86+ await expect ( await hre . ethers . provider . getBalance ( safe . address ) ) . to . be . deep . eq ( parseEther ( "1" ) )
87+
88+ const txs : MetaTransaction [ ] = [
89+ buildSafeTransaction ( { to : user2 . address , value : parseEther ( "1" ) , nonce : 0 } ) ,
90+ buildSafeTransaction ( { to : user2 . address , value : parseEther ( "1" ) , nonce : 0 } ) ,
91+ ]
92+ const safeTx = buildMultiSendSafeTx ( multiSend , txs , await safe . nonce ( ) , { safeTxGas : 1 } )
93+ await expect (
94+ executeTx ( safe , safeTx , [ await safeApproveHash ( user1 , safe , safeTx , true ) ] )
95+ ) . to . emit ( safe , "ExecutionFailure" )
96+
97+ await expect ( await hre . ethers . provider . getBalance ( safe . address ) ) . to . be . deep . eq ( parseEther ( "1" ) )
98+ await expect ( await hre . ethers . provider . getBalance ( user2 . address ) ) . to . be . deep . eq ( userBalance )
99+ } )
100+
101+ it ( 'can be used when ETH is sent with execution' , async ( ) => {
102+ const { safe, multiSend, storageSetter } = await setupTests ( )
103+
104+ const txs : MetaTransaction [ ] = [
105+ buildContractCall ( storageSetter , "setStorage" , [ "0xbaddad" ] , 0 )
106+ ]
107+ const safeTx = buildMultiSendSafeTx ( multiSend , txs , await safe . nonce ( ) )
108+
109+ await expect ( await hre . ethers . provider . getBalance ( safe . address ) ) . to . be . deep . eq ( parseEther ( "0" ) )
110+
111+ await expect (
112+ executeTx ( safe , safeTx , [ await safeApproveHash ( user1 , safe , safeTx , true ) ] , { value : parseEther ( "1" ) } )
113+ ) . to . emit ( safe , "ExecutionSuccess" )
114+
115+ await expect ( await hre . ethers . provider . getBalance ( safe . address ) ) . to . be . deep . eq ( parseEther ( "1" ) )
116+ } )
117+
118+ it ( 'can execute contract calls' , async ( ) => {
119+ const { safe, multiSend, storageSetter } = await setupTests ( )
120+
121+ const txs : MetaTransaction [ ] = [
122+ buildContractCall ( storageSetter , "setStorage" , [ "0xbaddad" ] , 0 )
123+ ]
124+ const safeTx = buildMultiSendSafeTx ( multiSend , txs , await safe . nonce ( ) )
125+ await expect (
126+ executeTx ( safe , safeTx , [ await safeApproveHash ( user1 , safe , safeTx , true ) ] )
127+ ) . to . emit ( safe , "ExecutionSuccess" )
128+
129+ await expect (
130+ await hre . ethers . provider . getStorageAt ( safe . address , "0x4242424242424242424242424242424242424242424242424242424242424242" )
131+ ) . to . be . eq ( "0x" + "" . padEnd ( 64 , "0" ) )
132+ await expect (
133+ await hre . ethers . provider . getStorageAt ( storageSetter . address , "0x4242424242424242424242424242424242424242424242424242424242424242" )
134+ ) . to . be . eq ( "0x" + "baddad" . padEnd ( 64 , "0" ) )
135+ } )
136+
137+ it ( 'can execute combinations' , async ( ) => {
138+ const { safe, multiSend, storageSetter } = await setupTests ( )
139+ await user1 . sendTransaction ( { to : safe . address , value : parseEther ( "1" ) } )
140+ const userBalance = await hre . ethers . provider . getBalance ( user2 . address )
141+ await expect ( await hre . ethers . provider . getBalance ( safe . address ) ) . to . be . deep . eq ( parseEther ( "1" ) )
142+
143+ const txs : MetaTransaction [ ] = [
144+ buildSafeTransaction ( { to : user2 . address , value : parseEther ( "1" ) , nonce : 0 } ) ,
145+ buildContractCall ( storageSetter , "setStorage" , [ "0xbaddad" ] , 0 )
146+ ]
147+ const safeTx = buildMultiSendSafeTx ( multiSend , txs , await safe . nonce ( ) )
148+ await expect (
149+ executeTx ( safe , safeTx , [ await safeApproveHash ( user1 , safe , safeTx , true ) ] )
150+ ) . to . emit ( safe , "ExecutionSuccess" )
151+
152+ await expect ( await hre . ethers . provider . getBalance ( safe . address ) ) . to . be . deep . eq ( parseEther ( "0" ) )
153+ await expect ( await hre . ethers . provider . getBalance ( user2 . address ) ) . to . be . deep . eq ( userBalance . add ( parseEther ( "1" ) ) )
154+ await expect (
155+ await hre . ethers . provider . getStorageAt ( safe . address , "0x4242424242424242424242424242424242424242424242424242424242424242" )
156+ ) . to . be . eq ( "0x" + "" . padEnd ( 64 , "0" ) )
157+ await expect (
158+ await hre . ethers . provider . getStorageAt ( storageSetter . address , "0x4242424242424242424242424242424242424242424242424242424242424242" )
159+ ) . to . be . eq ( "0x" + "baddad" . padEnd ( 64 , "0" ) )
160+ } )
161+ } )
162+ } )
0 commit comments