-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathtoken.ts
338 lines (291 loc) · 11 KB
/
token.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
import { expect } from "chai";
import hre, { ethers } from "hardhat";
import { BigNumber, Contract, ContractFactory } from "ethers";
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
const { formatBytes32String } = ethers.utils;
const { TOKEN_PARAMS } = require("../params");
describe.skip("RibbonToken contract", function () {
let RibbonToken: ContractFactory;
let ribbonToken: Contract;
let owner: SignerWithAddress;
let addr1: SignerWithAddress;
let addr2: SignerWithAddress;
let withSigner: Contract;
beforeEach(async function () {
// Get the ContractFactory and Signers here.
RibbonToken = await ethers.getContractFactory("RibbonToken");
[owner, addr1, addr2] = await ethers.getSigners();
ribbonToken = await RibbonToken.deploy(
TOKEN_PARAMS.NAME,
TOKEN_PARAMS.SYMBOL,
TOKEN_PARAMS.SUPPLY,
TOKEN_PARAMS.BENIFICIARY
);
await ribbonToken.deployed();
await owner.sendTransaction({
to: TOKEN_PARAMS.BENIFICIARY,
value: ethers.utils.parseEther("5.0"),
});
// Allow impersonation of new account
await hre.network.provider.request({
method: "hardhat_impersonateAccount",
params: [TOKEN_PARAMS.BENIFICIARY],
});
const signer = await ethers.provider.getSigner(TOKEN_PARAMS.BENIFICIARY);
let token = await ethers.getContractAt("RibbonToken", ribbonToken.address);
withSigner = await token.connect(signer);
});
// Test initial setup
describe("Deployment", function () {
it("Should mint the total supply", async function () {
expect(await ribbonToken.totalSupply()).to.equal(TOKEN_PARAMS.SUPPLY);
});
it("Should mint the total supply of tokens to the new benificiary", async function () {
const ownerBalance = await ribbonToken.balanceOf(
TOKEN_PARAMS.BENIFICIARY
);
expect(await ribbonToken.totalSupply()).to.equal(ownerBalance);
});
it("Should grant beneficiary minting rights", async function () {
expect(
await withSigner.hasRole(
await ribbonToken.MINTER_ROLE(),
TOKEN_PARAMS.BENIFICIARY
)
).to.be.true;
});
it("Should not grant non-beneficiary any minting rights", async function () {
await expect(
await withSigner.hasRole(await ribbonToken.MINTER_ROLE(), addr1.address)
).to.be.false;
});
it("Should grant beneficiary transfer rights", async function () {
expect(
await withSigner.hasRole(
await ribbonToken.TRANSFER_ROLE(),
TOKEN_PARAMS.BENIFICIARY
)
).to.be.true;
});
it("Should not grant non-beneficiary any transfer rights", async function () {
expect(
await withSigner.hasRole(
await ribbonToken.TRANSFER_ROLE(),
addr1.address
)
).to.be.false;
});
it("Should grant beneficiary admin rights", async function () {
expect(
await withSigner.hasRole(
await ribbonToken.ADMIN_ROLE(),
TOKEN_PARAMS.BENIFICIARY
)
).to.be.true;
});
it("Should not grant non-beneficiary any admin rights", async function () {
expect(
await withSigner.hasRole(await ribbonToken.ADMIN_ROLE(), addr1.address)
).to.be.false;
});
it("Admin role of transfer role should be ADMIN_ROLE", async function () {
expect(
await withSigner.getRoleAdmin(await ribbonToken.TRANSFER_ROLE())
).to.equal(await ribbonToken.ADMIN_ROLE());
});
});
// Test token parameter
describe("Token Parameters", function () {
it("Should have the correct decimals", async function () {
expect(await ribbonToken.decimals()).to.equal(
parseInt(TOKEN_PARAMS.DECIMALS)
);
});
it("Should have the correct name", async function () {
expect(await ribbonToken.name()).to.equal(TOKEN_PARAMS.NAME);
});
it("Should have the correct symbol", async function () {
expect(await ribbonToken.symbol()).to.equal(TOKEN_PARAMS.SYMBOL);
});
});
// Test minter privileges
describe("Mintability", function () {
beforeEach(async function () {
await withSigner.setTransfersAllowed(true);
});
it("Should allow the benificiary to mint", async function () {
await expect(await withSigner.mint(addr1.address, 50)).to.emit(
ribbonToken,
"Transfer"
);
});
it("Should revert mint attempts by non-minter", async function () {
await expect(ribbonToken.mint(addr1.address, 50)).to.be.revertedWith(
"RibbonToken: only minter"
);
});
it("Should revert mint attempts by minter after role renounced", async function () {
await withSigner.renounceRole(
await ribbonToken.MINTER_ROLE(),
TOKEN_PARAMS.BENIFICIARY
);
await expect(withSigner.mint(addr1.address, 50)).to.be.revertedWith(
"RibbonToken: only minter"
);
});
});
// Test transfer privileges
describe("Transferability", function () {
it("Should let beneficiary toggle transfer flag", async function () {
await withSigner.setTransfersAllowed(true);
expect(await withSigner.transfersAllowed()).to.be.true;
});
it("Should let beneficiary toggle transfer flag #2", async function () {
await withSigner.setTransfersAllowed(false);
expect(await withSigner.transfersAllowed()).to.be.false;
});
it("Should not let non-beneficiary toggle transfer flag", async function () {
await expect(
ribbonToken.connect(addr1).setTransfersAllowed(true)
).to.be.revertedWith("RibbonToken: only admin");
});
it("Should not let non-admin to transfer", async function () {
await expect(
ribbonToken.connect(addr1).transfer(owner.address, 1)
).to.be.revertedWith("RibbonToken: no transfer privileges");
});
it("Should let non-admin to transfer after toggle switched", async function () {
await withSigner.setTransfersAllowed(true);
await withSigner.transfer(addr1.address, 50);
await ribbonToken.connect(addr1).transfer(addr2.address, 50);
});
it("Should not let non-admin to transfer after toggle switched to false", async function () {
await withSigner.setTransfersAllowed(false);
await withSigner.transfer(addr1.address, 50);
await expect(
ribbonToken.connect(addr1).transfer(addr2.address, 50)
).to.be.revertedWith("RibbonToken: no transfer privileges");
});
});
// Test admin privileges
describe("Admin", function () {
it("Should let admin assign transfer role to another", async function () {
await withSigner.grantRole(
await ribbonToken.TRANSFER_ROLE(),
addr1.address
);
expect(
await withSigner.hasRole(
await ribbonToken.TRANSFER_ROLE(),
addr1.address
)
).to.be.true;
await withSigner.transfer(addr1.address, 50);
await ribbonToken.connect(addr1).transfer(addr2.address, 50);
});
it("Should let admin revoke transfer role from another", async function () {
await withSigner.grantRole(
await ribbonToken.TRANSFER_ROLE(),
addr1.address
);
await withSigner.revokeRole(
await ribbonToken.TRANSFER_ROLE(),
addr1.address
);
await withSigner.transfer(addr1.address, 50);
await expect(
ribbonToken.connect(addr1).transfer(addr2.address, 50)
).to.be.revertedWith("RibbonToken: no transfer privileges");
expect(
await withSigner.hasRole(
await ribbonToken.TRANSFER_ROLE(),
addr1.address
)
).to.be.false;
});
it("Should not let admin assign minter role to another", async function () {
await expect(
withSigner.grantRole(await ribbonToken.MINTER_ROLE(), addr1.address)
).to.be.reverted;
});
it("Should not let admin assign admin role to another", async function () {
await expect(
withSigner.grantRole(await ribbonToken.ADMIN_ROLE(), addr1.address)
).to.be.reverted;
});
it("Should let admin renounce own admin role", async function () {
await expect(
withSigner.renounceRole(
await ribbonToken.ADMIN_ROLE(),
TOKEN_PARAMS.BENIFICIARY
)
).to.emit(ribbonToken, "RoleRevoked");
expect(
await withSigner.hasRole(
await ribbonToken.ADMIN_ROLE(),
TOKEN_PARAMS.BENIFICIARY
)
).to.be.false;
});
});
// Test arbitrary ribbon token transfer attempts
describe("Transactions", function () {
beforeEach(async function () {
await withSigner.setTransfersAllowed(true);
});
it("Should transfer tokens between accounts", async function () {
// Transfer 50 tokens from owner to addr1
await withSigner.transfer(addr1.address, 50);
const addr1Balance = await ribbonToken.balanceOf(addr1.address);
expect(addr1Balance).to.equal(50);
// Transfer 50 tokens from addr1 to addr2
// We use .connect(signer) to send a transaction from another account
await ribbonToken.connect(addr1).transfer(addr2.address, 50);
const addr2Balance = await ribbonToken.balanceOf(addr2.address);
expect(addr2Balance).to.equal(50);
});
it("Should fail if sender doesn’t have enough tokens", async function () {
const initialOwnerBalance = await ribbonToken.balanceOf(
TOKEN_PARAMS.BENIFICIARY
);
// Try to send 1 token from addr1 (0 tokens) to owner (1000 tokens).
// `require` will evaluate false and revert the transaction.
await expect(
ribbonToken.connect(addr1).transfer(owner.address, 1)
).to.be.revertedWith("ERC20: transfer amount exceeds balance");
// Owner balance shouldn't have changed.
expect(await ribbonToken.balanceOf(TOKEN_PARAMS.BENIFICIARY)).to.equal(
initialOwnerBalance
);
});
it("Should update balances after transfers", async function () {
const initialOwnerBalance = await ribbonToken.balanceOf(
TOKEN_PARAMS.BENIFICIARY
);
// Transfer 100 tokens from owner to addr1.
const toTransfer1 = BigNumber.from("100")
.mul(BigNumber.from("10").pow(BigNumber.from(TOKEN_PARAMS.DECIMALS)))
.toString();
await withSigner.transfer(addr1.address, toTransfer1);
// Transfer another 50 tokens from owner to addr1.
const toTransfer2 = BigNumber.from("50")
.mul(BigNumber.from("10").pow(BigNumber.from(TOKEN_PARAMS.DECIMALS)))
.toString();
await withSigner.transfer(addr2.address, toTransfer2);
const amountLost = BigNumber.from("150").mul(
BigNumber.from("10").pow(BigNumber.from(TOKEN_PARAMS.DECIMALS))
);
// Check balances.
const finalOwnerBalance = await ribbonToken.balanceOf(
TOKEN_PARAMS.BENIFICIARY
);
expect(finalOwnerBalance.toString()).to.equal(
initialOwnerBalance.sub(amountLost).toString()
);
const addr1Balance = await ribbonToken.balanceOf(addr1.address);
expect(addr1Balance).to.equal(toTransfer1);
const addr2Balance = await ribbonToken.balanceOf(addr2.address);
expect(addr2Balance).to.equal(toTransfer2);
});
});
});