1
+ import "module-alias/register" ;
2
+
3
+ import { Address , Account } from "@utils/types" ;
4
+ import { ZERO } from "@utils/constants" ;
5
+ import { SupplyCapAllowedCallerIssuanceHook } from "@utils/contracts/index" ;
6
+ import { ContractCallerMock , SetToken } from "@utils/contracts/setV2" ;
7
+ import DeployHelper from "@utils/deploys" ;
8
+ import {
9
+ addSnapshotBeforeRestoreAfterEach ,
10
+ ether ,
11
+ getAccounts ,
12
+ getSetFixture ,
13
+ getWaffleExpect ,
14
+ getRandomAccount ,
15
+ } from "@utils/index" ;
16
+ import { SetFixture } from "@utils/fixtures" ;
17
+ import { BigNumber , ContractTransaction } from "ethers" ;
18
+
19
+ const expect = getWaffleExpect ( ) ;
20
+
21
+ describe ( "SupplyCapAllowedCallerIssuanceHook" , ( ) => {
22
+ let owner : Account ;
23
+ let hookOwner : Account ;
24
+ let otherAccount : Account ;
25
+ let setV2Setup : SetFixture ;
26
+
27
+ let deployer : DeployHelper ;
28
+ let setToken : SetToken ;
29
+
30
+ let issuanceHook : SupplyCapAllowedCallerIssuanceHook ;
31
+
32
+ before ( async ( ) => {
33
+ [
34
+ owner ,
35
+ hookOwner ,
36
+ otherAccount ,
37
+ ] = await getAccounts ( ) ;
38
+
39
+ deployer = new DeployHelper ( owner . wallet ) ;
40
+
41
+ setV2Setup = getSetFixture ( owner . address ) ;
42
+ await setV2Setup . initialize ( ) ;
43
+
44
+ setToken = await setV2Setup . createSetToken (
45
+ [ setV2Setup . dai . address ] ,
46
+ [ ether ( 1 ) ] ,
47
+ [ setV2Setup . debtIssuanceModule . address ]
48
+ ) ;
49
+ } ) ;
50
+
51
+ addSnapshotBeforeRestoreAfterEach ( ) ;
52
+
53
+ describe ( "#constructor" , async ( ) => {
54
+ let subjectOwner : Address ;
55
+ let subjectSupplyCap : BigNumber ;
56
+
57
+ beforeEach ( async ( ) => {
58
+ subjectOwner = hookOwner . address ;
59
+ subjectSupplyCap = ether ( 10 ) ;
60
+ } ) ;
61
+
62
+ async function subject ( ) : Promise < SupplyCapAllowedCallerIssuanceHook > {
63
+ return await deployer . hooks . deploySupplyCapAllowedCallerIssuanceHook ( subjectOwner , subjectSupplyCap ) ;
64
+ }
65
+
66
+ it ( "should set the correct SetToken address" , async ( ) => {
67
+ const hook = await subject ( ) ;
68
+
69
+ const actualSupplyCap = await hook . supplyCap ( ) ;
70
+ expect ( actualSupplyCap ) . to . eq ( subjectSupplyCap ) ;
71
+ } ) ;
72
+
73
+ it ( "should set the correct owner address" , async ( ) => {
74
+ const hook = await subject ( ) ;
75
+
76
+ const actualOwner = await hook . owner ( ) ;
77
+ expect ( actualOwner ) . to . eq ( subjectOwner ) ;
78
+ } ) ;
79
+ } ) ;
80
+
81
+ describe ( "#invokePreIssueHook" , async ( ) => {
82
+ let subjectSetToken : Address ;
83
+ let subjectQuantity : BigNumber ;
84
+ let subjectTo : Address ;
85
+
86
+ beforeEach ( async ( ) => {
87
+ issuanceHook = await deployer . hooks . deploySupplyCapAllowedCallerIssuanceHook ( owner . address , ether ( 10 ) ) ;
88
+
89
+ await setV2Setup . debtIssuanceModule . initialize (
90
+ setToken . address ,
91
+ ether ( .1 ) ,
92
+ ether ( .01 ) ,
93
+ ether ( .01 ) ,
94
+ owner . address ,
95
+ issuanceHook . address
96
+ ) ;
97
+
98
+ await setV2Setup . dai . approve ( setV2Setup . debtIssuanceModule . address , ether ( 100 ) ) ;
99
+
100
+ subjectSetToken = setToken . address ;
101
+ subjectQuantity = ether ( 5 ) ;
102
+ subjectTo = owner . address ;
103
+ } ) ;
104
+
105
+ async function subject ( ) : Promise < ContractTransaction > {
106
+ return await setV2Setup . debtIssuanceModule . issue (
107
+ subjectSetToken ,
108
+ subjectQuantity ,
109
+ subjectTo
110
+ ) ;
111
+ }
112
+
113
+ it ( "should not revert" , async ( ) => {
114
+ await expect ( subject ( ) ) . to . not . be . reverted ;
115
+ } ) ;
116
+
117
+ describe ( "when total issuance quantity forces supply over the limit" , async ( ) => {
118
+ beforeEach ( async ( ) => {
119
+ subjectQuantity = ether ( 11 ) ;
120
+ } ) ;
121
+
122
+ it ( "should revert" , async ( ) => {
123
+ await expect ( subject ( ) ) . to . be . revertedWith ( "Supply cap exceeded" ) ;
124
+ } ) ;
125
+ } ) ;
126
+
127
+ describe ( "when the sender is not EOA and on allowlist" , async ( ) => {
128
+ let subjectTarget : Address ;
129
+ let subjectCallData : string ;
130
+ let subjectValue : BigNumber ;
131
+
132
+ let contractCaller : ContractCallerMock ;
133
+
134
+ beforeEach ( async ( ) => {
135
+ contractCaller = await deployer . setV2 . deployContractCallerMock ( ) ;
136
+ await issuanceHook . updateCallerStatus ( [ contractCaller . address ] , [ true ] ) ;
137
+
138
+ await setV2Setup . dai . transfer ( contractCaller . address , ether ( 50 ) ) ;
139
+ // Approve token from contract caller to issuance module
140
+ const approveData = setV2Setup . dai . interface . encodeFunctionData ( "approve" , [
141
+ setV2Setup . debtIssuanceModule . address ,
142
+ ether ( 100 ) ,
143
+ ] ) ;
144
+ await contractCaller . invoke ( setV2Setup . dai . address , ZERO , approveData ) ;
145
+
146
+ subjectSetToken = setToken . address ;
147
+ subjectQuantity = ether ( 5 ) ;
148
+ subjectTo = owner . address ;
149
+
150
+ subjectTarget = setV2Setup . debtIssuanceModule . address ;
151
+ subjectCallData = setV2Setup . debtIssuanceModule . interface . encodeFunctionData ( "issue" , [
152
+ subjectSetToken ,
153
+ subjectQuantity ,
154
+ subjectTo ,
155
+ ] ) ;
156
+
157
+ subjectValue = ZERO ;
158
+ } ) ;
159
+
160
+ async function subjectContractCaller ( ) : Promise < any > {
161
+ return await contractCaller . invoke (
162
+ subjectTarget ,
163
+ subjectValue ,
164
+ subjectCallData
165
+ ) ;
166
+ }
167
+
168
+ it ( "should not revert" , async ( ) => {
169
+ await expect ( subjectContractCaller ( ) ) . to . not . be . reverted ;
170
+ } ) ;
171
+
172
+ describe ( "when the caller is not on allowlist" , async ( ) => {
173
+ beforeEach ( async ( ) => {
174
+ await issuanceHook . updateCallerStatus ( [ contractCaller . address ] , [ false ] ) ;
175
+ } ) ;
176
+
177
+ it ( "should revert" , async ( ) => {
178
+ await expect ( subjectContractCaller ( ) ) . to . be . revertedWith ( "Contract not permitted to call" ) ;
179
+ } ) ;
180
+
181
+ describe ( "when anyoneCallable is flipped to true" , async ( ) => {
182
+ beforeEach ( async ( ) => {
183
+ await issuanceHook . updateAnyoneCallable ( true ) ;
184
+ } ) ;
185
+
186
+ it ( "should succeed without revert" , async ( ) => {
187
+ await subjectContractCaller ( ) ;
188
+ } ) ;
189
+ } ) ;
190
+ } ) ;
191
+ } ) ;
192
+ } ) ;
193
+
194
+ describe ( "#updateSupplyCap" , async ( ) => {
195
+ let subjectNewCap : BigNumber ;
196
+ let subjectCaller : Account ;
197
+
198
+ beforeEach ( async ( ) => {
199
+ issuanceHook = await deployer . hooks . deploySupplyCapAllowedCallerIssuanceHook ( owner . address , ether ( 10 ) ) ;
200
+
201
+ subjectNewCap = ether ( 20 ) ;
202
+ subjectCaller = owner ;
203
+ } ) ;
204
+
205
+ async function subject ( ) : Promise < ContractTransaction > {
206
+ return await issuanceHook . connect ( subjectCaller . wallet ) . updateSupplyCap ( subjectNewCap ) ;
207
+ }
208
+
209
+ it ( "should update supply cap" , async ( ) => {
210
+ await subject ( ) ;
211
+
212
+ const actualCap = await issuanceHook . supplyCap ( ) ;
213
+
214
+ expect ( actualCap ) . to . eq ( subjectNewCap ) ;
215
+ } ) ;
216
+
217
+ it ( "should emit the correct SupplyCapUpdated event" , async ( ) => {
218
+ await expect ( subject ( ) ) . to . emit ( issuanceHook , "SupplyCapUpdated" ) . withArgs ( subjectNewCap ) ;
219
+ } ) ;
220
+
221
+ describe ( "when caller is not owner" , async ( ) => {
222
+ beforeEach ( async ( ) => {
223
+ subjectCaller = await getRandomAccount ( ) ;
224
+ } ) ;
225
+
226
+ it ( "should revert" , async ( ) => {
227
+ await expect ( subject ( ) ) . to . be . revertedWith ( "Ownable: caller is not the owner" ) ;
228
+ } ) ;
229
+ } ) ;
230
+ } ) ;
231
+
232
+ describe ( "#updateCallerStatus" , async ( ) => {
233
+ let subjectFunctionCallers : Address [ ] ;
234
+ let subjectStatuses : boolean [ ] ;
235
+ let subjectCaller : Account ;
236
+
237
+ beforeEach ( async ( ) => {
238
+ issuanceHook = await deployer . hooks . deploySupplyCapAllowedCallerIssuanceHook ( owner . address , ether ( 10 ) ) ;
239
+
240
+ subjectFunctionCallers = [ otherAccount . address ] ;
241
+ subjectStatuses = [ true ] ;
242
+ subjectCaller = owner ;
243
+ } ) ;
244
+
245
+ async function subject ( ) : Promise < ContractTransaction > {
246
+ return issuanceHook . connect ( subjectCaller . wallet ) . updateCallerStatus ( subjectFunctionCallers , subjectStatuses ) ;
247
+ }
248
+
249
+ it ( "should update the callAllowList" , async ( ) => {
250
+ await subject ( ) ;
251
+ const callerStatus = await issuanceHook . callAllowList ( subjectFunctionCallers [ 0 ] ) ;
252
+ expect ( callerStatus ) . to . be . true ;
253
+ } ) ;
254
+
255
+ it ( "should emit CallerStatusUpdated event" , async ( ) => {
256
+ await expect ( subject ( ) ) . to . emit ( issuanceHook , "CallerStatusUpdated" ) . withArgs (
257
+ subjectFunctionCallers [ 0 ] ,
258
+ subjectStatuses [ 0 ]
259
+ ) ;
260
+ } ) ;
261
+
262
+ describe ( "when the sender is not owner" , async ( ) => {
263
+ beforeEach ( async ( ) => {
264
+ subjectCaller = await getRandomAccount ( ) ;
265
+ } ) ;
266
+
267
+ it ( "should revert" , async ( ) => {
268
+ await expect ( subject ( ) ) . to . be . revertedWith ( "Ownable: caller is not the owner" ) ;
269
+ } ) ;
270
+ } ) ;
271
+ } ) ;
272
+
273
+ describe ( "#updateAnyoneCallable" , async ( ) => {
274
+ let subjectStatus : boolean ;
275
+ let subjectCaller : Account ;
276
+
277
+ beforeEach ( async ( ) => {
278
+ issuanceHook = await deployer . hooks . deploySupplyCapAllowedCallerIssuanceHook ( owner . address , ether ( 10 ) ) ;
279
+
280
+ subjectStatus = true ;
281
+ subjectCaller = owner ;
282
+ } ) ;
283
+
284
+ async function subject ( ) : Promise < ContractTransaction > {
285
+ return issuanceHook . connect ( subjectCaller . wallet ) . updateAnyoneCallable ( subjectStatus ) ;
286
+ }
287
+
288
+ it ( "should update the anyoneCallable boolean" , async ( ) => {
289
+ await subject ( ) ;
290
+ const callerStatus = await issuanceHook . anyoneCallable ( ) ;
291
+ expect ( callerStatus ) . to . be . true ;
292
+ } ) ;
293
+
294
+ it ( "should emit AnyoneCallableUpdated event" , async ( ) => {
295
+ await expect ( subject ( ) ) . to . emit ( issuanceHook , "AnyoneCallableUpdated" ) . withArgs (
296
+ subjectStatus
297
+ ) ;
298
+ } ) ;
299
+
300
+ describe ( "when the sender is not owner" , async ( ) => {
301
+ beforeEach ( async ( ) => {
302
+ subjectCaller = await getRandomAccount ( ) ;
303
+ } ) ;
304
+
305
+ it ( "should revert" , async ( ) => {
306
+ await expect ( subject ( ) ) . to . be . revertedWith ( "Ownable: caller is not the owner" ) ;
307
+ } ) ;
308
+ } ) ;
309
+ } ) ;
310
+ } ) ;
0 commit comments