gn-contract 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,182 @@
1
+ import { expect } from "chai";
2
+ import { ethers, upgrades } from "hardhat";
3
+ import { initialize, getState, getAccounts } from "./lib/initializer";
4
+ import { Swap } from "../typechain-types";
5
+ import { toBn } from "evm-bn";
6
+
7
+ describe("Swap Contract", function () {
8
+ let swap: Swap;
9
+
10
+ before(async () => {
11
+ // Initialize the environment (deploys USDT, CUSDT, CROWD, etc.)
12
+ await initialize();
13
+ const { usdt, cusdt, crowd, owner } = getState();
14
+
15
+ // Deploy Swap Contract
16
+ const SwapFactory = await ethers.getContractFactory("Swap", owner);
17
+ swap = (await upgrades.deployProxy(
18
+ SwapFactory,
19
+ [
20
+ usdt.address,
21
+ cusdt.address,
22
+ crowd.address,
23
+ owner.address, // feeReceiver
24
+ owner.address, // feeMarketing
25
+ ],
26
+ { kind: "uups" },
27
+ )) as Swap;
28
+ await swap.deployed();
29
+
30
+ // Fund the Swap contract with CUSDT and CROWD so users can swap
31
+ // Owner (admin) should have initial supply from initialize() or we can mint/transfer
32
+ // Check initial balances of owner
33
+ const ownerCusdtBal = await cusdt.balanceOf(owner.address);
34
+ const ownerCrowdBal = await crowd.balanceOf(owner.address);
35
+
36
+ // Transfer some liquidity to Swap contract
37
+ await cusdt.connect(owner).transfer(swap.address, toBn("100000", 18));
38
+ await crowd.connect(owner).transfer(swap.address, toBn("1000000", 18));
39
+ });
40
+
41
+ it("should initialize with correct token addresses", async () => {
42
+ const { usdt, cusdt, crowd } = getState();
43
+ expect(await swap.usdt()).to.eq(usdt.address);
44
+ expect(await swap.cusdt()).to.eq(cusdt.address);
45
+ expect(await swap.crowd()).to.eq(crowd.address);
46
+ });
47
+
48
+ it("should swap USDT to CUSDT 1:1", async () => {
49
+ const { usdt, cusdt } = getState();
50
+ const [user] = await getAccounts(1, 1);
51
+ const amount = toBn("100", 18);
52
+
53
+ // Fund user with USDT
54
+ const { owner } = getState();
55
+ await usdt.connect(owner).transfer(user.address, amount);
56
+
57
+ // Approve Swap contract
58
+ await usdt.connect(user).approve(swap.address, amount);
59
+
60
+ const userUsdtBefore = await usdt.balanceOf(user.address);
61
+ const userCusdtBefore = await cusdt.balanceOf(user.address);
62
+
63
+ // Perform Swap
64
+ await swap.connect(user).swapToCUSDT(amount);
65
+
66
+ const userUsdtAfter = await usdt.balanceOf(user.address);
67
+ const userCusdtAfter = await cusdt.balanceOf(user.address);
68
+
69
+ expect(userUsdtAfter).to.eq(userUsdtBefore.sub(amount));
70
+ expect(userCusdtAfter).to.eq(userCusdtBefore.add(amount));
71
+ });
72
+
73
+ it("should fail swapToCUSDT if insufficient pool balance", async () => {
74
+ const { usdt } = getState();
75
+ const [user] = await getAccounts(2, 1);
76
+ // Try to swap more than available in pool (we put 100k)
77
+ const amount = toBn("200000", 18);
78
+
79
+ const { owner } = getState();
80
+ await usdt.connect(owner).transfer(user.address, amount);
81
+ await usdt.connect(user).approve(swap.address, amount);
82
+
83
+ await expect(swap.connect(user).swapToCUSDT(amount)).to.be.revertedWith(
84
+ "Insufficient Pool",
85
+ );
86
+ });
87
+
88
+ it("should swap USDT to CROWD 1:500", async () => {
89
+ const { usdt, crowd } = getState();
90
+ const [user] = await getAccounts(3, 1);
91
+ const amount = toBn("10", 18); // 10 USDT
92
+ const expectedCrowd = amount.mul(500); // 5000 CROWD
93
+
94
+ // Fund user
95
+ const { owner } = getState();
96
+ await usdt.connect(owner).transfer(user.address, amount);
97
+
98
+ // Approve
99
+ await usdt.connect(user).approve(swap.address, amount);
100
+
101
+ const userUsdtBefore = await usdt.balanceOf(user.address);
102
+ const userCrowdBefore = await crowd.balanceOf(user.address);
103
+
104
+ // Swap
105
+ await swap.connect(user).swapToCROWD(amount);
106
+
107
+ const userUsdtAfter = await usdt.balanceOf(user.address);
108
+ const userCrowdAfter = await crowd.balanceOf(user.address);
109
+
110
+ expect(userUsdtAfter).to.eq(userUsdtBefore.sub(amount));
111
+ expect(userCrowdAfter).to.eq(userCrowdBefore.add(expectedCrowd));
112
+ });
113
+
114
+ it("should fail swapToCROWD if insufficient pool balance", async () => {
115
+ const { usdt } = getState();
116
+ const [user] = await getAccounts(4, 1);
117
+ // Pool has 1M CROWD.
118
+ // Need > 1M CROWD output.
119
+ // 1 USDT = 500 CROWD.
120
+ // 2001 USDT = 1,000,500 CROWD > 1M.
121
+ const amount = toBn("2001", 18);
122
+
123
+ const { owner } = getState();
124
+ await usdt.connect(owner).transfer(user.address, amount);
125
+ await usdt.connect(user).approve(swap.address, amount);
126
+
127
+ await expect(swap.connect(user).swapToCROWD(amount)).to.be.revertedWith(
128
+ "Insufficient Pool",
129
+ );
130
+ });
131
+
132
+ describe("Owner Withdrawals", function () {
133
+ it("should allow owner to withdraw USDT", async () => {
134
+ const { usdt, owner } = getState();
135
+ // Swap contract likely has USDT from previous tests
136
+ const contractUsdtBal = await usdt.balanceOf(swap.address);
137
+ const withdrawAmount = contractUsdtBal;
138
+
139
+ const ownerBefore = await usdt.balanceOf(owner.address);
140
+ await swap.connect(owner).withdrawUSDT(withdrawAmount);
141
+ const ownerAfter = await usdt.balanceOf(owner.address);
142
+
143
+ expect(ownerAfter).to.eq(ownerBefore.add(withdrawAmount));
144
+ });
145
+
146
+ it("should allow owner to withdraw CUSDT", async () => {
147
+ const { cusdt, owner } = getState();
148
+ const amount = toBn("50", 18); // Withdraw small amount
149
+
150
+ const ownerBefore = await cusdt.balanceOf(owner.address);
151
+ await swap.connect(owner).withdrawCUSDT(amount);
152
+ const ownerAfter = await cusdt.balanceOf(owner.address);
153
+
154
+ expect(ownerAfter).to.eq(ownerBefore.add(amount));
155
+ });
156
+
157
+ it("should allow owner to withdraw CROWD", async () => {
158
+ const { crowd, owner } = getState();
159
+ const amount = toBn("500", 18);
160
+
161
+ const ownerBefore = await crowd.balanceOf(owner.address);
162
+ await swap.connect(owner).withdrawCROWD(amount);
163
+ const ownerAfter = await crowd.balanceOf(owner.address);
164
+
165
+ expect(ownerAfter).to.eq(ownerBefore.add(amount));
166
+ });
167
+
168
+ it("should NOT allow non-owner to withdraw", async () => {
169
+ const [user] = await getAccounts(5, 1);
170
+ const amount = toBn("1", 18);
171
+ await expect(swap.connect(user).withdrawUSDT(amount)).to.be.revertedWith(
172
+ "Ownable: caller is not the owner",
173
+ );
174
+ await expect(swap.connect(user).withdrawCUSDT(amount)).to.be.revertedWith(
175
+ "Ownable: caller is not the owner",
176
+ );
177
+ await expect(swap.connect(user).withdrawCROWD(amount)).to.be.revertedWith(
178
+ "Ownable: caller is not the owner",
179
+ );
180
+ });
181
+ });
182
+ });
@@ -0,0 +1,193 @@
1
+ /* eslint-disable prettier/prettier */
2
+ /* eslint-disable node/no-missing-import */
3
+ import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
4
+ import { toBn } from "evm-bn";
5
+ import { ethers, upgrades, network } from "hardhat";
6
+ import { reserveAddress } from "../../constants/rootAddress";
7
+ import {
8
+ Network,
9
+ CROWD,
10
+ NFT,
11
+ NFTGenesis,
12
+ USDT,
13
+ NFTFounder,
14
+ CUSDT,
15
+ } from "../../typechain-types";
16
+
17
+ let valhalla: Network = null as any;
18
+ let crowd: CROWD = null as any;
19
+ let nft: NFT = null as any;
20
+ let cusdt: CUSDT = null as any;
21
+ let accounts: SignerWithAddress[] = [];
22
+ let feeReceiver: SignerWithAddress = null as any;
23
+ let feeReceiver2: SignerWithAddress = null as any;
24
+ let owner: SignerWithAddress = null as any;
25
+ let nftFounder: NFTFounder = null as any;
26
+
27
+ let nftGenesis: NFTGenesis = null as any;
28
+ let usdt: USDT = null as any;
29
+
30
+ const initiateAccounts = async () => {
31
+ const accounts = await ethers.getSigners();
32
+ return accounts;
33
+ };
34
+
35
+ export const createSignerWithInitialBalance = async (
36
+ balance: string | number,
37
+ ) => {
38
+ const wallet = ethers.Wallet.createRandom().connect(ethers.provider);
39
+ await network.provider.send("hardhat_setBalance", [
40
+ wallet.address,
41
+ "0x" + Number(toBn("" + balance).toString()).toString(16),
42
+ ]);
43
+ return await ethers.getImpersonatedSigner(wallet.address);
44
+ };
45
+
46
+ export const setBalance = async (address: string, amount: string | number) => {
47
+ await network.provider.send("hardhat_setBalance", [
48
+ address,
49
+ "0x" + Number(toBn("" + amount).toString()).toString(16),
50
+ ]);
51
+ };
52
+
53
+ export const getAccounts = async (startIndex: number, amount: number = 1) => {
54
+ if (startIndex + amount + 1 > accounts.length) {
55
+ // adjust start index in case its greater
56
+ // than the total length of cached accounts
57
+ startIndex = startIndex >= accounts.length ? accounts.length : startIndex;
58
+
59
+ for (let i = accounts.length - 1; i <= startIndex + amount; i++) {
60
+ const signer = await createSignerWithInitialBalance(1000);
61
+ accounts.push(signer);
62
+ }
63
+ }
64
+
65
+ return accounts.filter((_, idx) => {
66
+ return idx >= startIndex && idx < startIndex + amount;
67
+ });
68
+ };
69
+
70
+ export const initialize = async () => {
71
+ await initiateAccounts();
72
+ const _accounts = await getAccounts(0, 15);
73
+
74
+ feeReceiver = await createSignerWithInitialBalance(0);
75
+ feeReceiver2 = await createSignerWithInitialBalance(0);
76
+
77
+ const CROWDContract = await ethers.getContractFactory("CROWD");
78
+ const admin = _accounts[0];
79
+ crowd = await CROWDContract.connect(admin).deploy();
80
+ await crowd.connect(admin).deployed();
81
+
82
+ const USDTContract = await ethers.getContractFactory("USDT");
83
+ usdt = await USDTContract.connect(admin).deploy();
84
+ await usdt.connect(admin).deployed();
85
+
86
+ const CUSDTContract = await ethers.getContractFactory("CUSDT");
87
+ cusdt = await CUSDTContract.connect(admin).deploy();
88
+ await cusdt.connect(admin).deployed();
89
+
90
+ const ValhallaContract = await ethers.getContractFactory("Network");
91
+ valhalla = (await upgrades.deployProxy(
92
+ ValhallaContract,
93
+ [
94
+ admin.address,
95
+ [
96
+ _accounts[0].address,
97
+ _accounts[1].address,
98
+ _accounts[2].address,
99
+ _accounts[3].address,
100
+ _accounts[4].address,
101
+ _accounts[5].address,
102
+ _accounts[6].address,
103
+ _accounts[7].address,
104
+ _accounts[8].address,
105
+ _accounts[9].address,
106
+ _accounts[10].address,
107
+ _accounts[11].address,
108
+ _accounts[12].address,
109
+ _accounts[13].address,
110
+ _accounts[14].address,
111
+ ],
112
+ feeReceiver.address,
113
+ feeReceiver2.address,
114
+ reserveAddress,
115
+ 0,
116
+ toBn("50", 18), // Registration fee: 50 USDT
117
+ ],
118
+ { kind: "transparent" },
119
+ )) as any;
120
+ await valhalla.connect(admin).deployed();
121
+
122
+ const NFTContract = await ethers.getContractFactory("NFT");
123
+ nft = (await upgrades.deployProxy(
124
+ NFTContract,
125
+ [crowd.address, valhalla.address],
126
+ { kind: "transparent" },
127
+ )) as any;
128
+ await nft.connect(admin).deployed();
129
+
130
+ const [receiverAddress] = await getAccounts(420, 2);
131
+ const NFTGenesiscontract = await ethers.getContractFactory("NFTGenesis");
132
+ nftGenesis = (await upgrades.deployProxy(
133
+ NFTGenesiscontract,
134
+ [
135
+ crowd.address,
136
+ usdt.address,
137
+ nft.address,
138
+ valhalla.address,
139
+ receiverAddress.address,
140
+ ],
141
+ { kind: "transparent" },
142
+ )) as any;
143
+ await nftGenesis.connect(admin).deployed();
144
+
145
+ const NFTFounderContract = await ethers.getContractFactory("NFTFounder");
146
+ nftFounder = (await upgrades.deployProxy(
147
+ NFTFounderContract,
148
+ [usdt.address, valhalla.address, receiverAddress.address],
149
+ { kind: "transparent" },
150
+ )) as any;
151
+ await nftFounder.connect(admin).deployed();
152
+
153
+ owner = admin;
154
+
155
+ const tx = await crowd.setMinterContract(nft.address);
156
+ await tx.wait();
157
+
158
+ const tx2 = await valhalla.connect(admin).setNftAddress(nft.address);
159
+ await tx2.wait();
160
+
161
+ const tx3 = await valhalla.connect(admin).setCRWDAddress(crowd.address);
162
+ await tx3.wait();
163
+
164
+ const tx4 = await nft.setNFTGenesis(nftGenesis.address);
165
+ await tx4.wait();
166
+
167
+ // Set USDT as the registration token
168
+ const tx5 = await valhalla.connect(admin).setCUSDAddress(usdt.address);
169
+ await tx5.wait();
170
+
171
+ const tx6 = await valhalla
172
+ .connect(admin)
173
+ .setNFTFounderAddress(nftFounder.address);
174
+ await tx6.wait();
175
+
176
+ const receiverAddress2 = await createSignerWithInitialBalance(0);
177
+
178
+ const tx7 = await nftFounder.setReceiverAddress2(receiverAddress2.address);
179
+ await tx7.wait();
180
+ };
181
+
182
+ export const getState = () => ({
183
+ valhalla,
184
+ usdt,
185
+ crowd,
186
+ nft,
187
+ feeReceiver,
188
+ feeReceiver2,
189
+ nftGenesis,
190
+ owner,
191
+ nftFounder,
192
+ cusdt,
193
+ });