1+ import { ethers } from "hardhat" ;
2+ import { expect } from "chai" ;
3+ import { Contract , Signer , ZeroAddress } from "ethers" ;
4+ import { Safe , Safe__factory , SafeProxyFactory } from "../typechain-types" ;
5+ import { execTransaction } from "./utils/utils" ;
6+
7+ describe ( "Example module tests" , async function ( ) {
8+ let deployer : Signer ;
9+ let alice : Signer ;
10+ let masterCopy : Safe ;
11+ let proxyFactory : SafeProxyFactory ;
12+ let safeFactory : Safe__factory ;
13+ let safe : Safe ;
14+ let exampleGuard : Contract ;
15+
16+ // Setup signers and deploy contracts before running tests
17+ before ( async ( ) => {
18+ [ deployer , alice ] = await ethers . getSigners ( ) ;
19+
20+ safeFactory = await ethers . getContractFactory ( "Safe" , deployer ) ;
21+ masterCopy = await safeFactory . deploy ( ) ;
22+
23+ proxyFactory = await (
24+ await ethers . getContractFactory ( "SafeProxyFactory" , deployer )
25+ ) . deploy ( ) ;
26+ } ) ;
27+
28+ // Setup contracts: Deploy a new token contract, create a new Safe, deploy the TokenWithdrawModule contract, and enable the module in the Safe.
29+ const setupContracts = async (
30+ walletOwners : Signer [ ] ,
31+ threshold : number
32+ ) => {
33+ const ownerAddresses = await Promise . all (
34+ walletOwners . map ( async ( walletOwner ) => await walletOwner . getAddress ( ) )
35+ ) ;
36+
37+ const safeData = masterCopy . interface . encodeFunctionData ( "setup" , [
38+ ownerAddresses ,
39+ threshold ,
40+ ZeroAddress ,
41+ "0x" ,
42+ ZeroAddress ,
43+ ZeroAddress ,
44+ 0 ,
45+ ZeroAddress ,
46+ ] ) ;
47+
48+ // Read the safe address by executing the static call to createProxyWithNonce function
49+ const safeAddress = await proxyFactory . createProxyWithNonce . staticCall (
50+ await masterCopy . getAddress ( ) ,
51+ safeData ,
52+ 0n
53+ ) ;
54+
55+ // Create the proxy with nonce
56+ await proxyFactory . createProxyWithNonce (
57+ await masterCopy . getAddress ( ) ,
58+ safeData ,
59+ 0n
60+ ) ;
61+
62+ if ( safeAddress === ZeroAddress ) {
63+ throw new Error ( "Safe address not found" ) ;
64+ }
65+
66+ // Deploy the TokenWithdrawModule contract
67+ exampleGuard = await (
68+ await ethers . getContractFactory ( "NoDegegateCallGuard" , deployer )
69+ ) . deploy ( ) ;
70+
71+ const safe = await ethers . getContractAt ( "Safe" , safeAddress ) ;
72+
73+ // Enable the module in the safe
74+ const enableModuleData = masterCopy . interface . encodeFunctionData (
75+ "setGuard" ,
76+ [ exampleGuard . target ]
77+ ) ;
78+
79+ // Execute the transaction to enable the module
80+ await execTransaction (
81+ walletOwners . slice ( 0 , threshold ) ,
82+ safe ,
83+ safe . target ,
84+ 0 ,
85+ enableModuleData ,
86+ 0
87+ ) ;
88+ } ;
89+
90+ // Test case to verify token transfer to bob
91+ it ( "Should successfully transfer tokens to bob" , async function ( ) {
92+ const wallets = [ alice ] ;
93+ await setupContracts ( wallets , 1 ) ;
94+ // Execute the transaction to enable the module
95+ await expect ( execTransaction (
96+ wallets ,
97+ safe ,
98+ ZeroAddress ,
99+ 0 ,
100+ "0x" ,
101+ 1
102+ ) ) . to . be . revertedWithCustomError ( exampleGuard , "DelegateCallNotAllowed" ) ;
103+ } ) ;
104+ } ) ;
0 commit comments