thirdweb 5.59.2 → 5.60.0-nightly-6c26012a71d884f99dd5d8c914b3879037b36d56-20240929000339

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.
Files changed (191) hide show
  1. package/dist/cjs/exports/deploys.js +3 -1
  2. package/dist/cjs/exports/deploys.js.map +1 -1
  3. package/dist/cjs/exports/extensions/pack.js +24 -0
  4. package/dist/cjs/exports/extensions/pack.js.map +1 -0
  5. package/dist/cjs/extensions/pack/__generated__/IPack/events/PackCreated.js +31 -0
  6. package/dist/cjs/extensions/pack/__generated__/IPack/events/PackCreated.js.map +1 -0
  7. package/dist/cjs/extensions/pack/__generated__/IPack/events/PackOpened.js +32 -0
  8. package/dist/cjs/extensions/pack/__generated__/IPack/events/PackOpened.js.map +1 -0
  9. package/dist/cjs/extensions/pack/__generated__/IPack/events/PackUpdated.js +31 -0
  10. package/dist/cjs/extensions/pack/__generated__/IPack/events/PackUpdated.js.map +1 -0
  11. package/dist/cjs/extensions/pack/__generated__/IPack/read/canUpdatePack.js +114 -0
  12. package/dist/cjs/extensions/pack/__generated__/IPack/read/canUpdatePack.js.map +1 -0
  13. package/dist/cjs/extensions/pack/__generated__/IPack/read/getPackContents.js +137 -0
  14. package/dist/cjs/extensions/pack/__generated__/IPack/read/getPackContents.js.map +1 -0
  15. package/dist/cjs/extensions/pack/__generated__/IPack/read/getTokenCountOfBundle.js +114 -0
  16. package/dist/cjs/extensions/pack/__generated__/IPack/read/getTokenCountOfBundle.js.map +1 -0
  17. package/dist/cjs/extensions/pack/__generated__/IPack/read/getTokenOfBundle.js +139 -0
  18. package/dist/cjs/extensions/pack/__generated__/IPack/read/getTokenOfBundle.js.map +1 -0
  19. package/dist/cjs/extensions/pack/__generated__/IPack/read/getUriOfBundle.js +114 -0
  20. package/dist/cjs/extensions/pack/__generated__/IPack/read/getUriOfBundle.js.map +1 -0
  21. package/dist/cjs/extensions/pack/__generated__/IPack/write/addPackContents.js +175 -0
  22. package/dist/cjs/extensions/pack/__generated__/IPack/write/addPackContents.js.map +1 -0
  23. package/dist/cjs/extensions/pack/__generated__/IPack/write/createPack.js +193 -0
  24. package/dist/cjs/extensions/pack/__generated__/IPack/write/createPack.js.map +1 -0
  25. package/dist/cjs/extensions/pack/__generated__/IPack/write/openPack.js +146 -0
  26. package/dist/cjs/extensions/pack/__generated__/IPack/write/openPack.js.map +1 -0
  27. package/dist/cjs/extensions/pack/__generated__/IPackVRFDirect/events/PackOpenRequested.js +32 -0
  28. package/dist/cjs/extensions/pack/__generated__/IPackVRFDirect/events/PackOpenRequested.js.map +1 -0
  29. package/dist/cjs/extensions/pack/__generated__/IPackVRFDirect/events/PackRandomnessFulfilled.js +32 -0
  30. package/dist/cjs/extensions/pack/__generated__/IPackVRFDirect/events/PackRandomnessFulfilled.js.map +1 -0
  31. package/dist/cjs/extensions/pack/__generated__/IPackVRFDirect/read/canClaimRewards.js +114 -0
  32. package/dist/cjs/extensions/pack/__generated__/IPackVRFDirect/read/canClaimRewards.js.map +1 -0
  33. package/dist/cjs/extensions/pack/__generated__/IPackVRFDirect/write/claimRewards.js +74 -0
  34. package/dist/cjs/extensions/pack/__generated__/IPackVRFDirect/write/claimRewards.js.map +1 -0
  35. package/dist/cjs/extensions/pack/__generated__/IPackVRFDirect/write/openPackAndClaimRewards.js +143 -0
  36. package/dist/cjs/extensions/pack/__generated__/IPackVRFDirect/write/openPackAndClaimRewards.js.map +1 -0
  37. package/dist/cjs/extensions/pack/createNewPack.js +285 -0
  38. package/dist/cjs/extensions/pack/createNewPack.js.map +1 -0
  39. package/dist/cjs/extensions/prebuilts/__generated__/Pack/write/initialize.js +175 -0
  40. package/dist/cjs/extensions/prebuilts/__generated__/Pack/write/initialize.js.map +1 -0
  41. package/dist/cjs/extensions/prebuilts/deploy-pack.js +115 -0
  42. package/dist/cjs/extensions/prebuilts/deploy-pack.js.map +1 -0
  43. package/dist/cjs/rpc/watchBlockNumber.js +2 -8
  44. package/dist/cjs/rpc/watchBlockNumber.js.map +1 -1
  45. package/dist/cjs/utils/sleep.js +12 -0
  46. package/dist/cjs/utils/sleep.js.map +1 -0
  47. package/dist/cjs/version.js +1 -1
  48. package/dist/cjs/version.js.map +1 -1
  49. package/dist/cjs/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.js +4 -8
  50. package/dist/cjs/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.js.map +1 -1
  51. package/dist/esm/exports/deploys.js +1 -0
  52. package/dist/esm/exports/deploys.js.map +1 -1
  53. package/dist/esm/exports/extensions/pack.js +12 -0
  54. package/dist/esm/exports/extensions/pack.js.map +1 -0
  55. package/dist/esm/extensions/pack/__generated__/IPack/events/PackCreated.js +28 -0
  56. package/dist/esm/extensions/pack/__generated__/IPack/events/PackCreated.js.map +1 -0
  57. package/dist/esm/extensions/pack/__generated__/IPack/events/PackOpened.js +29 -0
  58. package/dist/esm/extensions/pack/__generated__/IPack/events/PackOpened.js.map +1 -0
  59. package/dist/esm/extensions/pack/__generated__/IPack/events/PackUpdated.js +28 -0
  60. package/dist/esm/extensions/pack/__generated__/IPack/events/PackUpdated.js.map +1 -0
  61. package/dist/esm/extensions/pack/__generated__/IPack/read/canUpdatePack.js +106 -0
  62. package/dist/esm/extensions/pack/__generated__/IPack/read/canUpdatePack.js.map +1 -0
  63. package/dist/esm/extensions/pack/__generated__/IPack/read/getPackContents.js +129 -0
  64. package/dist/esm/extensions/pack/__generated__/IPack/read/getPackContents.js.map +1 -0
  65. package/dist/esm/extensions/pack/__generated__/IPack/read/getTokenCountOfBundle.js +106 -0
  66. package/dist/esm/extensions/pack/__generated__/IPack/read/getTokenCountOfBundle.js.map +1 -0
  67. package/dist/esm/extensions/pack/__generated__/IPack/read/getTokenOfBundle.js +131 -0
  68. package/dist/esm/extensions/pack/__generated__/IPack/read/getTokenOfBundle.js.map +1 -0
  69. package/dist/esm/extensions/pack/__generated__/IPack/read/getUriOfBundle.js +106 -0
  70. package/dist/esm/extensions/pack/__generated__/IPack/read/getUriOfBundle.js.map +1 -0
  71. package/dist/esm/extensions/pack/__generated__/IPack/write/addPackContents.js +168 -0
  72. package/dist/esm/extensions/pack/__generated__/IPack/write/addPackContents.js.map +1 -0
  73. package/dist/esm/extensions/pack/__generated__/IPack/write/createPack.js +186 -0
  74. package/dist/esm/extensions/pack/__generated__/IPack/write/createPack.js.map +1 -0
  75. package/dist/esm/extensions/pack/__generated__/IPack/write/openPack.js +139 -0
  76. package/dist/esm/extensions/pack/__generated__/IPack/write/openPack.js.map +1 -0
  77. package/dist/esm/extensions/pack/__generated__/IPackVRFDirect/events/PackOpenRequested.js +29 -0
  78. package/dist/esm/extensions/pack/__generated__/IPackVRFDirect/events/PackOpenRequested.js.map +1 -0
  79. package/dist/esm/extensions/pack/__generated__/IPackVRFDirect/events/PackRandomnessFulfilled.js +29 -0
  80. package/dist/esm/extensions/pack/__generated__/IPackVRFDirect/events/PackRandomnessFulfilled.js.map +1 -0
  81. package/dist/esm/extensions/pack/__generated__/IPackVRFDirect/read/canClaimRewards.js +106 -0
  82. package/dist/esm/extensions/pack/__generated__/IPackVRFDirect/read/canClaimRewards.js.map +1 -0
  83. package/dist/esm/extensions/pack/__generated__/IPackVRFDirect/write/claimRewards.js +69 -0
  84. package/dist/esm/extensions/pack/__generated__/IPackVRFDirect/write/claimRewards.js.map +1 -0
  85. package/dist/esm/extensions/pack/__generated__/IPackVRFDirect/write/openPackAndClaimRewards.js +136 -0
  86. package/dist/esm/extensions/pack/__generated__/IPackVRFDirect/write/openPackAndClaimRewards.js.map +1 -0
  87. package/dist/esm/extensions/pack/createNewPack.js +281 -0
  88. package/dist/esm/extensions/pack/createNewPack.js.map +1 -0
  89. package/dist/esm/extensions/prebuilts/__generated__/Pack/write/initialize.js +168 -0
  90. package/dist/esm/extensions/prebuilts/__generated__/Pack/write/initialize.js.map +1 -0
  91. package/dist/esm/extensions/prebuilts/deploy-pack.js +112 -0
  92. package/dist/esm/extensions/prebuilts/deploy-pack.js.map +1 -0
  93. package/dist/esm/rpc/watchBlockNumber.js +1 -7
  94. package/dist/esm/rpc/watchBlockNumber.js.map +1 -1
  95. package/dist/esm/utils/sleep.js +9 -0
  96. package/dist/esm/utils/sleep.js.map +1 -0
  97. package/dist/esm/version.js +1 -1
  98. package/dist/esm/version.js.map +1 -1
  99. package/dist/esm/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.js +4 -8
  100. package/dist/esm/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.js.map +1 -1
  101. package/dist/types/exports/deploys.d.ts +1 -0
  102. package/dist/types/exports/deploys.d.ts.map +1 -1
  103. package/dist/types/exports/extensions/pack.d.ts +9 -0
  104. package/dist/types/exports/extensions/pack.d.ts.map +1 -0
  105. package/dist/types/extensions/pack/__generated__/IPack/events/PackCreated.d.ts +47 -0
  106. package/dist/types/extensions/pack/__generated__/IPack/events/PackCreated.d.ts.map +1 -0
  107. package/dist/types/extensions/pack/__generated__/IPack/events/PackOpened.d.ts +70 -0
  108. package/dist/types/extensions/pack/__generated__/IPack/events/PackOpened.d.ts.map +1 -0
  109. package/dist/types/extensions/pack/__generated__/IPack/events/PackUpdated.d.ts +47 -0
  110. package/dist/types/extensions/pack/__generated__/IPack/events/PackUpdated.d.ts.map +1 -0
  111. package/dist/types/extensions/pack/__generated__/IPack/read/canUpdatePack.d.ts +83 -0
  112. package/dist/types/extensions/pack/__generated__/IPack/read/canUpdatePack.d.ts.map +1 -0
  113. package/dist/types/extensions/pack/__generated__/IPack/read/getPackContents.d.ts +93 -0
  114. package/dist/types/extensions/pack/__generated__/IPack/read/getPackContents.d.ts.map +1 -0
  115. package/dist/types/extensions/pack/__generated__/IPack/read/getTokenCountOfBundle.d.ts +83 -0
  116. package/dist/types/extensions/pack/__generated__/IPack/read/getTokenCountOfBundle.d.ts.map +1 -0
  117. package/dist/types/extensions/pack/__generated__/IPack/read/getTokenOfBundle.d.ts +100 -0
  118. package/dist/types/extensions/pack/__generated__/IPack/read/getTokenOfBundle.d.ts.map +1 -0
  119. package/dist/types/extensions/pack/__generated__/IPack/read/getUriOfBundle.d.ts +83 -0
  120. package/dist/types/extensions/pack/__generated__/IPack/read/getUriOfBundle.d.ts.map +1 -0
  121. package/dist/types/extensions/pack/__generated__/IPack/write/addPackContents.d.ts +118 -0
  122. package/dist/types/extensions/pack/__generated__/IPack/write/addPackContents.d.ts.map +1 -0
  123. package/dist/types/extensions/pack/__generated__/IPack/write/createPack.d.ts +132 -0
  124. package/dist/types/extensions/pack/__generated__/IPack/write/createPack.d.ts.map +1 -0
  125. package/dist/types/extensions/pack/__generated__/IPack/write/openPack.d.ts +86 -0
  126. package/dist/types/extensions/pack/__generated__/IPack/write/openPack.d.ts.map +1 -0
  127. package/dist/types/extensions/pack/__generated__/IPackVRFDirect/events/PackOpenRequested.d.ts +57 -0
  128. package/dist/types/extensions/pack/__generated__/IPackVRFDirect/events/PackOpenRequested.d.ts.map +1 -0
  129. package/dist/types/extensions/pack/__generated__/IPackVRFDirect/events/PackRandomnessFulfilled.d.ts +51 -0
  130. package/dist/types/extensions/pack/__generated__/IPackVRFDirect/events/PackRandomnessFulfilled.d.ts.map +1 -0
  131. package/dist/types/extensions/pack/__generated__/IPackVRFDirect/read/canClaimRewards.d.ts +83 -0
  132. package/dist/types/extensions/pack/__generated__/IPackVRFDirect/read/canClaimRewards.d.ts.map +1 -0
  133. package/dist/types/extensions/pack/__generated__/IPackVRFDirect/write/claimRewards.d.ts +33 -0
  134. package/dist/types/extensions/pack/__generated__/IPackVRFDirect/write/claimRewards.d.ts.map +1 -0
  135. package/dist/types/extensions/pack/__generated__/IPackVRFDirect/write/openPackAndClaimRewards.d.ts +93 -0
  136. package/dist/types/extensions/pack/__generated__/IPackVRFDirect/write/openPackAndClaimRewards.d.ts.map +1 -0
  137. package/dist/types/extensions/pack/createNewPack.d.ts +104 -0
  138. package/dist/types/extensions/pack/createNewPack.d.ts.map +1 -0
  139. package/dist/types/extensions/prebuilts/__generated__/Pack/write/initialize.d.ts +121 -0
  140. package/dist/types/extensions/prebuilts/__generated__/Pack/write/initialize.d.ts.map +1 -0
  141. package/dist/types/extensions/prebuilts/deploy-pack.d.ts +62 -0
  142. package/dist/types/extensions/prebuilts/deploy-pack.d.ts.map +1 -0
  143. package/dist/types/rpc/watchBlockNumber.d.ts.map +1 -1
  144. package/dist/types/utils/sleep.d.ts +7 -0
  145. package/dist/types/utils/sleep.d.ts.map +1 -0
  146. package/dist/types/version.d.ts +1 -1
  147. package/dist/types/version.d.ts.map +1 -1
  148. package/dist/types/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.d.ts.map +1 -1
  149. package/package.json +1 -1
  150. package/src/exports/deploys.ts +6 -0
  151. package/src/exports/extensions/pack.ts +42 -0
  152. package/src/extensions/erc1155/drops/read/getActiveClaimCondition.test.ts +6 -4
  153. package/src/extensions/erc721/drops/write/updateMetadata.test.ts +2 -2
  154. package/src/extensions/erc721/read/getTotalClaimedSupply.test.ts +2 -2
  155. package/src/extensions/erc721/read/getTotalUnclaimedSupply.test.ts +2 -2
  156. package/src/extensions/erc721/write/updateTokenURI.test.ts +2 -2
  157. package/src/extensions/pack/__generated__/IPack/events/PackCreated.ts +41 -0
  158. package/src/extensions/pack/__generated__/IPack/events/PackOpened.ts +47 -0
  159. package/src/extensions/pack/__generated__/IPack/events/PackUpdated.ts +41 -0
  160. package/src/extensions/pack/__generated__/IPack/read/canUpdatePack.ts +125 -0
  161. package/src/extensions/pack/__generated__/IPack/read/getPackContents.ts +148 -0
  162. package/src/extensions/pack/__generated__/IPack/read/getTokenCountOfBundle.ts +129 -0
  163. package/src/extensions/pack/__generated__/IPack/read/getTokenOfBundle.ts +151 -0
  164. package/src/extensions/pack/__generated__/IPack/read/getUriOfBundle.ts +125 -0
  165. package/src/extensions/pack/__generated__/IPack/write/addPackContents.ts +213 -0
  166. package/src/extensions/pack/__generated__/IPack/write/createPack.ts +239 -0
  167. package/src/extensions/pack/__generated__/IPack/write/openPack.ts +168 -0
  168. package/src/extensions/pack/__generated__/IPackVRFDirect/events/PackOpenRequested.ts +49 -0
  169. package/src/extensions/pack/__generated__/IPackVRFDirect/events/PackRandomnessFulfilled.ts +49 -0
  170. package/src/extensions/pack/__generated__/IPackVRFDirect/read/canClaimRewards.ts +125 -0
  171. package/src/extensions/pack/__generated__/IPackVRFDirect/write/claimRewards.ts +73 -0
  172. package/src/extensions/pack/__generated__/IPackVRFDirect/write/openPackAndClaimRewards.ts +177 -0
  173. package/src/extensions/pack/createNewPack.test.ts +207 -0
  174. package/src/extensions/pack/createNewPack.ts +433 -0
  175. package/src/extensions/prebuilts/__generated__/Pack/write/initialize.ts +216 -0
  176. package/src/extensions/prebuilts/deploy-erc20.test.ts +5 -3
  177. package/src/extensions/prebuilts/deploy-erc721.test.ts +6 -4
  178. package/src/extensions/prebuilts/deploy-pack.test.ts +23 -0
  179. package/src/extensions/prebuilts/deploy-pack.ts +173 -0
  180. package/src/extensions/prebuilts/deploy-split.test.ts +2 -2
  181. package/src/extensions/prebuilts/deploy-vote.test.ts +7 -5
  182. package/src/extensions/split/read/getAllRecipientsAddresses.test.ts +2 -2
  183. package/src/extensions/split/read/getAllRecipientsPercentages.test.ts +2 -2
  184. package/src/extensions/split/read/getRecipientSplitPercentage.test.ts +4 -2
  185. package/src/extensions/vote/read/proposalExists.test.ts +6 -6
  186. package/src/rpc/watchBlockNumber.ts +1 -8
  187. package/src/utils/sleep.ts +8 -0
  188. package/src/version.ts +1 -1
  189. package/src/wallets/in-app/web/utils/iFrameCommunication/IframeCommunicator.ts +5 -9
  190. package/src/wallets/smart/smart-wallet-integration-v07.test.ts +11 -8
  191. package/src/wallets/utils/getTokenBalance.test.ts +8 -6
