|
| 1 | +import { beforeAll, describe, expect, it } from "vitest"; |
| 2 | +import { VITALIK_WALLET } from "../../../test/src/addresses.js"; |
| 3 | +import { ANVIL_CHAIN } from "../../../test/src/chains.js"; |
| 4 | +import { TEST_CLIENT } from "../../../test/src/test-clients.js"; |
| 5 | +import { |
| 6 | + TEST_ACCOUNT_A, |
| 7 | + TEST_ACCOUNT_B, |
| 8 | +} from "../../../test/src/test-wallets.js"; |
| 9 | +import { type ThirdwebContract, getContract } from "../../contract/contract.js"; |
| 10 | +import { sendAndConfirmTransaction } from "../../exports/transaction.js"; |
| 11 | +import { getContractMetadata } from "../common/read/getContractMetadata.js"; |
| 12 | +import { deployERC721Contract } from "../prebuilts/deploy-erc721.js"; |
| 13 | +import { balanceOf } from "./__generated__/IERC721A/read/balanceOf.js"; |
| 14 | +import { nextTokenIdToMint } from "./__generated__/IERC721Enumerable/read/nextTokenIdToMint.js"; |
| 15 | +import { claimTo } from "./drops/write/claimTo.js"; |
| 16 | +import { setClaimConditions } from "./drops/write/setClaimConditions.js"; |
| 17 | +import { getNFT } from "./read/getNFT.js"; |
| 18 | +import { lazyMint } from "./write/lazyMint.js"; |
| 19 | + |
| 20 | +describe.runIf(process.env.TW_SECRET_KEY)( |
| 21 | + "DropERC721", |
| 22 | + { |
| 23 | + retry: 0, |
| 24 | + }, |
| 25 | + () => { |
| 26 | + let contract: ThirdwebContract; |
| 27 | + |
| 28 | + beforeAll(async () => { |
| 29 | + const contractAddress = await deployERC721Contract({ |
| 30 | + account: TEST_ACCOUNT_A, |
| 31 | + chain: ANVIL_CHAIN, |
| 32 | + client: TEST_CLIENT, |
| 33 | + params: { |
| 34 | + name: "Test DropERC721", |
| 35 | + }, |
| 36 | + type: "DropERC721", |
| 37 | + }); |
| 38 | + |
| 39 | + contract = getContract({ |
| 40 | + address: contractAddress, |
| 41 | + chain: ANVIL_CHAIN, |
| 42 | + client: TEST_CLIENT, |
| 43 | + }); |
| 44 | + // this deploys a contract, it may take some time |
| 45 | + }, 60_000); |
| 46 | + |
| 47 | + describe("Deployment", () => { |
| 48 | + it("should deploy", async () => { |
| 49 | + expect(contract).toBeDefined(); |
| 50 | + }); |
| 51 | + it("should have the correct name", async () => { |
| 52 | + const metadata = await getContractMetadata({ contract }); |
| 53 | + expect(metadata.name).toBe("Test DropERC721"); |
| 54 | + }); |
| 55 | + }); |
| 56 | + |
| 57 | + it("should allow for lazy minting tokens", async () => { |
| 58 | + const mintTx = lazyMint({ |
| 59 | + contract, |
| 60 | + nfts: [ |
| 61 | + { name: "Test NFT" }, |
| 62 | + { name: "Test NFT 2" }, |
| 63 | + { name: "Test NFT 3" }, |
| 64 | + { name: "Test NFT 4" }, |
| 65 | + ], |
| 66 | + }); |
| 67 | + await sendAndConfirmTransaction({ |
| 68 | + transaction: mintTx, |
| 69 | + account: TEST_ACCOUNT_A, |
| 70 | + }); |
| 71 | + |
| 72 | + await expect(nextTokenIdToMint({ contract })).resolves.toBe(4n); |
| 73 | + await expect( |
| 74 | + getNFT({ contract, tokenId: 0n }), |
| 75 | + ).resolves.toMatchInlineSnapshot(` |
| 76 | + { |
| 77 | + "id": 0n, |
| 78 | + "metadata": { |
| 79 | + "name": "Test NFT", |
| 80 | + }, |
| 81 | + "owner": null, |
| 82 | + "tokenURI": "ipfs://QmUfspS2uU9roYLJveebbY5geYaNR4KkZAsMkb5pPRtc7a/0", |
| 83 | + "type": "ERC721", |
| 84 | + } |
| 85 | + `); |
| 86 | + }); |
| 87 | + |
| 88 | + it("should allow to claim tokens", async () => { |
| 89 | + await expect( |
| 90 | + balanceOf({ contract, owner: TEST_ACCOUNT_A.address }), |
| 91 | + ).resolves.toBe(0n); |
| 92 | + await sendAndConfirmTransaction({ |
| 93 | + transaction: setClaimConditions({ |
| 94 | + contract, |
| 95 | + phases: [{}], |
| 96 | + }), |
| 97 | + account: TEST_ACCOUNT_A, |
| 98 | + }); |
| 99 | + const claimTx = claimTo({ |
| 100 | + contract, |
| 101 | + to: TEST_ACCOUNT_A.address, |
| 102 | + quantity: 1n, |
| 103 | + }); |
| 104 | + await sendAndConfirmTransaction({ |
| 105 | + transaction: claimTx, |
| 106 | + account: TEST_ACCOUNT_A, |
| 107 | + }); |
| 108 | + await expect( |
| 109 | + balanceOf({ contract, owner: TEST_ACCOUNT_A.address }), |
| 110 | + ).resolves.toBe(1n); |
| 111 | + }); |
| 112 | + |
| 113 | + describe("Allowlists", () => { |
| 114 | + it("should allow to claim tokens with an allowlist", async () => { |
| 115 | + await sendAndConfirmTransaction({ |
| 116 | + transaction: setClaimConditions({ |
| 117 | + contract, |
| 118 | + phases: [ |
| 119 | + { |
| 120 | + overrideList: [ |
| 121 | + { address: TEST_ACCOUNT_A.address, maxClaimable: "100" }, |
| 122 | + { address: VITALIK_WALLET, maxClaimable: "100" }, |
| 123 | + ], |
| 124 | + maxClaimablePerWallet: 0n, |
| 125 | + }, |
| 126 | + ], |
| 127 | + }), |
| 128 | + account: TEST_ACCOUNT_A, |
| 129 | + }); |
| 130 | + |
| 131 | + await expect( |
| 132 | + balanceOf({ contract, owner: TEST_ACCOUNT_B.address }), |
| 133 | + ).resolves.toBe(0n); |
| 134 | + |
| 135 | + await sendAndConfirmTransaction({ |
| 136 | + account: TEST_ACCOUNT_A, |
| 137 | + transaction: claimTo({ |
| 138 | + contract, |
| 139 | + from: TEST_ACCOUNT_A.address, |
| 140 | + to: TEST_ACCOUNT_B.address, |
| 141 | + quantity: 1n, |
| 142 | + }), |
| 143 | + }); |
| 144 | + |
| 145 | + await expect( |
| 146 | + balanceOf({ contract, owner: TEST_ACCOUNT_B.address }), |
| 147 | + ).resolves.toBe(1n); |
| 148 | + |
| 149 | + await expect( |
| 150 | + sendAndConfirmTransaction({ |
| 151 | + account: TEST_ACCOUNT_B, |
| 152 | + transaction: claimTo({ |
| 153 | + contract, |
| 154 | + to: TEST_ACCOUNT_B.address, |
| 155 | + quantity: 1n, |
| 156 | + }), |
| 157 | + }), |
| 158 | + ).rejects.toThrowErrorMatchingInlineSnapshot(` |
| 159 | + [TransactionError: Error - !Qty |
| 160 | +
|
| 161 | + contract: ${contract.address} |
| 162 | + chainId: 31337] |
| 163 | + `); |
| 164 | + }); |
| 165 | + |
| 166 | + it("should respect max claimable", async () => { |
| 167 | + await sendAndConfirmTransaction({ |
| 168 | + transaction: setClaimConditions({ |
| 169 | + contract, |
| 170 | + phases: [ |
| 171 | + { |
| 172 | + overrideList: [ |
| 173 | + { address: TEST_ACCOUNT_A.address, maxClaimable: "3" }, |
| 174 | + { address: VITALIK_WALLET, maxClaimable: "3" }, |
| 175 | + ], |
| 176 | + maxClaimablePerWallet: 0n, |
| 177 | + }, |
| 178 | + ], |
| 179 | + }), |
| 180 | + account: TEST_ACCOUNT_A, |
| 181 | + }); |
| 182 | + |
| 183 | + await expect( |
| 184 | + balanceOf({ contract, owner: TEST_ACCOUNT_A.address }), |
| 185 | + ).resolves.toBe(1n); |
| 186 | + |
| 187 | + // we try to claim an extra `2` tokens |
| 188 | + // this should faile bcause the max claimable is `3` and we have previously already claimed 2 tokens (one for ourselves, one for the other wallet) |
| 189 | + // NOTE: this relies on the previous tests, we should extract this and properly re-set tests every time |
| 190 | + // this probably requires re-deploying contracts for every test => clean slate |
| 191 | + await expect( |
| 192 | + sendAndConfirmTransaction({ |
| 193 | + account: TEST_ACCOUNT_A, |
| 194 | + transaction: claimTo({ |
| 195 | + contract, |
| 196 | + to: TEST_ACCOUNT_A.address, |
| 197 | + quantity: 2n, |
| 198 | + }), |
| 199 | + }), |
| 200 | + ).rejects.toThrowErrorMatchingInlineSnapshot(` |
| 201 | + [TransactionError: Error - !Qty |
| 202 | +
|
| 203 | + contract: ${contract.address} |
| 204 | + chainId: 31337] |
| 205 | + `); |
| 206 | + |
| 207 | + // we now try to claim just ONE more token |
| 208 | + // this should work because we have only claimed `2` tokens so far (one for ourselves, one for the other wallet) |
| 209 | + // this should work because the max claimable is `3` and so we **can** claim `1` more token |
| 210 | + await sendAndConfirmTransaction({ |
| 211 | + account: TEST_ACCOUNT_A, |
| 212 | + transaction: claimTo({ |
| 213 | + contract, |
| 214 | + to: TEST_ACCOUNT_A.address, |
| 215 | + quantity: 1n, |
| 216 | + }), |
| 217 | + }); |
| 218 | + |
| 219 | + await expect( |
| 220 | + balanceOf({ contract, owner: TEST_ACCOUNT_A.address }), |
| 221 | + ).resolves.toBe(2n); |
| 222 | + }); |
| 223 | + }); |
| 224 | + |
| 225 | + it("should respect price", async () => { |
| 226 | + await sendAndConfirmTransaction({ |
| 227 | + transaction: setClaimConditions({ |
| 228 | + contract, |
| 229 | + phases: [ |
| 230 | + { |
| 231 | + overrideList: [ |
| 232 | + { |
| 233 | + address: TEST_ACCOUNT_A.address, |
| 234 | + maxClaimable: "10", |
| 235 | + price: "0", |
| 236 | + }, |
| 237 | + ], |
| 238 | + maxClaimablePerWallet: 0n, |
| 239 | + price: "1000", |
| 240 | + }, |
| 241 | + ], |
| 242 | + }), |
| 243 | + account: TEST_ACCOUNT_A, |
| 244 | + }); |
| 245 | + |
| 246 | + await expect( |
| 247 | + balanceOf({ contract, owner: TEST_ACCOUNT_A.address }), |
| 248 | + ).resolves.toBe(2n); |
| 249 | + |
| 250 | + await sendAndConfirmTransaction({ |
| 251 | + account: TEST_ACCOUNT_A, |
| 252 | + transaction: claimTo({ |
| 253 | + contract, |
| 254 | + to: TEST_ACCOUNT_A.address, |
| 255 | + quantity: 1n, |
| 256 | + }), |
| 257 | + }); |
| 258 | + |
| 259 | + await expect( |
| 260 | + balanceOf({ contract, owner: TEST_ACCOUNT_A.address }), |
| 261 | + ).resolves.toBe(3n); |
| 262 | + }); |
| 263 | + }, |
| 264 | +); |
0 commit comments