@@ -0,0 +1,207 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import { ANVIL_CHAIN } from "~test/chains.js";
3
+ import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
4
+ import { TEST_CLIENT } from "~test/test-clients.js";
5
+ import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
6
+ import { getContract } from "../../contract/contract.js";
7
+ import { download } from "../../storage/download.js";
8
+ import { sendAndConfirmTransaction } from "../../transaction/actions/send-and-confirm-transaction.js";
9
+ import { balanceOf as balanceOfERC20 } from "../erc20/__generated__/IERC20/read/balanceOf.js";
10
+ import { approve } from "../erc20/write/approve.js";
11
+ import { mintTo as mintToERC20 } from "../erc20/write/mintTo.js";
12
+ import { balanceOf as balanceOfERC721 } from "../erc721/__generated__/IERC721A/read/balanceOf.js";
13
+ import { ownerOf } from "../erc721/__generated__/IERC721A/read/ownerOf.js";
14
+ import { setApprovalForAll } from "../erc721/__generated__/IERC721A/write/setApprovalForAll.js";
15
+ import { mintTo as mintToERC721 } from "../erc721/write/mintTo.js";
16
+ import { openPack } from "../erc1155/__generated__/IPack/write/openPack.js";
17
+ import { getPackContents } from "../pack/__generated__/IPack/read/getPackContents.js";
18
+ import { getTokenCountOfBundle } from "../pack/__generated__/IPack/read/getTokenCountOfBundle.js";
19
+ import { getUriOfBundle } from "../pack/__generated__/IPack/read/getUriOfBundle.js";
20
+ import { deployERC20Contract } from "../prebuilts/deploy-erc20.js";
21
+ import { deployERC721Contract } from "../prebuilts/deploy-erc721.js";
22
+ import { deployPackContract } from "../prebuilts/deploy-pack.js";
23
+ import { createNewPack } from "./createNewPack.js";
24
+
25
+ const account = TEST_ACCOUNT_A;
26
+ const client = TEST_CLIENT;
27
+ const chain = ANVIL_CHAIN;
28
+
29
+ describe.runIf(process.env.TW_SECRET_KEY)("createPack", () => {
30
+ it("should create a Pack and open it to receive rewards", async () => {
31
+ const packAddress = await deployPackContract({
32
+ account,
33
+ client,
34
+ chain,
35
+ params: {
36
+ name: "pack-contract",
37
+ },
38
+ });
39
+
40
+ const packContract = getContract({
41
+ address: packAddress,
42
+ chain,
43
+ client,
44
+ });
45
+
46
+ const erc20Address = await deployERC20Contract({
47
+ client: TEST_CLIENT,
48
+ chain: ANVIL_CHAIN,
49
+ account: TEST_ACCOUNT_A,
50
+ type: "TokenERC20",
51
+ params: {
52
+ name: "Token",
53
+ contractURI: TEST_CONTRACT_URI,
54
+ },
55
+ });
56
+
57
+ const erc20Contract = getContract({ address: erc20Address, chain, client });
58
+
59
+ const erc721Address = await deployERC721Contract({
60
+ client: TEST_CLIENT,
61
+ chain: ANVIL_CHAIN,
62
+ account: TEST_ACCOUNT_A,
63
+ type: "TokenERC721",
64
+ params: {
65
+ name: "NFTCollection",
66
+ contractURI: TEST_CONTRACT_URI,
67
+ },
68
+ });
69
+
70
+ const erc721Contract = getContract({
71
+ address: erc721Address,
72
+ chain,
73
+ client,
74
+ });
75
+ // Mint some ERC20 tokens
76
+ await sendAndConfirmTransaction({
77
+ transaction: mintToERC20({
78
+ contract: erc20Contract,
79
+ to: account.address,
80
+ amount: "100",
81
+ }),
82
+ account,
83
+ });
84
+
85
+ // Set allowance for Pack contract
86
+ await sendAndConfirmTransaction({
87
+ transaction: approve({
88
+ contract: erc20Contract,
89
+ amount: "1000000000000000",
90
+ spender: packContract.address,
91
+ }),
92
+ account,
93
+ });
94
+
95
+ // Mint some ERC721 tokens
96
+ await sendAndConfirmTransaction({
97
+ transaction: mintToERC721({
98
+ contract: erc721Contract,
99
+ to: account.address,
100
+ nft: { name: "token #0" },
101
+ }),
102
+ account,
103
+ });
104
+
105
+ // set erc721 approval
106
+ await sendAndConfirmTransaction({
107
+ transaction: setApprovalForAll({
108
+ contract: erc721Contract,
109
+ approved: true,
110
+ operator: packContract.address,
111
+ }),
112
+ account,
113
+ });
114
+
115
+ // Create pack
116
+ await sendAndConfirmTransaction({
117
+ transaction: createNewPack({
118
+ contract: packContract,
119
+ erc20Rewards: [
120
+ {
121
+ contractAddress: erc20Contract.address,
122
+ totalRewards: 1,
123
+ quantityPerReward: 1,
124
+ },
125
+ ],
126
+ erc721Rewards: [
127
+ { contractAddress: erc721Contract.address, tokenId: 0n },
128
+ ],
129
+ client,
130
+ packMetadata: {
131
+ name: "Pack #0",
132
+ },
133
+ recipient: account.address,
134
+ tokenOwner: account.address,
135
+ openStartTimestamp: new Date(),
136
+ amountDistributedPerOpen: 1n,
137
+ }),
138
+ account,
139
+ });
140
+
141
+ // Read the info of the new Pack
142
+ const [
143
+ packContent,
144
+ tokenCountOfBundle,
145
+ bundleUri,
146
+ erc20BalanceAfterCreatePack,
147
+ erc721BalanceAfterCreatePack,
148
+ ] = await Promise.all([
149
+ getPackContents({ contract: packContract, packId: 0n }),
150
+ getTokenCountOfBundle({ contract: packContract, bundleId: 0n }),
151
+ getUriOfBundle({ contract: packContract, bundleId: 0n }),
152
+ balanceOfERC20({ contract: erc20Contract, address: account.address }),
153
+ balanceOfERC721({ contract: erc721Contract, owner: account.address }),
154
+ ]);
155
+
156
+ // After this, the account should have 99 ERC20 tokens, and 0 (zero) ERC721 token
157
+ expect(erc20BalanceAfterCreatePack).toBe(99n * 10n ** 18n);
158
+ expect(erc721BalanceAfterCreatePack).toBe(0n);
159
+
160
+ // Make sure the content is correct
161
+ expect(packContent).toStrictEqual([
162
+ [
163
+ {
164
+ assetContract: erc20Contract.address,
165
+ tokenType: 0,
166
+ tokenId: 0n,
167
+ totalAmount: 1000000000000000000n,
168
+ },
169
+ {
170
+ assetContract: erc721Contract.address,
171
+ tokenType: 1,
172
+ tokenId: 0n,
173
+ totalAmount: 1n,
174
+ },
175
+ ],
176
+ [1000000000000000000n, 1n],
177
+ ]);
178
+ expect(tokenCountOfBundle).toBe(2n);
179
+
180
+ // Make sure the Pack metadata is correct
181
+ expect(bundleUri).toBeDefined();
182
+ const metadata = await (await download({ client, uri: bundleUri })).json();
183
+ expect(metadata?.name).toBe("Pack #0");
184
+
185
+ // Make sure you can open the Pack, since the open-date was set to "now"
186
+ await sendAndConfirmTransaction({
187
+ account,
188
+ transaction: openPack({
189
+ contract: packContract,
190
+ packId: 0n,
191
+ amountToOpen: 1n,
192
+ }),
193
+ });
194
+
195
+ const [erc20Balance, erc721Owner] = await Promise.all([
196
+ balanceOfERC20({ contract: erc20Contract, address: account.address }),
197
+ ownerOf({ contract: erc721Contract, tokenId: 0n }),
198
+ ]);
199
+
200
+ // Since opening a Pack gives "random" rewards, in this case we can check if
201
+ // the recipient received either 1. <one ERC20 token>, or 2. <one ERC721 token>
202
+ expect(
203
+ erc20Balance === 100n * 10n ** 18n ||
204
+ erc721Owner.toLowerCase() === account.address.toLowerCase(),
205
+ ).toBe(true);
206
+ });
207
+ });
@@ -0,0 +1,433 @@
1
+ import type { ThirdwebClient } from "../../client/client.js";
2
+ import { type ThirdwebContract, getContract } from "../../contract/contract.js";
3
+ import { upload } from "../../storage/upload.js";
4
+ import type { BaseTransactionOptions } from "../../transaction/types.js";
5
+ import type { NFTInput } from "../../utils/nft/parseNft.js";
6
+ import { toUnits } from "../../utils/units.js";
7
+ import type { AddPackContentsParams } from "./__generated__/IPack/write/addPackContents.js";
8
+ import {
9
+ type CreatePackParams,
10
+ createPack,
11
+ } from "./__generated__/IPack/write/createPack.js";
12
+
13
+ export enum PACK_TOKEN_TYPE {
14
+ ERC20 = 0,
15
+ ERC721 = 1,
16
+ ERC1155 = 2,
17
+ }
18
+
19
+ export type ERC20Reward = {
20
+ contractAddress: string;
21
+ quantityPerReward: number | string;
22
+ totalRewards: number | string;
23
+ };
24
+
25
+ export type ERC721Reward = {
26
+ contractAddress: string;
27
+ tokenId: bigint;
28
+ };
29
+
30
+ export type ERC1155Reward = {
31
+ contractAddress: string;
32
+ tokenId: bigint;
33
+ quantityPerReward: number | string;
34
+ totalRewards: number | string;
35
+ };
36
+
37
+ /**
38
+ * @extension PACK
39
+ */
40
+ export type CreateNewPackParams = {
41
+ client: ThirdwebClient;
42
+ contract: ThirdwebContract;
43
+ /**
44
+ * The address of the reward recipient
45
+ */
46
+ recipient: string;
47
+ /**
48
+ * The address of the entity who owns the tokens that are used as rewards.
49
+ * This is only used for checking token approval
50
+ */
51
+ tokenOwner: string;
52
+ /**
53
+ * The metadata (image, description, etc.) of the Pack.
54
+ * This is similar to an NFT's metadata
55
+ */
56
+ packMetadata: NFTInput | string;
57
+ amountDistributedPerOpen: bigint;
58
+ /**
59
+ * JavaScript Date object
60
+ */
61
+ openStartTimestamp: Date;
62
+ /**
63
+ * An array of ERC20 rewards, see type `ERC20Reward` for more info
64
+ */
65
+ erc20Rewards?: ERC20Reward[];
66
+ /**
67
+ * An array of ERC721 rewards, see type `ERC721Reward` for more info
68
+ */
69
+ erc721Rewards?: ERC721Reward[];
70
+ /**
71
+ * An array of ERC1155 rewards, see type `ERC1155Reward` for more info
72
+ */
73
+ erc1155Rewards?: ERC1155Reward[];
74
+ };
75
+
76
+ /**
77
+ * @extension PACK
78
+ * @example
79
+ * ```ts
80
+ * import { createNewPack } from "thirdweb/extensions/pack";
81
+ *
82
+ * const transaction = createNewPack({
83
+ * contract: packContract,
84
+ * client,
85
+ * recipient: "0x...",
86
+ * tokenOwner: "0x...",
87
+ * packMetadata: {
88
+ * name: "Pack #1",
89
+ * image: "image-of-pack-1",
90
+ * },
91
+ * openStartTimestamp: new Date(),
92
+ * erc20Rewards: [
93
+ * {
94
+ * contractAddress: "0x...",
95
+ * quantityPerReward: 1,
96
+ * totalRewards: 1,
97
+ * },
98
+ * ],
99
+ * erc721Rewards: [
100
+ * {
101
+ * contractAddress: "0x...",
102
+ * tokenId: 0n,
103
+ * },
104
+ * ],
105
+ * erc1155Rewards: [
106
+ * {
107
+ * contractAddress: "0x...",
108
+ * tokenId: 0n,
109
+ * quantityPerReward: 1,
110
+ * totalRewards: 1,
111
+ * },
112
+ * ],
113
+ * });
114
+ * ```
115
+ */
116
+ export function createNewPack(
117
+ options: BaseTransactionOptions<CreateNewPackParams>,
118
+ ) {
119
+ return createPack({
120
+ contract: options.contract,
121
+ asyncParams: async () => getCreatePackParams(options),
122
+ });
123
+ }
124
+
125
+ /**
126
+ * @internal
127
+ */
128
+ async function getCreatePackParams(
129
+ options: BaseTransactionOptions<CreateNewPackParams>,
130
+ ): Promise<CreatePackParams> {
131
+ const {
132
+ contract,
133
+ recipient,
134
+ packMetadata,
135
+ amountDistributedPerOpen,
136
+ openStartTimestamp,
137
+ erc20Rewards,
138
+ erc721Rewards,
139
+ erc1155Rewards,
140
+ tokenOwner,
141
+ } = options;
142
+ const [erc20Content, erc721Content, erc1155Content, packUri] =
143
+ await Promise.all([
144
+ processErc20Rewards({
145
+ packContract: contract,
146
+ content: erc20Rewards,
147
+ tokenOwner,
148
+ }),
149
+ processErc721Rewards({
150
+ packContract: contract,
151
+ content: erc721Rewards,
152
+ tokenOwner,
153
+ }),
154
+ processErc1155Rewards({
155
+ packContract: contract,
156
+ content: erc1155Rewards,
157
+ tokenOwner,
158
+ }),
159
+ typeof packMetadata === "string"
160
+ ? packMetadata
161
+ : upload({
162
+ client: options.contract.client,
163
+ files: [packMetadata],
164
+ }),
165
+ ]);
166
+ const contents = erc20Content.content
167
+ .concat(erc721Content.content)
168
+ .concat(erc1155Content.content);
169
+
170
+ const numOfRewardUnits = erc20Content.numOfRewardUnits
171
+ .concat(erc721Content.numOfRewardUnits)
172
+ .concat(erc1155Content.numOfRewardUnits);
173
+
174
+ return {
175
+ packUri,
176
+ recipient,
177
+ contents,
178
+ numOfRewardUnits,
179
+ // openStartTimestamp should be in seconds and not millisecond
180
+ openStartTimestamp: BigInt(Math.ceil(openStartTimestamp.getTime() / 1000)),
181
+ amountDistributedPerOpen,
182
+ };
183
+ }
184
+
185
+ /**
186
+ * @internal
187
+ */
188
+ async function processErc20Rewards(options: {
189
+ content?: ERC20Reward[];
190
+ packContract: ThirdwebContract;
191
+ tokenOwner: string;
192
+ }): Promise<{
193
+ content: AddPackContentsParams["contents"];
194
+ numOfRewardUnits: bigint[];
195
+ }> {
196
+ const { content, packContract, tokenOwner } = options;
197
+ if (!content?.length) {
198
+ return {
199
+ content: [],
200
+ numOfRewardUnits: [],
201
+ };
202
+ }
203
+ const [{ allowance }, { decimals }] = await Promise.all([
204
+ import("../erc20/__generated__/IERC20/read/allowance.js"),
205
+ import("../erc20/__generated__/IERC20/read/decimals.js"),
206
+ ]);
207
+
208
+ const uniqueERC20Contracts = [
209
+ ...new Set(
210
+ content.map((o) =>
211
+ getContract({
212
+ address: o.contractAddress,
213
+ chain: packContract.chain,
214
+ client: packContract.client,
215
+ }),
216
+ ),
217
+ ),
218
+ ];
219
+
220
+ const data: Array<{
221
+ _allowance: bigint;
222
+ _decimals: number;
223
+ address: string;
224
+ }> = (
225
+ await Promise.all(
226
+ uniqueERC20Contracts.map((contract) => {
227
+ return Promise.all([
228
+ allowance({
229
+ contract,
230
+ spender: packContract.address,
231
+ owner: tokenOwner,
232
+ }),
233
+ decimals({ contract }).catch(() => undefined),
234
+ contract.address,
235
+ ]);
236
+ }),
237
+ )
238
+ ).map((item) => {
239
+ const [_allowance, _decimals, address] = item;
240
+ if (_decimals === undefined) {
241
+ throw new Error(
242
+ `Failed to get the decimals of contract: ${address}. Make sure it is a valid ERC20 contract`,
243
+ );
244
+ }
245
+ return {
246
+ _allowance,
247
+ _decimals,
248
+ address,
249
+ };
250
+ });
251
+ const numOfRewardUnits: bigint[] = [];
252
+ const result = content.map((item, index) => {
253
+ const { contractAddress, quantityPerReward, totalRewards } = item;
254
+ if (!totalRewards) {
255
+ throw new Error(
256
+ `Invalid totalRewards for contract: ${contractAddress} at index: ${index}`,
257
+ );
258
+ }
259
+ const _data = data.find((o) => o.address === contractAddress);
260
+ if (!_data) {
261
+ // This should never happen
262
+ throw new Error(`contractAddress not found: ${contractAddress}`);
263
+ }
264
+ const quantityInWei = toUnits(String(quantityPerReward), _data._decimals);
265
+ const totalRequired = quantityInWei * BigInt(totalRewards);
266
+ if (totalRequired > _data._allowance) {
267
+ throw new Error(
268
+ `The following ERC20 contract address do not have enough allowance for the Pack contract: ${contractAddress}`,
269
+ );
270
+ }
271
+ numOfRewardUnits.push(BigInt(item.totalRewards));
272
+ return {
273
+ assetContract: contractAddress,
274
+ tokenType: PACK_TOKEN_TYPE.ERC20,
275
+ tokenId: 0n, // hard-coded to `0n` for ERC20
276
+ totalAmount: totalRequired,
277
+ };
278
+ });
279
+
280
+ return {
281
+ content: result,
282
+ numOfRewardUnits,
283
+ };
284
+ }
285
+
286
+ /**
287
+ * @internal
288
+ */
289
+ async function processErc721Rewards(options: {
290
+ content?: ERC721Reward[];
291
+ packContract: ThirdwebContract;
292
+ tokenOwner: string;
293
+ }): Promise<{
294
+ content: AddPackContentsParams["contents"];
295
+ numOfRewardUnits: bigint[];
296
+ }> {
297
+ const { content, packContract, tokenOwner } = options;
298
+ if (!content?.length) {
299
+ return {
300
+ content: [],
301
+ numOfRewardUnits: [],
302
+ };
303
+ }
304
+ const uniqueERC721Contracts = [
305
+ ...new Set(
306
+ content.map((o) => ({
307
+ contract: getContract({
308
+ address: o.contractAddress,
309
+ chain: packContract.chain,
310
+ client: packContract.client,
311
+ }),
312
+ tokenId: o.tokenId,
313
+ })),
314
+ ),
315
+ ];
316
+ const [{ isApprovedForAll }, { getApproved }] = await Promise.all([
317
+ import("../erc721/__generated__/IERC721A/read/isApprovedForAll.js"),
318
+ import("../erc721/__generated__/IERC721A/read/getApproved.js"),
319
+ ]);
320
+ const numOfRewardUnits: bigint[] = [];
321
+ const result = (
322
+ await Promise.all(
323
+ uniqueERC721Contracts.map(({ contract, tokenId }) => {
324
+ return Promise.all([
325
+ isApprovedForAll({
326
+ contract,
327
+ operator: packContract.address,
328
+ owner: tokenOwner,
329
+ }).catch(() => false),
330
+ getApproved({ contract, tokenId }).catch(() => ""),
331
+ contract.address,
332
+ tokenId,
333
+ ]);
334
+ }),
335
+ )
336
+ ).map((item) => {
337
+ const [_allApproved, _tokenApprove, address, tokenId] = item;
338
+ if (
339
+ !_allApproved &&
340
+ _tokenApprove.toLowerCase() !== packContract.address.toLowerCase()
341
+ ) {
342
+ throw new Error(
343
+ `TokenID: ${tokenId} from contract address ${address} is not approved to be used by this Pack contract.`,
344
+ );
345
+ }
346
+ numOfRewardUnits.push(1n);
347
+ return {
348
+ assetContract: address,
349
+ tokenType: PACK_TOKEN_TYPE.ERC721,
350
+ tokenId,
351
+ totalAmount: 1n,
352
+ };
353
+ });
354
+
355
+ return {
356
+ content: result,
357
+ numOfRewardUnits,
358
+ };
359
+ }
360
+
361
+ async function processErc1155Rewards(options: {
362
+ content?: ERC1155Reward[];
363
+ packContract: ThirdwebContract;
364
+ tokenOwner: string;
365
+ }): Promise<{
366
+ content: AddPackContentsParams["contents"];
367
+ numOfRewardUnits: bigint[];
368
+ }> {
369
+ const { content, packContract, tokenOwner } = options;
370
+ if (!content?.length) {
371
+ return {
372
+ content: [],
373
+ numOfRewardUnits: [],
374
+ };
375
+ }
376
+ const uniqueERC1155Contracts = [
377
+ ...new Set(
378
+ content.map((o) => ({
379
+ contract: getContract({
380
+ address: o.contractAddress,
381
+ chain: packContract.chain,
382
+ client: packContract.client,
383
+ }),
384
+ tokenId: o.tokenId,
385
+ quantityPerReward: o.quantityPerReward,
386
+ totalRewards: o.totalRewards,
387
+ })),
388
+ ),
389
+ ];
390
+ const { isApprovedForAll } = await import(
391
+ "../erc1155/__generated__/IERC1155/read/isApprovedForAll.js"
392
+ );
393
+ const numOfRewardUnits: bigint[] = [];
394
+ const result = (
395
+ await Promise.all(
396
+ uniqueERC1155Contracts.map(
397
+ ({ contract, tokenId, quantityPerReward, totalRewards }) => {
398
+ return Promise.all([
399
+ isApprovedForAll({
400
+ contract,
401
+ operator: packContract.address,
402
+ owner: tokenOwner,
403
+ }).catch(() => false),
404
+ contract.address,
405
+ tokenId,
406
+ quantityPerReward,
407
+ totalRewards,
408
+ ]);
409
+ },
410
+ ),
411
+ )
412
+ ).map((item) => {
413
+ const [_allApproved, address, tokenId, quantityPerReward, totalRewards] =
414
+ item;
415
+ if (!_allApproved) {
416
+ throw new Error(
417
+ `ERC1155 contract address ${address} is not approved to be used by this Pack contract.`,
418
+ );
419
+ }
420
+ numOfRewardUnits.push(BigInt(totalRewards));
421
+ return {
422
+ assetContract: address,
423
+ tokenType: PACK_TOKEN_TYPE.ERC1155,
424
+ tokenId,
425
+ totalAmount: BigInt(quantityPerReward) * BigInt(totalRewards),
426
+ };
427
+ });
428
+
429
+ return {
430
+ content: result,
431
+ numOfRewardUnits,
432
+ };
433
+ }