Compare commits

..
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
0f0125acf2 Version Packages (#477)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-01-18 21:03:46 -08:00
Joaquim VergesandGitHub 894cbefc63 [SDK] Add intermediate event for contract deploy transactions before confirmation (#502) 2023-01-18 20:54:21 -08:00
retocroomanandGitHub 73dc026ff9 [SDK] Fix getting domain separator error (#500) 2023-01-18 15:18:42 -08:00
Joaquim VergesandGitHub af32007b9f [SDK] remove debug logs (#501) 2023-01-18 22:57:07 +00:00
Joaquim VergesandGitHub 5fba324ac1 [SDK] Fix claim conditions detection on legacy contracts (#498) 2023-01-15 20:34:39 -08:00
Joaquim VergesandGitHub bff433e121 [SDK] Fix deploy transaction listener for all deploy types sdk.deployer.addDeployListener() (#494) 2023-01-13 19:32:50 -08:00
Joaquim VergesandGitHub 68c8e3c4d7 [SDK] resolve contracts via multichain registry (#491) 2023-01-11 17:41:08 -08:00
Jonas DanielsandGitHub 4e8ff58208 [CLI] attempt to fix usage of rm on windows (#483) 2023-01-10 15:57:33 +01:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
d0d5a3c23d Bump json5 from 1.0.1 to 1.0.2 (#476)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-09 12:56:52 +01:00
9eaa21d09a [SDK] Multichain registry (#311)
Co-authored-by: Yash <[email protected]>
2023-01-05 19:43:28 -08:00
557429b5cf [SDK] Support for PackVRF (#463)
Co-authored-by: Jonas Daniels <[email protected]>
2023-01-05 15:38:59 -08:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
96d2dfd25d Version Packages (#467)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-01-03 14:54:29 +13:00
YashandGitHub 5862c558fb [SDK] Update forwarder address (#469) 2022-12-20 12:42:02 -08:00
e913e0daa9 [SDK] Add SDK options to factory (#465)
Co-authored-by: Joaquim Verges <[email protected]>
2022-12-17 13:05:52 +13:00
Joaquim VergesandGitHub f7a74a3b7c [SDK] Expose sdk.wallet.signTypedData() (#468) 2022-12-16 23:50:36 +00:00
Joaquim VergesandGitHub 73883f56d0 [SDK] workaround for signing typed data with magic.link signers (#466) 2022-12-17 10:44:03 +13:00
Jonas DanielsandGitHub e47085af92 [config] add timeouts for all relevant github actions (#464) 2022-12-16 10:06:58 +01:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
f525e2cc23 Version Packages (#455)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-12-16 15:28:02 +13:00
Nacho IacovinoandGitHub af85389dc0 [CLI] Fix deprecated links (#461) 2022-12-13 16:20:34 -08:00
ccb4ce8d00 [Wallets] - magic wallet connector (#457)
Co-authored-by: Joaquim Verges <[email protected]>
2022-12-13 13:58:49 +13:00
Joaquim VergesandGitHub 4cdd0bd634 [SDK] Fixes for latest wallet package integration (#458) 2022-12-08 22:13:16 +00:00
ea95c5f609 [SDK] add two new utilities toEther and toWei (#421)
Co-authored-by: Nacho Iacovino <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2022-12-08 12:46:41 -08:00
Joaquim VergesandGitHub 699a2b16fb [SOL] Fix claiming drops with custom currencies (#456) 2022-12-08 09:32:47 +00:00
Joaquim VergesandGitHub a8267f912d [SOL] Drop fixes for batch upload (#453) 2022-12-08 21:59:47 +13:00
Jonas DanielsandGitHub c673e39f23 upgrade dependencies across the codebase (#454) 2022-12-08 08:19:16 +00:00
08d04fe4dc [React] add props for button title to change the text (#422)
Co-authored-by: Jonas Daniels <[email protected]>
2022-12-08 08:09:23 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
cbf5508bd5 Version Packages (#449)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-12-07 14:21:51 +13:00
Joaquim VergesandGitHub 3731459d33 [SDK] Less strict prebuilt checks to support OSRF variants (#451) 2022-12-07 13:08:12 +13:00
Adam MajmudarandGitHub 64f24f1bb1 CLI auto-updates on every run (#441) 2022-12-06 02:40:31 +00:00
Joaquim VergesandGitHub cac6c30bca [SDK] Fix setting allowance or approvals gaslessly (#450) 2022-12-06 11:49:04 +13:00
Adam MajmudarandGitHub e7740a59db Detect if forge isn't installed and display error (#447) 2022-12-05 16:54:13 -05:00
Jonas DanielsandGitHub 7a37e564fd [SDK, React] - useContract fail fast (#448) 2022-12-05 21:41:58 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
e173636f4b Version Packages (#446)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-12-04 11:34:00 +13:00
Joaquim VergesandGitHub 8c6cdaa288 [SDK] Fix creating listings with a magic.link wallet (#443) 2022-12-03 21:58:44 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
ad9b3febff Version Packages (#445)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-12-04 07:49:38 +13:00
Adam MajmudarandGitHub 94f49b1294 Move framework check back to template (#444) 2022-12-03 18:40:46 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
517e2a75e3 Version Packages (#442)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-12-02 16:26:33 -08:00
Jonas DanielsandGitHub 72692689e9 initialize pay package (#433) 2022-12-02 22:52:04 +00:00
Jonas DanielsandGitHub efc56fa580 [SDK] - improved batch provider (#440) 2022-12-02 22:39:11 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
564b17e760 Version Packages (#419)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-12-03 11:25:35 +13:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
b4507db963 Bump decode-uri-component from 0.2.0 to 0.2.2 (#439)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-12-02 14:10:31 -08:00
Joaquim VergesandGitHub f451da6395 [SDK] Fix SigMint detection for OSRF NFT Collection contracts (#438) 2022-12-03 11:00:21 +13:00
Jonas DanielsandGitHub ee47840767 fix #429 (#436) 2022-12-02 10:47:46 -08:00
Adam MajmudarandGitHub bef97f72f4 [CLI] Make solc default backup compilation (#435) 2022-12-02 17:11:20 +00:00
Adam MajmudarandGitHub 3e87dd3ccb [CLI] display file names when there are duplicate contract names (#432) 2022-12-02 03:21:40 +00:00
Joaquim VergesandGitHub def42511ff [SOL] Remove workaround for getLargestAccount (#434) 2022-12-02 02:42:26 +00:00
Adam MajmudarandGitHub c42545a647 [CLI] fix CLI on paths with spaces for windows (#431) 2022-12-01 19:03:54 -05:00
Adam MajmudarandGitHub 6e20d1f21a [CLI] allow adding contracts to existing projects (#428) 2022-12-01 20:31:06 +00:00
Joaquim VergesandGitHub e684d7e1ca [CLI] Fix metadata upload with special characters (#430) 2022-12-01 20:14:27 +00:00
Adam MajmudarandGitHub f545a67e9f [Auth] include credentials when requesting user (#425) 2022-12-01 18:17:31 +00:00
Jake LooandGitHub 034a257442 [SDK] Support more types of Minimal Proxy (#429) 2022-12-01 20:30:09 +13:00
1bfb91dbf3 [SDK] Improve error parsing for other wallets (#424)
Co-authored-by: Jonas Daniels <[email protected]>
2022-11-30 18:02:21 -08:00
Jonas DanielsandGitHub 5d95cbcdb2 fix turbo (#427) 2022-12-01 00:52:06 +00:00
Jonas DanielsandGitHub 639e535ed5 init unity-js-bridge package (#420) 2022-11-30 22:36:16 +00:00
af3acc6b10 [SDK] Add support for AWS KMS (#416)
Co-authored-by: Jonas Daniels <[email protected]>
2022-11-28 20:34:24 -08:00
Joaquim VergesandGitHub eca47763cd [SDK] increase gas limit for opening packs (#418) 2022-11-29 03:30:15 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
37b5bec897 Version Packages (#417)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-11-28 18:23:23 -08:00
Nacho IacovinoandGitHub 48d91e4431 [CLI] Fix mappings for prebuilts (#415) 2022-11-28 18:13:00 -08:00
187 changed files with 8679 additions and 2744 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ concurrency:
jobs:
build:
name: Build and Test
# timeout-minutes: 15
timeout-minutes: 30
runs-on: ubuntu-latest-32
# To use Remote Caching, uncomment the next lines and follow the steps below.
env:
+1 -1
View File
@@ -12,7 +12,7 @@ concurrency:
jobs:
integration-tests:
timeout-minutes: 60
timeout-minutes: 30
runs-on: ubuntu-latest-32
steps:
- uses: actions/checkout@v3
+1 -2
View File
@@ -13,8 +13,7 @@ concurrency:
jobs:
lint:
name: Lint
# timeout-minutes: 15
# try out buildjet to speed up build and test
timeout-minutes: 15
runs-on: ubuntu-latest
# To use Remote Caching, uncomment the next lines and follow the steps below.
env:
+1
View File
@@ -41,6 +41,7 @@ jobs:
deploy:
runs-on: ubuntu-latest-32
timeout-minutes: 30
needs: deploy-check
if: needs.deploy-check.outputs.triggered == 'true'
steps:
+1
View File
@@ -14,6 +14,7 @@ concurrency:
jobs:
release:
name: Release
timeout-minutes: 30
runs-on: ubuntu-latest-32
steps:
- name: Checkout branch
+1
View File
@@ -5,6 +5,7 @@ on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest-32
timeout-minutes: 30
steps:
- uses: actions/checkout@v3
+1 -1
View File
@@ -36,7 +36,7 @@
"@changesets/cli": "^2.24.3",
"@manypkg/cli": "^0.19.1",
"@manypkg/get-packages": "^1.1.3",
"@trivago/prettier-plugin-sort-imports": "^3.3.0",
"@trivago/prettier-plugin-sort-imports": "^4.0.0",
"eslint": "^8.21.0",
"postinstall-postinstall": "^2.1.0",
"prettier": "^2.7.1",
+18
View File
@@ -1,5 +1,23 @@
# @thirdweb-dev/auth
## 2.0.40
## 2.0.39
## 2.0.38
## 2.0.37
## 2.0.36
## 2.0.35
## 2.0.34
### Patch Changes
- [#425](https://github.com/thirdweb-dev/js/pull/425) [`f545a67`](https://github.com/thirdweb-dev/js/commit/f545a67e9fb597d27bb39ca515d24d306fbb121a) Thanks [@adam-maj](https://github.com/adam-maj)! - Add sameSite none and include credentials
## 2.0.33
## 2.0.32
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "2.0.33",
"version": "2.0.40",
"exports": {
"./next": {
"module": "./next/dist/thirdweb-dev-auth-next.esm.js",
@@ -43,7 +43,7 @@ export default async function handler(
path: "/",
httpOnly: true,
secure: true,
sameSite: "strict",
sameSite: "none",
}),
);
+2 -2
View File
@@ -40,11 +40,11 @@ export function ThirdwebNextAuth(cfg: ThirdwebNextAuthConfig) {
path: "/",
httpOnly: true,
secure: true,
sameSite: "strict",
sameSite: "none",
}),
);
return { address };
return { id: address, address };
} catch (err) {
return null;
}
+1 -1
View File
@@ -47,7 +47,7 @@ export default async function handler(
path: "/",
httpOnly: true,
secure: true,
sameSite: "strict",
sameSite: "none",
}),
);
@@ -47,7 +47,7 @@ export default async function handler(
path: "/",
httpOnly: true,
secure: true,
sameSite: "strict",
sameSite: "none",
}),
);
+81
View File
@@ -1,5 +1,86 @@
# thirdweb
## 0.9.9
### Patch Changes
- [#483](https://github.com/thirdweb-dev/js/pull/483) [`4e8ff58`](https://github.com/thirdweb-dev/js/commit/4e8ff582084c3d201314e6c5dff5b79f15eb6292) Thanks [@jnsdls](https://github.com/jnsdls)! - `thirdweb create` with usage of `forge` should now function correctly in windows CMD shell
- Updated dependencies [[`5fba324`](https://github.com/thirdweb-dev/js/commit/5fba324ac17ab02bc8f13d82a232bc5c6970c8e5), [`894cbef`](https://github.com/thirdweb-dev/js/commit/894cbefc6361f23fc528a6c6819f5c71793d46e4), [`557429b`](https://github.com/thirdweb-dev/js/commit/557429b5cfb3af2983ee01cf7d12d41ee0557593), [`73dc026`](https://github.com/thirdweb-dev/js/commit/73dc026ff9d0ac9099bd5a9a9cab8fdbfc0ae723), [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857), [`68c8e3c`](https://github.com/thirdweb-dev/js/commit/68c8e3c4d79f5d56dc4414241bcca0d88285fcca), [`bff433e`](https://github.com/thirdweb-dev/js/commit/bff433e12150dc029e33a578219c8437a510da99)]:
- @thirdweb-dev/sdk@3.6.10
## 0.9.8
### Patch Changes
- Updated dependencies [[`e913e0d`](https://github.com/thirdweb-dev/js/commit/e913e0daa9ece9a6274f7ffa4e66bdcbf32e6ada), [`5862c55`](https://github.com/thirdweb-dev/js/commit/5862c558fb48604b5aca4defd1ccc06fc3536358), [`73883f5`](https://github.com/thirdweb-dev/js/commit/73883f56d0ed0a35ace8b98b96caa782443be22e), [`f7a74a3`](https://github.com/thirdweb-dev/js/commit/f7a74a3b7c489ada5b1ec435632a326334a33c9b)]:
- @thirdweb-dev/sdk@3.6.9
## 0.9.7
### Patch Changes
- [#454](https://github.com/thirdweb-dev/js/pull/454) [`c673e39`](https://github.com/thirdweb-dev/js/commit/c673e39f23ef082097d73d62910580e8fad400a0) Thanks [@jnsdls](https://github.com/jnsdls)! - upgraded dependencies
- [#461](https://github.com/thirdweb-dev/js/pull/461) [`af85389`](https://github.com/thirdweb-dev/js/commit/af85389dc07fb163b8f9d70093eb1b691e47561a) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix deprecated links
- Updated dependencies [[`c673e39`](https://github.com/thirdweb-dev/js/commit/c673e39f23ef082097d73d62910580e8fad400a0), [`ea95c5f`](https://github.com/thirdweb-dev/js/commit/ea95c5f609e306e333ee0f73f7920503358ca848), [`699a2b1`](https://github.com/thirdweb-dev/js/commit/699a2b16fb991c474ec57db8f178e2601d631f39), [`4cdd0bd`](https://github.com/thirdweb-dev/js/commit/4cdd0bd6348494a256d7c6a2bdf8f7b5c20f6877), [`a8267f9`](https://github.com/thirdweb-dev/js/commit/a8267f912df84c58d3fe3f47b90bd474f73c84ca)]:
- @thirdweb-dev/sdk@3.6.8
## 0.9.6
### Patch Changes
- [#441](https://github.com/thirdweb-dev/js/pull/441) [`64f24f1`](https://github.com/thirdweb-dev/js/commit/64f24f1bb167c3d0cb3beca51fd300eaec21cc27) Thanks [@adam-maj](https://github.com/adam-maj)! - CLI autoupdates on run
- [#447](https://github.com/thirdweb-dev/js/pull/447) [`e7740a5`](https://github.com/thirdweb-dev/js/commit/e7740a59db022a3396194ac66cd195d8ae754d57) Thanks [@adam-maj](https://github.com/adam-maj)! - Detect whether forge is installed
- Updated dependencies [[`3731459`](https://github.com/thirdweb-dev/js/commit/3731459d33f1ded7ebb69124809449b901b3ad3d), [`cac6c30`](https://github.com/thirdweb-dev/js/commit/cac6c30bca5e17df81d746ef81316af47d5e252e), [`7a37e56`](https://github.com/thirdweb-dev/js/commit/7a37e564fd5d5a9df84c8da44ecaf6c42f67a0e2)]:
- @thirdweb-dev/sdk@3.6.7
## 0.9.5
### Patch Changes
- Updated dependencies [[`8c6cdaa`](https://github.com/thirdweb-dev/js/commit/8c6cdaa2887fb2cc40d3ee6991233d195d103805)]:
- @thirdweb-dev/sdk@3.6.6
## 0.9.4
### Patch Changes
- [#444](https://github.com/thirdweb-dev/js/pull/444) [`94f49b1`](https://github.com/thirdweb-dev/js/commit/94f49b1294bc0208171b16ed413cbb44644af017) Thanks [@adam-maj](https://github.com/adam-maj)! - Add changeset
## 0.9.3
### Patch Changes
- Updated dependencies [[`efc56fa`](https://github.com/thirdweb-dev/js/commit/efc56fa5802490ac8ef50037658d046afd89e9a1)]:
- @thirdweb-dev/sdk@3.6.5
## 0.9.2
### Patch Changes
- [#430](https://github.com/thirdweb-dev/js/pull/430) [`e684d7e`](https://github.com/thirdweb-dev/js/commit/e684d7e1ca16f633bce8698529d16bf60c264aa4) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix uploading contracts with special characters in the comments
- [#435](https://github.com/thirdweb-dev/js/pull/435) [`bef97f7`](https://github.com/thirdweb-dev/js/commit/bef97f72f4860596b7b70b05e67fcadf2c9a012e) Thanks [@adam-maj](https://github.com/adam-maj)! - Make solc default backup compilation
- [#432](https://github.com/thirdweb-dev/js/pull/432) [`3e87dd3`](https://github.com/thirdweb-dev/js/commit/3e87dd3ccb04a2b73437357c939a251e83b783b2) Thanks [@adam-maj](https://github.com/adam-maj)! - Display file name on duplicate contract names
- [#431](https://github.com/thirdweb-dev/js/pull/431) [`c42545a`](https://github.com/thirdweb-dev/js/commit/c42545a64725492136025fa1dcdb4d46ba674a30) Thanks [@adam-maj](https://github.com/adam-maj)! - Add changeset
- [#428](https://github.com/thirdweb-dev/js/pull/428) [`6e20d1f`](https://github.com/thirdweb-dev/js/commit/6e20d1f21a622f102e94b956f700d0871c0dc779) Thanks [@adam-maj](https://github.com/adam-maj)! - Update CLI to enable create contract inside contracts project
- Updated dependencies [[`f451da6`](https://github.com/thirdweb-dev/js/commit/f451da6395689a5f89800ee63f34b6175b61f703), [`af3acc6`](https://github.com/thirdweb-dev/js/commit/af3acc6b10751b840e56aef6400da5eea6040df2), [`1bfb91d`](https://github.com/thirdweb-dev/js/commit/1bfb91dbf3a39160c987a425813ac5dbb84703ad), [`ee47840`](https://github.com/thirdweb-dev/js/commit/ee478407673b0416e0c1cfe2be11bd6963395348), [`def4251`](https://github.com/thirdweb-dev/js/commit/def42511ff5a20d83f9094164dafb87e412571b5), [`034a257`](https://github.com/thirdweb-dev/js/commit/034a257442314c67729f7bafcbe3740cff33fa32), [`eca4776`](https://github.com/thirdweb-dev/js/commit/eca47763cd89cc3b7aa57b542971837987540b55), [`639e535`](https://github.com/thirdweb-dev/js/commit/639e535ed55280ad9d081001aab3f5af72bb3e45)]:
- @thirdweb-dev/sdk@3.6.4
## 0.9.1
### Patch Changes
- [#415](https://github.com/thirdweb-dev/js/pull/415) [`48d91e4`](https://github.com/thirdweb-dev/js/commit/48d91e4431a3740d0f98f730ed5abf5b287f92c1) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix mappings for prebuilts redirect on deploy
## 0.9.0
### Minor Changes
+1 -1
View File
@@ -62,7 +62,7 @@ Deploying released contracts give deployers access to automatic SDKs to integrat
npx thirdweb@latest detect
```
As you're developing your contracts, you may want to implement [Extensions](https://portal.thirdweb.com/extensions) to unlock functionality on the SDKs (ie. nft minting with automatic upload to IPFS) and the dashboard (ie. generated UI to manage permissions). This command will show what extensions were detected on your contract, unlocking the corresponding functionality on the SDKs and dashboard.
As you're developing your contracts, you may want to implement [Extensions](https://portal.thirdweb.com/contractkit) to unlock functionality on the SDKs (ie. nft minting with automatic upload to IPFS) and the dashboard (ie. generated UI to manage permissions). This command will show what extensions were detected on your contract, unlocking the corresponding functionality on the SDKs and dashboard.
---
+2 -1
View File
@@ -1,6 +1,7 @@
export const CREATE_MESSAGES = {
typeOfProject: "What type of project do you want to create?",
projectName: "What is your project named?",
contractName: "What will be the name of your new smart contract?",
chain: "Which blockchain do you want to use?",
framework: "What framework do you want to use?",
language: "What language do you want to use?",
@@ -10,5 +11,5 @@ export const CREATE_MESSAGES = {
export const ERROR_MESSAGES = {
noConfiguration:
"Failed to find a supported project configuration file in current directory",
"No contract project configuration file found in current directory",
};
+4
View File
@@ -19,6 +19,10 @@ describe("npx thirdweb detect", () => {
await create.waitForText(CREATE_MESSAGES.framework);
// select hardhat
await create.pressKey("enter");
await create.waitForText(CREATE_MESSAGES.contractName);
// set contract name
await create.writeText("Contract");
await create.pressKey("enter");
await create.waitForText(CREATE_MESSAGES.contract);
// select ERC721
await create.pressKey("arrowDown");
+5 -4
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.9.0",
"version": "0.9.9",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -18,12 +18,12 @@
"@types/prompts": "^2.0.14",
"@types/rimraf": "^3.0.0",
"@types/tar": "^6.1.2",
"@types/update-notifier": "^5.1.0",
"@types/update-notifier": "^6.0.1",
"@types/validate-npm-package-name": "^4.0.0",
"hardhat": "^2.9.3",
"jest": "^28",
"jest": "^29",
"prettier": "^2.7.1",
"ts-jest": "^28.0.8",
"ts-jest": "^29.0.3",
"ts-node": "^10.7.0",
"tsup": "^6.2.3",
"typescript": "^4.7.4"
@@ -32,6 +32,7 @@
"@thirdweb-dev/sdk": "*",
"async-retry": "^1.3.3",
"commander": "^9.1.0",
"detect-package-manager": "^2.0.1",
"enquirer": "^2.3.6",
"ethers": "^5.7.2",
"got": "11.8.5",
+168 -20
View File
@@ -2,37 +2,37 @@
import { detectExtensions } from "../common/feature-detector";
import { processProject } from "../common/processor";
import { cliVersion, pkg } from "../constants/urls";
import { info, logger } from "../core/helpers/logger";
import { info, logger, spinner } from "../core/helpers/logger";
import { twCreate } from "../create/command";
import { deploy } from "../deploy";
import { findPackageInstallation } from "../helpers/detect-local-packages";
import { upload } from "../storage/command";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import chalk from "chalk";
import { exec, spawn } from "child_process";
import { Command } from "commander";
import open from "open";
import prompts from "prompts";
const main = async () => {
// eslint-disable-next-line turbo/no-undeclared-env-vars
const skipIntro = process.env.THIRDWEB_CLI_SKIP_INTRO === "true";
const program = new Command();
//yes this has to look like this, eliminates whitespace
console.info(`
$$\\ $$\\ $$\\ $$\\ $$\\
$$ | $$ | \\__| $$ | $$ |
$$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$$\\
\\_$$ _| $$ __$$\\ $$ |$$ __$$\\ $$ __$$ |$$ | $$ | $$ |$$ __$$\\ $$ __$$\\
$$ | $$ | $$ |$$ |$$ | \\__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
$$ |$$\\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
\\$$$$ |$$ | $$ |$$ |$$ | \\$$$$$$$ |\\$$$$$\\$$$$ |\\$$$$$$$\\ $$$$$$$ |
\\____/ \\__| \\__|\\__|\\__| \\_______| \\_____\\____/ \\_______|\\_______/ `);
console.info(`\n 💎 thirdweb-cli v${cliVersion} 💎\n`);
import("update-notifier").then(({ default: updateNotifier }) => {
updateNotifier({
pkg,
shouldNotifyInNpmScript: true,
// check every time while we're still building the CLI
updateCheckInterval: 0,
}).notify();
});
// yes this has to look like this, eliminates whitespace
if (!skipIntro) {
console.info(`
$$\\ $$\\ $$\\ $$\\ $$\\
$$ | $$ | \\__| $$ | $$ |
$$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$$\\
\\_$$ _| $$ __$$\\ $$ |$$ __$$\\ $$ __$$ |$$ | $$ | $$ |$$ __$$\\ $$ __$$\\
$$ | $$ | $$ |$$ |$$ | \\__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
$$ |$$\\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
\\$$$$ |$$ | $$ |$$ |$$ | \\$$$$$$$ |\\$$$$$\\$$$$ |\\$$$$$$$\\ $$$$$$$ |
\\____/ \\__| \\__|\\__|\\__| \\_______| \\_____\\____/ \\_______|\\_______/ `);
console.info(`\n 💎 thirdweb-cli v${cliVersion} 💎\n`);
}
program
.name("thirdweb-cli")
@@ -68,6 +68,10 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
"-t, --template [name]",
"A template to start your project from. You can use an template repository name from the official thirdweb-example org.",
)
.option(
"-c, --contract-name [name]",
"Name of the new smart contract to create",
)
.action(async (type, path, options) => {
await twCreate(type, path, options);
});
@@ -97,6 +101,14 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
"-n, --name [name]",
"Name of the pre-built or released contract (such as nft-drop)",
)
.option(
"-f, --file [name]",
"Filter for contract files that contain this file name",
)
.option(
"-cn, --contract-name [name]",
"Filter for contracts that contain this contract name",
)
.option(
"-cv, --contract-version [version]",
"Version of the released contract",
@@ -116,6 +128,14 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
"Release your protocol so other devs can deploy them and unlock SDKs, Dashboards and Analytics",
)
.option("-p, --path <project-path>", "path to project", ".")
.option(
"-f, --file [name]",
"Filter for contract files that contain the file name",
)
.option(
"-cn, --contract-name [name]",
"Filter for contracts that contain this contract name",
)
.option("--dry-run", "dry run (skip actually publishing)")
.option("-d, --debug", "show debug logs")
.option("--ci", "Continuous Integration mode")
@@ -178,6 +198,134 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
await detectExtensions(options);
});
if (!skipIntro) {
const versionSpinner = spinner("Checking for updates...");
await import("update-notifier").then(
async ({ default: updateNotifier }) => {
const notifier = updateNotifier({
pkg,
shouldNotifyInNpmScript: true,
// check every time while we're still building the CLI
updateCheckInterval: 0,
});
const versionInfo = await notifier.fetchInfo();
versionSpinner.stop();
if (versionInfo.type !== "latest") {
const res = await prompts({
type: "toggle",
name: "upgrade",
message: `A new version of the CLI is available. Would you like to upgrade?`,
initial: true,
active: "yes",
inactive: "no",
});
if (res.upgrade) {
const updateSpinner = spinner(
`Upgrading CLI to version ${versionInfo.latest}...`,
);
const clonedEnvironment = { ...process.env };
clonedEnvironment.THIRDWEB_CLI_SKIP_INTRO = "true";
const installation = await findPackageInstallation();
// If the package isn't installed anywhere, just defer to npx thirdweb@latest
if (!installation) {
updateSpinner.succeed(
`Now using CLI version ${versionInfo.latest}. Continuing execution...`,
);
await new Promise((done, failed) => {
const shell = spawn(
`npx --yes thirdweb@latest ${process.argv
.slice(2)
.join(" ")}`,
[],
{ stdio: "inherit", shell: true, env: clonedEnvironment },
);
shell.on("close", (code) => {
if (code === 0) {
done("");
} else {
failed();
}
});
});
return process.exit(0);
}
// Otherwise, get the correct command based on package manager and local vs. global
let command = "";
switch (installation.packageManager) {
case "npm":
command = installation.isGlobal
? `npm install -g thirdweb`
: `npm install thirdweb`;
break;
case "yarn":
command = installation.isGlobal
? `yarn global add thirdweb`
: `yarn add thirdweb`;
break;
case "pnpm":
command = installation.isGlobal
? `pnpm add -g thirdweb@latest`
: `pnpm add thirdweb@latest`;
break;
default:
console.error(
`Could not detect package manager in use, aborting automatic upgrade.\nIf you want to upgrade the CLI, please do it manually with your package manager.`,
);
process.exit(1);
}
await new Promise((done, failed) => {
exec(command, (err, stdout, stderr) => {
if (err) {
failed(err);
return;
}
done({ stdout, stderr });
});
});
updateSpinner.succeed(
`Successfully upgraded CLI to version ${versionInfo.latest}. Continuing execution...`,
);
// If the package is installed globally with yarn or pnpm, then npx won't recognize it
// So we need to make sure to run the command directly
const executionCommand =
!installation.isGlobal || installation.packageManager === "npm"
? `npx thirdweb`
: `thirdweb`;
await new Promise((done, failed) => {
const shell = spawn(
`${executionCommand} ${process.argv.slice(2).join(" ")}`,
[],
{ stdio: "inherit", shell: true, env: clonedEnvironment },
);
shell.on("close", (code) => {
if (code === 0) {
done("");
} else {
failed();
}
});
});
process.exit(0);
}
}
},
);
}
await program.parseAsync();
};
+2 -2
View File
@@ -72,13 +72,13 @@ export async function detectExtensions(options: any) {
const enabledFeatures: Feature[] = features.enabledFeatures.map(
(feature) => ({
name: feature.name,
reference: `https://portal.thirdweb.com/extensions/${feature.name.toLowerCase()}`,
reference: `https://portal.thirdweb.com/interfaces/${feature.name.toLowerCase()}`,
}),
);
const suggestedFeatures: Feature[] = features.suggestedFeatures.map(
(feature) => ({
name: feature.name,
reference: `https://portal.thirdweb.com/extensions/${feature.name.toLowerCase()}`,
reference: `https://portal.thirdweb.com/interfaces/${feature.name.toLowerCase()}`,
}),
);
+43 -6
View File
@@ -76,7 +76,7 @@ export async function processProject(
}
}
let compiledResult;
let compiledResult: { contracts: ContractPayload[] };
const compileLoader = spinner("Compiling project...");
try {
compiledResult = await build(projectPath, projectType);
@@ -106,10 +106,47 @@ export async function processProject(
if (options.ci) {
selectedContracts = compiledResult.contracts;
} else {
const choices = compiledResult.contracts.map((c) => ({
name: c.name,
value: c,
}));
const filtered = compiledResult.contracts
.filter((c) => {
if (typeof options.file === "string" && options.file.length > 0) {
return c.fileName.includes(options.file);
}
return true;
})
.filter((c) => {
if (
typeof options.contractName === "string" &&
options.contractName.length > 0
) {
return c.name.includes(options.contractName);
}
return true;
});
if (filtered.length === 0) {
logger.error(`No contracts found matching the specified filters.`);
process.exit(1);
}
const choices = filtered.map((c) => {
if (
compiledResult.contracts.filter(
(other: ContractPayload) => other.name === c.name,
).length > 1
) {
return {
name: `${c.name} - ${chalk.gray(c.fileName)}`,
value: c,
};
}
return {
name: c.name,
value: c,
};
});
const prompt = createContractsPrompt(
choices,
`Choose which contract(s) to ${command}`,
@@ -164,7 +201,7 @@ export async function processProject(
const metadataURIs = await Promise.all(
selectedContracts.map(async (c) => {
logger.debug(`Uploading ${c.name}...`);
return await storage.upload(JSON.parse(c.metadata), {
return await storage.upload(JSON.parse(JSON.stringify(c.metadata)), {
uploadWithoutDirectory: true,
});
}),
+1
View File
@@ -55,6 +55,7 @@ export class BrownieBuilder extends BaseBuilder {
metadata: {},
bytecode,
sources: [], // TODO
fileName: "", // TODO
name: contractName,
});
break;
+20
View File
@@ -1,9 +1,11 @@
import { findFiles } from "../../common/file-helper";
import { hasForge } from "../../create/helpers/has-forge";
import { execute } from "../helpers/exec";
import { logger } from "../helpers/logger";
import { CompileOptions } from "../interfaces/Builder";
import { ContractPayload } from "../interfaces/ContractPayload";
import { BaseBuilder } from "./builder-base";
import chalk from "chalk";
import { existsSync, readFileSync } from "fs";
import { basename, join } from "path";
@@ -11,6 +13,18 @@ export class FoundryBuilder extends BaseBuilder {
public async compile(options: CompileOptions): Promise<{
contracts: ContractPayload[];
}> {
const isInstalled = await hasForge();
if (!isInstalled) {
console.error(
`\n${chalk.redBright(
`error`,
)} You don't have forge installed on this machine!\n\nYou can install forge by following these instructions:\n${chalk.blueBright(
`https://book.getfoundry.sh/getting-started/installation`,
)}\n`,
);
process.exit(1);
}
await execute("forge clean", options.projectPath);
await execute("forge build --extra-output metadata", options.projectPath);
@@ -88,6 +102,11 @@ export class FoundryBuilder extends BaseBuilder {
})
.filter((path) => path !== undefined) as string[];
const fileNames = Object.keys(
parsedMetadata?.settings?.compilationTarget || {},
);
const fileName = fileNames.length > 0 ? fileNames[0] : "";
if (
this.shouldProcessContract(
contractInfo.abi,
@@ -99,6 +118,7 @@ export class FoundryBuilder extends BaseBuilder {
name: contractName,
metadata,
bytecode,
fileName,
sources,
});
}
+7 -1
View File
@@ -25,7 +25,7 @@ export class HardhatBuilder extends BaseBuilder {
//the hardhat extractor **logs out** the runtime config of hardhat, we take that stdout and parse it
const stringifiedConfig = (
await execute(
`npx hardhat run ${configExtractorScriptPath} --no-compile`,
`npx hardhat run "${configExtractorScriptPath}" --no-compile`,
options.projectPath,
)
).stdout;
@@ -123,11 +123,17 @@ export class HardhatBuilder extends BaseBuilder {
})
.filter((path) => path !== undefined) as string[];
const fileNames = Object.keys(
meta?.settings?.compilationTarget || {},
);
const fileName = fileNames.length > 0 ? fileNames[0] : "";
if (this.shouldProcessContract(abi, deployedBytecode, contractName)) {
contracts.push({
metadata,
bytecode,
name: contractName,
fileName,
sources,
});
}
+6
View File
@@ -140,11 +140,17 @@ export class SolcBuilder extends BaseBuilder {
})
.filter((path) => path !== undefined) as string[];
const fileNames = Object.keys(
parsedMetadata?.settings?.compilationTarget || {},
);
const fileName = fileNames.length > 0 ? fileNames[0] : "";
if (this.shouldProcessContract(abi, deployedBytecode, contractName)) {
contracts.push({
metadata,
bytecode,
name: contractName,
fileName,
sources: _sources,
});
}
+7
View File
@@ -72,11 +72,18 @@ export class TruffleBuilder extends BaseBuilder {
return undefined;
})
.filter((path) => path !== undefined) as string[];
const fileNames = Object.keys(
parsedMetadata?.settings?.compilationTarget || {},
);
const fileName = fileNames.length > 0 ? fileNames[0] : "";
if (this.shouldProcessContract(abi, deployedBytecode, contractName)) {
contracts.push({
metadata,
bytecode,
name: contractName,
fileName,
sources,
});
}
@@ -36,6 +36,7 @@ export default async function detect(
name: "continue",
message:
"Do you want to continue and compile this project with solc instead?",
initial: true,
});
const shouldCompile = await prompt.run();
if (!shouldCompile) {
@@ -17,6 +17,11 @@ export interface ContractPayload {
*/
metadata: any;
/**
* The file name of the original compiled file
*/
fileName: string;
/**
* The source file paths
*/
+217 -128
View File
@@ -2,14 +2,17 @@
/* eslint-disable import/no-extraneous-dependencies */
import { CREATE_MESSAGES } from "../../constants/constants";
import detect from "../core/detection/detect";
import { DownloadError, createApp } from "./helpers/create-app";
import { createContract } from "./helpers/create-contract";
import { createContractProject } from "./helpers/create-contract";
import { getPkgManager } from "./helpers/get-pkg-manager";
import { validateNpmName } from "./helpers/validate-pkg";
import chalk from "chalk";
import fs from "fs";
import path from "path";
import prompts from "prompts";
let contractName: string = "";
let projectPath: string = "";
let projectType: string = "";
let framework: string = "";
@@ -27,6 +30,10 @@ export async function twCreate(
projectPath = pPath;
}
if (typeof options.contractName === "string") {
contractName = options.contractName;
}
if (pType === "app" || options.app) {
projectType = "app";
} else if (pType === "contract" || options.contract) {
@@ -97,123 +104,210 @@ export async function twCreate(
projectType = "app";
}
if (!projectPath) {
const defaultName =
projectType === "contract" ? "thirdweb-contracts" : "thirdweb-app";
const res = await prompts({
type: "text",
name: "path",
message: CREATE_MESSAGES.projectName,
initial: options.template || defaultName,
format: (name: string) => name.toLowerCase(),
validate: (name: string) => {
const validation = validateNpmName(
path.basename(path.resolve(name.toLowerCase())),
);
if (validation.valid) {
return true;
}
return "Invalid project name: " + validation.problems?.[0];
},
});
if (typeof res.path === "string") {
projectPath = res.path.trim();
}
}
if (!projectPath) {
console.log(
"\nPlease specify the project directory:\n" +
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
"<project-directory>",
)}\n` +
"For example:\n" +
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
"my-thirdweb-app",
)}\n\n` +
`Run ${chalk.cyan("npx thirdweb --help")} to see all options.`,
);
process.exit(1);
}
if (!options.template) {
if (projectType === "app" && !chain) {
const res = await prompts({
type: "select",
name: "chain",
message: CREATE_MESSAGES.chain,
choices: [
{ title: "EVM", value: "evm" },
{ title: "Solana", value: "solana" },
],
});
if (res.chain === "solana") {
chain = "solana";
} else {
chain = "evm";
}
}
if (projectType === "app" && !framework) {
const res = await prompts({
type: "select",
name: "framework",
message: CREATE_MESSAGES.framework,
choices:
// Solana doesn't support Vite just yet:
chain === "solana"
? [
{ title: "Next.js", value: "next" },
{ title: "Create React App", value: "cra" },
// { title: "Vite", value: "vite" },
]
: [
{ title: "Next.js", value: "next" },
{ title: "Create React App", value: "cra" },
{ title: "Vite", value: "vite" },
],
});
if (typeof res.framework === "string") {
framework = res.framework.trim();
}
}
if (projectType === "app" && !language) {
const res = await prompts({
type: "select",
name: "language",
message: CREATE_MESSAGES.language,
choices: [
{ title: "JavaScript", value: "javascript" },
{ title: "TypeScript", value: "typescript" },
],
});
if (typeof res.language === "string") {
language = res.language.trim();
}
}
// Whether to only create a new contract without the project
let onlyContract = false;
if (projectType === "contract") {
const resolvedProjectPath = path.resolve(projectPath);
const contractProjectType = await detect(resolvedProjectPath, {});
if (
projectType === "contract" &&
framework !== "forge" &&
framework !== "hardhat"
contractProjectType === "foundry" &&
fs.existsSync(path.join(resolvedProjectPath, "src"))
) {
onlyContract = true;
projectPath = path.join(projectPath, "src");
} else if (contractProjectType === "hardhat") {
if (fs.existsSync(path.join(resolvedProjectPath, "contracts"))) {
onlyContract = true;
projectPath = path.join(projectPath, "contracts");
} else {
// If there's no expected contracts folder, check for a directory that has .sol files
const directories = fs
.readdirSync(resolvedProjectPath)
.filter((file) =>
fs.lstatSync(path.join(resolvedProjectPath, file)).isDirectory(),
);
for (const directory of directories) {
const files = fs.readdirSync(path.join(projectPath, directory));
if (files.some((file) => file.endsWith(".sol"))) {
onlyContract = true;
projectPath = path.join(projectPath, directory);
break;
}
}
}
}
}
if (!onlyContract) {
if (!projectPath) {
const defaultName =
projectType === "contract" ? "thirdweb-contracts" : "thirdweb-app";
const res = await prompts({
type: "select",
name: "framework",
message: CREATE_MESSAGES.framework,
choices: [
{ title: "Hardhat", value: "hardhat" },
{ title: "Forge", value: "forge" },
],
type: "text",
name: "path",
message: CREATE_MESSAGES.projectName,
initial: options.template || defaultName,
format: (name: string) => name.toLowerCase(),
validate: (name: string) => {
const validation = validateNpmName(
path.basename(path.resolve(name.toLowerCase())),
);
if (validation.valid) {
return true;
}
return "Invalid project name: " + validation.problems?.[0];
},
});
if (typeof res.framework === "string") {
framework = res.framework.trim();
if (typeof res.path === "string") {
projectPath = path.join(projectPath, res.path.trim());
}
}
if (!projectPath) {
console.log(
"\nPlease specify the project directory:\n" +
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
"<project-directory>",
)}\n` +
"For example:\n" +
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
"my-thirdweb-app",
)}\n\n` +
`Run ${chalk.cyan("npx thirdweb --help")} to see all options.`,
);
process.exit(1);
}
if (!options.template) {
if (projectType === "app" && !chain) {
const res = await prompts({
type: "select",
name: "chain",
message: CREATE_MESSAGES.chain,
choices: [
{ title: "EVM", value: "evm" },
{ title: "Solana", value: "solana" },
],
});
if (res.chain === "solana") {
chain = "solana";
} else {
chain = "evm";
}
}
if (projectType === "app" && !framework) {
const res = await prompts({
type: "select",
name: "framework",
message: CREATE_MESSAGES.framework,
choices:
// Solana doesn't support Vite just yet:
chain === "solana"
? [
{ title: "Next.js", value: "next" },
{ title: "Create React App", value: "cra" },
// { title: "Vite", value: "vite" },
]
: [
{ title: "Next.js", value: "next" },
{ title: "Create React App", value: "cra" },
{ title: "Vite", value: "vite" },
],
});
if (typeof res.framework === "string") {
framework = res.framework.trim();
}
}
if (projectType === "app" && !language) {
const res = await prompts({
type: "select",
name: "language",
message: CREATE_MESSAGES.language,
choices: [
{ title: "JavaScript", value: "javascript" },
{ title: "TypeScript", value: "typescript" },
],
});
if (typeof res.language === "string") {
language = res.language.trim();
}
}
if (
projectType === "contract" &&
framework !== "forge" &&
framework !== "hardhat"
) {
const res = await prompts({
type: "select",
name: "framework",
message: CREATE_MESSAGES.framework,
choices: [
{ title: "Hardhat", value: "hardhat" },
{ title: "Forge", value: "forge" },
],
});
if (typeof res.framework === "string") {
framework = res.framework.trim();
}
}
if (!framework) {
console.log("Please specify a framework");
process.exit(1);
}
if (!language) {
// Default = JavaScript
language = "javascript";
}
}
}
if (projectType === "contract") {
// Select contract name
if (!contractName) {
const defaultName = "MyContract";
const res = await prompts({
type: "text",
name: "path",
message: CREATE_MESSAGES.contractName,
initial: defaultName,
validate: (name: string) => {
const isValid = /(^[a-z0-9A-Z]+$)|(^[a-z0-9A-Z]+\.sol$)/.test(name);
if (isValid) {
return true;
}
return `Invalid contract name 'contractName' (only alphanumeric characters allowed)`;
},
});
if (typeof res.path === "string") {
contractName = res.path.trim();
}
if (!contractName) {
console.log(
"\nPlease specify the contract name:\n" +
` ${chalk.cyan(
"npx thirdweb create --contract --name",
)} ${chalk.green("<contract-name>")}\n` +
"For example:\n" +
` ${chalk.cyan(
"npx thirdweb create --contract --name",
)} ${chalk.green("MyContract")}\n\n` +
`Run ${chalk.cyan("npx thirdweb --help")} to see all options.`,
);
process.exit(1);
}
}
@@ -225,7 +319,9 @@ export async function twCreate(
name: "standard",
message: CREATE_MESSAGES.contract,
choices: [
{ title: "Empty Contract", value: "none" },
...(!onlyContract
? [{ title: "Empty Contract", value: "none" }]
: []),
{ title: "ERC721", value: "erc721" },
{ title: "ERC20", value: "erc20" },
{ title: "ERC1155", value: "erc1155" },
@@ -279,20 +375,11 @@ export async function twCreate(
}
}
}
if (!framework) {
console.log("Please specify a framework");
process.exit(1);
}
if (!language) {
// Default = JavaScript
language = "javascript";
}
}
const resolvedProjectPath = path.resolve(projectPath);
const projectName = path.basename(resolvedProjectPath);
// Resolve project path
projectPath = path.resolve(projectPath);
const projectName = path.basename(projectPath);
const { valid, problems } = validateNpmName(projectName);
if (!valid) {
@@ -324,7 +411,7 @@ export async function twCreate(
try {
if (projectType === "app") {
await createApp({
appPath: resolvedProjectPath,
appPath: projectPath,
packageManager,
framework,
language,
@@ -332,11 +419,13 @@ export async function twCreate(
chain,
});
} else {
await createContract({
contractPath: resolvedProjectPath,
await createContractProject({
contractPath: projectPath,
packageManager,
framework,
contractName,
baseContract,
onlyContract,
});
}
} catch (reason) {
@@ -2,6 +2,7 @@ import { hasBaseContract, readBaseContract } from "./base-contracts";
import { DownloadError } from "./create-app";
import { PackageManager } from "./get-pkg-manager";
import { tryGitInit } from "./git";
import { hasForge } from "./has-forge";
import { install } from "./install";
import { isFolderEmpty } from "./is-folder-empty";
import { getOnline } from "./is-online";
@@ -11,22 +12,28 @@ import { submodules } from "./submodules";
import { downloadAndExtractRepo } from "./templates";
import retry from "async-retry";
import chalk from "chalk";
import fs from "fs";
import { writeFile } from "fs/promises";
import path from "path";
interface ICreateContract {
interface ICreateContractProject {
contractPath: string;
packageManager: PackageManager;
contractName: string;
framework?: string;
baseContract?: string;
onlyContract: boolean;
}
export async function createContract({
export async function createContractProject({
contractPath,
packageManager,
framework,
contractName,
baseContract,
}: ICreateContract) {
onlyContract,
}: ICreateContractProject) {
// Check that the selected base contract is valid
if (baseContract) {
const found = hasBaseContract(baseContract);
@@ -40,8 +47,8 @@ export async function createContract({
}
}
// Check that we have write permission for the specified directory
const root = path.resolve(contractPath);
if (!(await isWriteable(path.dirname(root)))) {
console.error(
"The application path is not writable, please check folder permissions and try again.",
@@ -52,117 +59,179 @@ export async function createContract({
process.exit(1);
}
const projectName = path.basename(root);
await makeDir(root);
if (!isFolderEmpty(root, projectName)) {
// Check that the contract name is valid
if (!/(^[a-z0-9A-Z]+$)|(^[a-z0-9A-Z]+\.sol$)/.test(contractName)) {
console.error(
`Contract name ${chalk.red(
`"${contractName}"`,
)} is not valid (only alphanumeric characters are allowed).`,
);
process.exit(1);
}
// Clean the contract name
contractName = contractName.replace(/\.sol$/, "") + ".sol";
const useYarn = packageManager === "yarn";
const isOnline = !useYarn || (await getOnline());
const originalDirectory = process.cwd();
console.log(
`Creating a new thirdweb contracts project in ${chalk.green(root)}.`,
);
console.log();
process.chdir(root);
function isErrorLike(err: unknown): err is { message: string } {
return (
typeof err === "object" &&
err !== null &&
typeof (err as { message?: unknown }).message === "string"
);
}
try {
console.log(`Downloading files. This might take a moment.`);
let starter = "";
if (framework === "hardhat") {
starter = "hardhat-javascript-starter";
} else if (framework === "forge") {
starter = "forge-starter";
} else {
console.error("Please provide a valid contracts framework.");
if (onlyContract) {
// If we are already in a contracts project, just create a new contract
if (fs.existsSync(path.join(root, contractName))) {
console.error(
`A contract with the name ${chalk.red(
`"${contractName}"`,
)} already exists in specified directory.`,
);
process.exit(1);
}
await retry(
() => downloadAndExtractRepo(root, { name: starter, filePath: "" }),
{
retries: 3,
},
);
// Modify the /contracts/MyContract.sol contents to match the base contract
if (baseContract && baseContract.length > 0) {
const baseContractText = readBaseContract(baseContract);
// Set the contents of the Contract.sol file to the base contract
let contractFile = "";
if (framework === "hardhat") {
contractFile = path.join(root, "contracts", "Contract.sol");
}
if (framework === "forge") {
contractFile = path.join(root, "src", "Contract.sol");
}
contractFile = path.join(root, contractName);
// Write the base contract to the MyContract.sol file
await writeFile(contractFile, baseContractText);
console.log(
`${chalk.green("Success!")} Created ${contractName} at ${contractPath}`,
);
}
} catch (reason) {
throw new DownloadError(
isErrorLike(reason) ? reason.message : String(reason),
);
}
console.log("Installing packages. This might take a couple of minutes.");
console.log();
await install(root, null, { packageManager, isOnline });
console.log();
if (tryGitInit(root)) {
console.log("Initialized a git repository.");
console.log();
}
if (framework === "forge") {
await submodules();
}
let cdpath: string;
if (path.join(originalDirectory, projectName) === contractPath) {
cdpath = projectName;
} else {
cdpath = contractPath;
}
// Otherwise, create a new contracts project
const projectName = path.basename(root);
console.log(
`${chalk.green("Success!")} Created ${projectName} at ${contractPath}`,
);
console.log();
console.log("Inside that directory, you can run several commands:");
console.log();
console.log(chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} build`));
console.log(
" Compiles your contracts and detects thirdweb extensions implemented on them.",
);
console.log();
console.log(chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} deploy`));
console.log(" Deploys your contracts with the thirdweb deploy flow.");
console.log();
console.log(
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} release`),
);
console.log(" Releases your contracts with the thirdweb release flow.");
console.log();
console.log("We suggest that you begin by typing:");
console.log();
console.log(chalk.cyan(" cd"), cdpath);
console.log();
await makeDir(root);
if (!isFolderEmpty(root, projectName)) {
process.exit(1);
}
const isOnline = !useYarn || (await getOnline());
const originalDirectory = process.cwd();
console.log(
`Creating a new thirdweb contracts project in ${chalk.green(root)}.`,
);
console.log();
process.chdir(root);
function isErrorLike(err: unknown): err is { message: string } {
return (
typeof err === "object" &&
err !== null &&
typeof (err as { message?: unknown }).message === "string"
);
}
try {
console.log(`Downloading files. This might take a moment.`);
let starter = "";
if (framework === "hardhat") {
starter = "hardhat-javascript-starter";
} else if (framework === "forge") {
starter = "forge-starter";
} else {
console.error("Please provide a valid contracts framework.");
process.exit(1);
}
await retry(
() => downloadAndExtractRepo(root, { name: starter, filePath: "" }),
{
retries: 3,
},
);
// Add in a new contracts file with specific base contract
if (baseContract && baseContract.length > 0) {
const baseContractText = readBaseContract(baseContract);
// Set the filename of the new file and delete the dummy Contract.sol file
let contractFile = "";
if (framework === "hardhat") {
fs.unlinkSync(path.join(root, "contracts", "Contract.sol"));
contractFile = path.join(root, "contracts", contractName);
}
if (framework === "forge") {
fs.unlinkSync(path.join(root, "src", "Contract.sol"));
contractFile = path.join(root, "src", contractName);
}
// Write the base contract to the new file
await writeFile(contractFile, baseContractText);
}
} catch (reason) {
throw new DownloadError(
isErrorLike(reason) ? reason.message : String(reason),
);
}
console.log("Installing packages. This might take a couple of minutes.");
console.log();
await install(root, null, { packageManager, isOnline });
console.log();
if (tryGitInit(root)) {
console.log("Initialized a git repository.");
console.log();
}
if (framework === "forge") {
await submodules();
}
let cdpath: string;
if (path.join(originalDirectory, projectName) === contractPath) {
cdpath = projectName;
} else {
cdpath = contractPath;
}
console.log(
`${chalk.green("Success!")} Created ${projectName} at ${contractPath}`,
);
console.log();
console.log("Inside that directory, you can run several commands:");
console.log();
console.log(
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} build`),
);
console.log(
" Compiles your contracts and detects thirdweb extensions implemented on them.",
);
console.log();
console.log(
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} deploy`),
);
console.log(" Deploys your contracts with the thirdweb deploy flow.");
console.log();
console.log(
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} release`),
);
console.log(" Releases your contracts with the thirdweb release flow.");
console.log();
console.log("We suggest that you begin by typing:");
console.log();
console.log(chalk.cyan(" cd"), cdpath);
console.log();
if (framework === "forge") {
const isInstalled = await hasForge();
if (!isInstalled) {
console.log(
`\n${chalk.yellowBright(
`warning`,
)} You don't have forge installed on this machine, and will need it to run this project! \n\nYou can install forge by following these instructions:\n${chalk.blueBright(
`https://book.getfoundry.sh/getting-started/installation`,
)}\n`,
);
}
}
}
}
@@ -0,0 +1,14 @@
import { exec } from "child_process";
export async function hasForge() {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
return await new Promise((resolve, reject) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
exec("forge --version", (error, stdout, stderr) => {
if (error) {
resolve(false);
}
resolve(true);
});
});
}
@@ -1,5 +1,6 @@
/* eslint-disable import/no-extraneous-dependencies */
import { runCommand } from "./run-command";
import { rm, writeFile } from "node:fs/promises";
/**
* Spawn a package manager installation with either Yarn or NPM.
@@ -8,12 +9,12 @@ import { runCommand } from "./run-command";
*/
export async function submodules(): Promise<void> {
// Remove script folder because it clashes with contract templates (and not needed with deploy)
await runCommand("rm", ["-rf", "script"]);
await rm("script", { recursive: true, force: true });
// Reset and recursively add forge submodules
await runCommand("rm", ["-rf", ".gitmodules"]);
await runCommand("rm", ["-rf", "lib"]);
await runCommand("touch", [".gitmodules"]);
await rm(".gitmodules", { recursive: true, force: true });
await rm("lib", { recursive: true, force: true });
await writeFile(".gitmodules", "");
await runCommand("git", [
"submodule",
"add",
@@ -0,0 +1,103 @@
import { exec } from "child_process";
type PackageManager = "npm" | "yarn" | "pnpm";
interface Installation {
packageManager: PackageManager;
isGlobal: boolean;
}
export async function findPackageInstallation(): Promise<
Installation | undefined
> {
const isLocal = await isInstalledLocally();
if (isLocal) {
const packageManager = await import("detect-package-manager").then(
({ detect }) => {
return detect();
},
);
return { packageManager, isGlobal: false };
}
const isGlobalNpm = await isInstalledGloballyWithNpm();
if (isGlobalNpm) {
return { packageManager: "npm", isGlobal: true };
}
const isGlobalYarn = await isInstalledGloballyWithYarn();
if (isGlobalYarn) {
return { packageManager: "yarn", isGlobal: true };
}
const isGlobalPnpm = await isInstalledGloballyWithPnpm();
if (isGlobalPnpm) {
return { packageManager: "pnpm", isGlobal: true };
}
return undefined;
}
// For LOCAL packages, npm ls picks up things installed by yarn and pnpm too
async function isInstalledLocally(): Promise<boolean> {
const packages = await detectPackages("npm ls --depth=0");
return containsThirdweb(packages || []);
}
// But for GLOBAL packages, we need to use a separate command for each one
async function isInstalledGloballyWithNpm(): Promise<boolean> {
const packages = await detectPackages("npm ls -g --depth=0");
return containsThirdweb(packages || []);
}
async function isInstalledGloballyWithYarn(): Promise<boolean> {
const packages = await detectPackages("yarn --cwd `yarn global dir` list");
return containsThirdweb(packages || []);
}
async function isInstalledGloballyWithPnpm(): Promise<boolean> {
const packages: string[] = await new Promise((resolve) => {
exec(`pnpm list -g --depth=0`, (err, stdout) => {
var pkgs: string[] = [];
pkgs = stdout.split("dependencies:")[1]?.trim().split("\n") || [];
pkgs = pkgs.map((pkg) => pkg.replace(" ", "@"));
resolve(pkgs);
});
});
return containsThirdweb(packages || []);
}
function containsThirdweb(packages: string[]) {
return packages.some((pkg) => pkg.match(/^thirdweb/));
}
async function detectPackages(cmd: string): Promise<string[]> {
return new Promise((resolve) => {
exec(cmd, (err, stdout) => {
var packages: string[] = [];
packages = stdout.split("\n");
// We're one short on '-' to support both yarn and npm
packages = packages.filter(function (item) {
if (item.match(/^├─.+/g) !== null) {
return true;
}
if (item.match(/^└─.+/g) !== null) {
return true;
}
return undefined;
});
packages = packages
.map(function (item) {
if (item.match(/^├─.+/g) !== null) {
return item.replace(/(^├──\s|^├─\s)/g, "");
}
if (item.match(/^└─.+/g) !== null) {
return item.replace(/(^└──\s|^├─\s)/g, "");
}
})
.filter((item) => !!item) as string[];
resolve(packages);
});
});
}
@@ -13,18 +13,18 @@ export default function generateDashboardUrl(
// Pre-built contract
else {
const mapping = {
"signature-drop": "drop/signature-drop",
"nft-drop": "drop/nft-drop",
"edition-drop": "drop/edition-drop",
"nft-collection": "token/nft-collection",
edition: "token/edition",
"token-drop": "drop/token-drop",
token: "token/token",
marketplace: "marketplace/marketplace",
split: "governance/split",
vote: "governance/vote",
pack: "token/pack",
multiwrap: "token/multiwrap",
"signature-drop": "SignatureDrop",
"nft-drop": "DropERC721",
"edition-drop": "DropERC1155",
"nft-collection": "TokenERC721",
edition: "TokenERC1155",
"token-drop": "DropERC20",
token: "TokenERC20",
marketplace: "Marketplace",
split: "Split",
vote: "VoteERC20",
pack: "Pack",
multiwrap: "Multiwrap",
};
const foundMapping = mapping[name as keyof typeof mapping];
@@ -33,6 +33,6 @@ export default function generateDashboardUrl(
return undefined;
}
return `https://thirdweb.com/contracts/new/pre-built/${foundMapping}`;
return `https://thirdweb.com/thirdweb.eth/${foundMapping}`;
}
}
+16
View File
@@ -1,5 +1,21 @@
# @thirdweb-dev/contracts-js
## 1.2.3
### Patch Changes
- [#463](https://github.com/thirdweb-dev/js/pull/463) [`557429b`](https://github.com/thirdweb-dev/js/commit/557429b5cfb3af2983ee01cf7d12d41ee0557593) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - PackVRF contract
- [#311](https://github.com/thirdweb-dev/js/pull/311) [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Update to v3.3.0 of contracts package
- [#311](https://github.com/thirdweb-dev/js/pull/311) [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Update to 3.1.10 of contracts package
## 1.2.2
### Patch Changes
- [#438](https://github.com/thirdweb-dev/js/pull/438) [`f451da6`](https://github.com/thirdweb-dev/js/commit/f451da6395689a5f89800ee63f34b6175b61f703) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix SigMint detection for OSRF NFT Collection contracts
## 1.2.1
### Patch Changes
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryLogic__factory.cjs.js",
"module": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryLogic__factory.esm.js"
}
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryRouter__factory.cjs.js",
"module": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryRouter__factory.esm.js"
}
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryStorage__factory.cjs.js",
"module": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryStorage__factory.esm.js"
}
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-contracts-js-factories-TWRegistryLegacy__factory.cjs.js",
"module": "dist/thirdweb-dev-contracts-js-factories-TWRegistryLegacy__factory.esm.js"
}
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@thirdweb-dev/contracts-js",
"version": "1.2.1",
"version": "1.2.3",
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
"module": "dist/thirdweb-dev-contracts-js.esm.js",
"license": "Apache-2.0",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/contracts-js",
"dependencies": {
"@thirdweb-dev/contracts": "^3.2.2"
"@thirdweb-dev/contracts": "3.3.0"
},
"devDependencies": {
"@babel/preset-env": "^7.18.10",
+6
View File
@@ -0,0 +1,6 @@
{
"presets": [
"@babel/preset-typescript",
["@babel/preset-env", { "targets": "defaults, not ie 11" }]
]
}
+4
View File
@@ -0,0 +1,4 @@
# folders
dist/
# files
+4
View File
@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ["thirdweb"],
};
+7
View File
@@ -0,0 +1,7 @@
# @thirdweb-dev/pay
## 0.1.0
### Minor Changes
- [#433](https://github.com/thirdweb-dev/js/pull/433) [`7269268`](https://github.com/thirdweb-dev/js/commit/72692689e9adb41e92038765fd01a36c2b7457e1) Thanks [@jnsdls](https://github.com/jnsdls)! - Initialize Pay Package
+16
View File
@@ -0,0 +1,16 @@
<p align="center">
<br />
<a href="https://thirdweb.com"><img src="https://github.com/thirdweb-dev/js/blob/main/packages/sdk/logo.svg?raw=true" width="200" alt=""/></a>
<br />
</p>
<h1 align="center">thirdweb wallets</h1>
<p align="center">
<!-- <a href="https://www.npmjs.com/package/@thirdweb-dev/sdk"><img src="https://img.shields.io/npm/v/@thirdweb-dev/sdk?color=red&label=npm&logo=npm" alt="npm version"/></a> -->
<!-- <a href="https://github.com/thirdweb-dev/js/actions/workflows/CI.yml"><img alt="Build Status" src="https://github.com/thirdweb-dev/js/actions/workflows/CI.yml/badge.svg"/></a> -->
<!-- <a href="https://discord.gg/thirdweb"><img alt="Join our Discord!" src="https://img.shields.io/discord/834227967404146718.svg?color=7289da&label=discord&logo=discord&style=flat"/></a> -->
</p>
<!-- <p align="center"><strong>Best in class Web3 SDK for Browser, Node and Mobile apps</strong></p> -->
<br />
### todo
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-pay-integrations-coinbase.cjs.js",
"module": "dist/thirdweb-dev-pay-integrations-coinbase.esm.js"
}
+53
View File
@@ -0,0 +1,53 @@
{
"name": "@thirdweb-dev/pay",
"version": "0.1.0",
"main": "dist/thirdweb-dev-pay.cjs.js",
"module": "dist/thirdweb-dev-pay.esm.js",
"exports": {
".": {
"module": "./dist/thirdweb-dev-pay.esm.js",
"default": "./dist/thirdweb-dev-pay.cjs.js"
},
"./integrations/coinbase": {
"module": "./integrations/coinbase/dist/thirdweb-dev-pay-integrations-coinbase.esm.js",
"default": "./integrations/coinbase/dist/thirdweb-dev-pay-integrations-coinbase.cjs.js"
},
"./package.json": "./package.json"
},
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/pay",
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/thirdweb-dev/js/issues"
},
"author": "thirdweb eng <[email protected]>",
"files": [
"dist/",
"integrations/"
],
"preconstruct": {
"entrypoints": [
"index.ts",
"integrations/**"
],
"___experimentalFlags_WILL_CHANGE_IN_PATCH": {
"exports": true
},
"exports": true
},
"sideEffects": false,
"dependencies": {
"@coinbase/cbpay-js": "^1.6.0"
},
"devDependencies": {
"@preconstruct/cli": "^2.2.1",
"typescript": "^4.7.4"
},
"scripts": {
"format": "prettier --write 'src/**/*'",
"lint": "eslint src/",
"fix": "eslint src/ --fix",
"clean": "rm -rf dist/",
"build": "tsc && preconstruct build",
"push": "yalc push"
}
}
+1
View File
@@ -0,0 +1 @@
export * from "./integrations/coinbase";
@@ -0,0 +1,62 @@
import { initOnRamp, InitOnRampParams } from "@coinbase/cbpay-js";
interface CoinbasePayOptions extends Pick<InitOnRampParams, "appId"> {}
const CHAIN_ID_MAP = {
[-1]: "solana",
1: "ethereum",
69: "optimism",
137: "polygon",
} as const;
export type FundWalletOptions = {
address: string;
chainId: keyof typeof CHAIN_ID_MAP;
assets?: string[];
};
export class CoinbasePayIntegration {
#appId: string;
constructor(options: CoinbasePayOptions) {
this.#appId = options.appId;
}
async fundWallet(opts: FundWalletOptions): Promise<void> {
const { address, chainId, assets } = opts;
return new Promise((res, rej) => {
initOnRamp(
{
appId: this.#appId,
widgetParameters: {
destinationWallets: [
{
address,
assets,
supportedNetworks: [CHAIN_ID_MAP[chainId]],
},
],
},
experienceLoggedIn: "embedded",
experienceLoggedOut: "popup",
closeOnExit: true,
onSuccess: () => {
res();
},
onExit(error) {
if (error) {
return rej(error);
}
return res();
},
},
(err, instance) => {
if (err || !instance) {
return rej(err);
}
instance.open();
},
);
});
}
}
+5
View File
@@ -0,0 +1,5 @@
{
"extends": "@thirdweb-dev/tsconfig/sdk.json",
"include": ["src", "types"],
"exclude": ["dist", "build", "node_modules"]
}
+34
View File
@@ -1,5 +1,39 @@
# @thirdweb-dev/react
## 3.6.10
## 3.6.9
## 3.6.8
### Patch Changes
- [#454](https://github.com/thirdweb-dev/js/pull/454) [`c673e39`](https://github.com/thirdweb-dev/js/commit/c673e39f23ef082097d73d62910580e8fad400a0) Thanks [@jnsdls](https://github.com/jnsdls)! - upgraded dependencies
- [#422](https://github.com/thirdweb-dev/js/pull/422) [`08d04fe`](https://github.com/thirdweb-dev/js/commit/08d04fe4dc74ba0d12625d7d4004c23f7dc330a2) Thanks [@yehia67](https://github.com/yehia67)! - Add `btnTitle` prop to the `ConnectWallet` component. Now you can set customized string or child component to the connect button.
## 3.6.7
### Patch Changes
- [#448](https://github.com/thirdweb-dev/js/pull/448) [`7a37e56`](https://github.com/thirdweb-dev/js/commit/7a37e564fd5d5a9df84c8da44ecaf6c42f67a0e2) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - allow `useContract` to fail faster to enable the import case
## 3.6.6
### Patch Changes
- [#443](https://github.com/thirdweb-dev/js/pull/443) [`8c6cdaa`](https://github.com/thirdweb-dev/js/commit/8c6cdaa2887fb2cc40d3ee6991233d195d103805) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix magic link connector not connecting to the right chain
## 3.6.5
## 3.6.4
### Patch Changes
- [#425](https://github.com/thirdweb-dev/js/pull/425) [`f545a67`](https://github.com/thirdweb-dev/js/commit/f545a67e9fb597d27bb39ca515d24d306fbb121a) Thanks [@adam-maj](https://github.com/adam-maj)! - Add sameSite none and include credentials
- [#420](https://github.com/thirdweb-dev/js/pull/420) [`639e535`](https://github.com/thirdweb-dev/js/commit/639e535ed55280ad9d081001aab3f5af72bb3e45) Thanks [@jnsdls](https://github.com/jnsdls)! - update deps
## 3.6.3
## 3.6.2
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "3.6.3",
"version": "3.6.10",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -97,19 +97,19 @@
"dependencies": {
"@emotion/react": "^11.10.0",
"@emotion/styled": "^11.10.0",
"@gnosis.pm/safe-core-sdk": "^3.1.1",
"@gnosis.pm/safe-ethers-adapters": "0.1.0-alpha.11",
"@gnosis.pm/safe-ethers-lib": "^1.6.1",
"@react-icons/all-files": "^4.1.0",
"@safe-global/safe-core-sdk": "^3.2.0",
"@safe-global/safe-ethers-adapters": "0.1.0-alpha.13",
"@safe-global/safe-ethers-lib": "^1.7.0",
"@solana/wallet-adapter-phantom": "^0.9.17",
"@tanstack/react-query": "^4.0.10",
"@zag-js/menu": "^0.1.16",
"@zag-js/react": "^0.1.18",
"@zag-js/menu": "^0.3.0",
"@zag-js/react": "^0.3.1",
"buffer": "^6.0.3",
"color": "^4.2.3",
"copy-to-clipboard": "^3.3.2",
"detect-browser": "^5.3.0",
"magic-sdk": "^8.1.1",
"magic-sdk": "^10.1.0",
"mime": "^3.0.0",
"react-cool-dimensions": "^2.0.7",
"tiny-invariant": "^1.2.0",
@@ -14,19 +14,19 @@ export const SupportedNetworkSelect: React.FC<SupportedNetworkSelectProps> = ({
const deprecatedNetworks = useMemo(() => {
return SUPPORTED_CHAIN_IDS.map((supportedChain) => {
return getChainFromChainId(supportedChain);
}).filter((n) => !!n.deprecated);
});
}, []);
const testnets = useMemo(() => {
return SUPPORTED_CHAIN_IDS.map((supportedChain) => {
return getChainFromChainId(supportedChain);
}).filter((n) => n.testnet && !n.deprecated);
});
}, []);
const mainnets = useMemo(() => {
return SUPPORTED_CHAIN_IDS.map((supportedChain) => {
return getChainFromChainId(supportedChain);
}).filter((n) => !n.testnet && !n.deprecated);
});
}, []);
return (
<Select {...selectProps}>
@@ -63,6 +63,7 @@ interface ConnectWalletProps extends ThemeProviderProps {
loginOptional?: boolean;
};
className?: string;
btnTitle?: JSX.Element | string;
}
let connecting = false;
@@ -120,6 +121,7 @@ const chainIdToCurrencyMap: Record<
export const ConnectWallet: React.FC<ConnectWalletProps> = ({
auth,
className,
btnTitle,
...themeProps
}) => {
const id = useId();
@@ -248,7 +250,9 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = ({
</span>
)
) : (
<span style={{ whiteSpace: "nowrap" }}>Connect Wallet</span>
<span style={{ whiteSpace: "nowrap" }}>
{btnTitle || "Connect Wallet"}
</span>
)}
</Button>
@@ -98,12 +98,15 @@ export class GnosisSafeConnector extends Connector {
invariant(serverUrl, "Chain not supported");
const [safeEthersAdapters, safeCoreSdk, safeEthersLib] = await Promise.all([
import("@gnosis.pm/safe-ethers-adapters"),
import("@gnosis.pm/safe-core-sdk"),
import("@gnosis.pm/safe-ethers-lib"),
import("@safe-global/safe-ethers-adapters"),
import("@safe-global/safe-core-sdk"),
import("@safe-global/safe-ethers-lib"),
]);
const ethAdapter = new safeEthersLib.default({ ethers, signer });
const ethAdapter = new safeEthersLib.default({
ethers,
signerOrProvider: signer,
});
const safe = await safeCoreSdk.default.create({
ethAdapter: ethAdapter as any,
@@ -62,6 +62,18 @@ export class MagicConnector extends Connector {
const { apiKey, ...options } = this.options;
const configuration = this.getConfiguration();
const chains = Object.entries(this.options.rpcUrls);
if (chains.length > 1) {
console.warn(
`Magic only supports connecting to one chain at a time. Using the first chain specified in rpcUrls: ${chains[0]}.`,
);
}
const [chainId, rpcUrl] = chains[0];
this.options.network = {
chainId: parseInt(chainId),
rpcUrl,
};
try {
invariant(
configuration,
+1 -1
View File
@@ -2,7 +2,7 @@ import { NATIVE_TOKENS, SUPPORTED_CHAIN_ID } from "@thirdweb-dev/sdk";
import { ChainId } from "@thirdweb-dev/sdk";
import type { Chain as WagmiChain } from "wagmi";
export type Chain = WagmiChain & { deprecated?: boolean };
export type Chain = WagmiChain;
const chain: Record<string, Chain> = {
mainnet: {
id: ChainId.Mainnet,
@@ -238,7 +238,7 @@ export function useContract(
await queryClient.fetchQuery(
compilerMetadata.cacheKey(contractAddress, activeChainId),
() => compilerMetadata.fetchQuery(contractAddress, sdk),
{ cacheTime: Infinity, staleTime: Infinity },
{ cacheTime: Infinity, staleTime: Infinity, retry: 0 },
)
)?.abi;
}
@@ -258,6 +258,8 @@ export function useContract(
cacheTime: Infinity,
staleTime: Infinity,
enabled: !!contractAddress && !!sdk && !!activeChainId,
// never retry
retry: 0,
},
);
+3 -1
View File
@@ -24,7 +24,9 @@ export function useUser() {
authConfig,
"Please specify an authConfig in the ThirdwebProvider",
);
const res = await fetch(`${authConfig.authUrl}/user`);
const res = await fetch(`${authConfig.authUrl}/user`, {
credentials: "include",
});
return (await res.json()) as ThirdwebAuthUser;
},
{
@@ -24,7 +24,9 @@ export function useUser() {
authConfig,
"Please specify an authConfig in the ThirdwebProvider",
);
const res = await fetch(`${authConfig.authUrl}/user`);
const res = await fetch(`${authConfig.authUrl}/user`, {
credentials: "include",
});
return (await res.json()) as ThirdwebAuthUser;
},
{
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+92
View File
@@ -1,5 +1,97 @@
# @thirdweb-dev/sdk
## 3.6.10
### Patch Changes
- [#498](https://github.com/thirdweb-dev/js/pull/498) [`5fba324`](https://github.com/thirdweb-dev/js/commit/5fba324ac17ab02bc8f13d82a232bc5c6970c8e5) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix claim condition detection on legacy contracts
- [#502](https://github.com/thirdweb-dev/js/pull/502) [`894cbef`](https://github.com/thirdweb-dev/js/commit/894cbefc6361f23fc528a6c6819f5c71793d46e4) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add intermediate event for contract deploy transactions before confirmation
- [#463](https://github.com/thirdweb-dev/js/pull/463) [`557429b`](https://github.com/thirdweb-dev/js/commit/557429b5cfb3af2983ee01cf7d12d41ee0557593) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - PackVRF integration
- [#500](https://github.com/thirdweb-dev/js/pull/500) [`73dc026`](https://github.com/thirdweb-dev/js/commit/73dc026ff9d0ac9099bd5a9a9cab8fdbfc0ae723) Thanks [@retocrooman](https://github.com/retocrooman)! - Getting the domain separator is not a required function. If an error occurs there, the permit it self will not be possible. Therefore, error handling should be performed appropriately.
- [#311](https://github.com/thirdweb-dev/js/pull/311) [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add support for multi chain registry
- [#491](https://github.com/thirdweb-dev/js/pull/491) [`68c8e3c`](https://github.com/thirdweb-dev/js/commit/68c8e3c4d79f5d56dc4414241bcca0d88285fcca) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Use multichain registry to resolve contracts that cannot be resolved via IPFS
- [#494](https://github.com/thirdweb-dev/js/pull/494) [`bff433e`](https://github.com/thirdweb-dev/js/commit/bff433e12150dc029e33a578219c8437a510da99) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix deploy transaction listener for all deploy types `sdk.deployer.addDeployListener()`
- Updated dependencies [[`557429b`](https://github.com/thirdweb-dev/js/commit/557429b5cfb3af2983ee01cf7d12d41ee0557593), [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857), [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857)]:
- @thirdweb-dev/contracts-js@1.2.3
## 3.6.9
### Patch Changes
- [#465](https://github.com/thirdweb-dev/js/pull/465) [`e913e0d`](https://github.com/thirdweb-dev/js/commit/e913e0daa9ece9a6274f7ffa4e66bdcbf32e6ada) Thanks [@adam-maj](https://github.com/adam-maj)! - Fix passing options to factory
- [`5862c55`](https://github.com/thirdweb-dev/js/commit/5862c558fb48604b5aca4defd1ccc06fc3536358) Thanks [@kumaryash90](https://github.com/kumaryash90)! - update forwarder address
- [#466](https://github.com/thirdweb-dev/js/pull/466) [`73883f5`](https://github.com/thirdweb-dev/js/commit/73883f56d0ed0a35ace8b98b96caa782443be22e) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - workaround for signing typed data with magic.link signers
- [#468](https://github.com/thirdweb-dev/js/pull/468) [`f7a74a3`](https://github.com/thirdweb-dev/js/commit/f7a74a3b7c489ada5b1ec435632a326334a33c9b) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose `sdk.wallet.signTypedData()`
## 3.6.8
### Patch Changes
- [#454](https://github.com/thirdweb-dev/js/pull/454) [`c673e39`](https://github.com/thirdweb-dev/js/commit/c673e39f23ef082097d73d62910580e8fad400a0) Thanks [@jnsdls](https://github.com/jnsdls)! - upgraded dependencies
- [#421](https://github.com/thirdweb-dev/js/pull/421) [`ea95c5f`](https://github.com/thirdweb-dev/js/commit/ea95c5f609e306e333ee0f73f7920503358ca848) Thanks [@yehia67](https://github.com/yehia67)! - Add new utilities to parse/format currencies. `toEther` & `toWei` as default 18 decimal and `toUnits` & `toDisplayValue` in case of different numbers of decimals.
- [#456](https://github.com/thirdweb-dev/js/pull/456) [`699a2b1`](https://github.com/thirdweb-dev/js/commit/699a2b16fb991c474ec57db8f178e2601d631f39) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SOL] Fix claiming drops with custom currencies
- [#458](https://github.com/thirdweb-dev/js/pull/458) [`4cdd0bd`](https://github.com/thirdweb-dev/js/commit/4cdd0bd6348494a256d7c6a2bdf8f7b5c20f6877) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fixes for latest wallet package integration
- [#453](https://github.com/thirdweb-dev/js/pull/453) [`a8267f9`](https://github.com/thirdweb-dev/js/commit/a8267f912df84c58d3fe3f47b90bd474f73c84ca) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SOL] Drop fixes for large batch uploads
## 3.6.7
### Patch Changes
- [#451](https://github.com/thirdweb-dev/js/pull/451) [`3731459`](https://github.com/thirdweb-dev/js/commit/3731459d33f1ded7ebb69124809449b901b3ad3d) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Less strict prebuilt checks to support OSRF variants
- [#450](https://github.com/thirdweb-dev/js/pull/450) [`cac6c30`](https://github.com/thirdweb-dev/js/commit/cac6c30bca5e17df81d746ef81316af47d5e252e) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix setting allowance or approvals gaslessly
- [#448](https://github.com/thirdweb-dev/js/pull/448) [`7a37e56`](https://github.com/thirdweb-dev/js/commit/7a37e564fd5d5a9df84c8da44ecaf6c42f67a0e2) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - allow `useContract` to fail faster to enable the import case
## 3.6.6
### Patch Changes
- [#443](https://github.com/thirdweb-dev/js/pull/443) [`8c6cdaa`](https://github.com/thirdweb-dev/js/commit/8c6cdaa2887fb2cc40d3ee6991233d195d103805) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix signature minting from OpenSea Royalty Filter NFT collection contracts
## 3.6.5
### Patch Changes
- [#440](https://github.com/thirdweb-dev/js/pull/440) [`efc56fa`](https://github.com/thirdweb-dev/js/commit/efc56fa5802490ac8ef50037658d046afd89e9a1) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - providers are now re-used if the constructor options are identical leading to better batching, also introduced an additional max batch size param (250 by default)
## 3.6.4
### Patch Changes
- [#438](https://github.com/thirdweb-dev/js/pull/438) [`f451da6`](https://github.com/thirdweb-dev/js/commit/f451da6395689a5f89800ee63f34b6175b61f703) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix SigMint detection for OSRF NFT Collection contracts
- [#416](https://github.com/thirdweb-dev/js/pull/416) [`af3acc6`](https://github.com/thirdweb-dev/js/commit/af3acc6b10751b840e56aef6400da5eea6040df2) Thanks [@adam-maj](https://github.com/adam-maj)! - Add support for AWS KMS
- [#424](https://github.com/thirdweb-dev/js/pull/424) [`1bfb91d`](https://github.com/thirdweb-dev/js/commit/1bfb91dbf3a39160c987a425813ac5dbb84703ad) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Improve error parsing for other wallets
- [#436](https://github.com/thirdweb-dev/js/pull/436) [`ee47840`](https://github.com/thirdweb-dev/js/commit/ee478407673b0416e0c1cfe2be11bd6963395348) Thanks [@jnsdls](https://github.com/jnsdls)! - fix #429
- [#434](https://github.com/thirdweb-dev/js/pull/434) [`def4251`](https://github.com/thirdweb-dev/js/commit/def42511ff5a20d83f9094164dafb87e412571b5) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SOL] Remove workaround to fetch NFT owners
- [#429](https://github.com/thirdweb-dev/js/pull/429) [`034a257`](https://github.com/thirdweb-dev/js/commit/034a257442314c67729f7bafcbe3740cff33fa32) Thanks [@jakeloo](https://github.com/jakeloo)! - Extract more minimal proxy impl address
- [#418](https://github.com/thirdweb-dev/js/pull/418) [`eca4776`](https://github.com/thirdweb-dev/js/commit/eca47763cd89cc3b7aa57b542971837987540b55) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Increase gas limit for opening packs
- [#420](https://github.com/thirdweb-dev/js/pull/420) [`639e535`](https://github.com/thirdweb-dev/js/commit/639e535ed55280ad9d081001aab3f5af72bb3e45) Thanks [@jnsdls](https://github.com/jnsdls)! - update deps
- Updated dependencies [[`f451da6`](https://github.com/thirdweb-dev/js/commit/f451da6395689a5f89800ee63f34b6175b61f703)]:
- @thirdweb-dev/contracts-js@1.2.2
## 3.6.3
### Patch Changes
+10 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "3.6.3",
"version": "3.6.10",
"description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
"license": "Apache-2.0",
@@ -62,7 +62,7 @@
"build": "tsc && preconstruct build",
"test:evm:all": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/evm/.mocharc.json' --timeout 30000 --parallel './test/evm/**/*.test.ts'",
"test:evm": "make test-evm",
"test:evm:single": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/evm/.mocharc.json' --timeout 30000",
"test:evm:single": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/evm/.mocharc.json' --timeout 90000",
"node:solana:start": "DEBUG='amman:(info|error|debug)' amman start --forceClone",
"node:solana:stop": "amman stop",
"test:solana:all": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/solana/.mocharc.json' --timeout 30000 --parallel './test/solana/**/*.test.ts'",
@@ -85,7 +85,7 @@
"@types/deep-equal-in-any-order": "^1.0.1",
"@types/mocha": "^10.0.0",
"@types/node": "^18.0.0",
"@types/uuid": "^8.3.3",
"@types/uuid": "^9.0.0",
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"chai": "^4.3.6",
@@ -97,6 +97,7 @@
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-tsdoc": "^0.2.16",
"ethers": "^5.7.2",
"ethers-aws-kms-signer": "^1.3.2",
"hardhat": "^2.9.3",
"mocha": "^10.0.0",
"prettier": "^2.7.1",
@@ -104,11 +105,15 @@
},
"peerDependencies": {
"@aws-sdk/client-secrets-manager": "^3.215.0",
"ethers": "^5"
"ethers": "^5",
"ethers-aws-kms-signer": "^1.3.2"
},
"peerDependenciesMeta": {
"@aws-sdk/client-secrets-manager": {
"optional": true
},
"ethers-aws-kms-signer": {
"optional": true
}
},
"dependencies": {
@@ -122,7 +127,7 @@
"bn.js": "^5.2.1",
"bs58": "^5.0.0",
"cross-fetch": "^3.1.5",
"eventemitter3": "^4.0.7",
"eventemitter3": "^5.0.0",
"fast-deep-equal": "^3.1.3",
"merkletreejs": "^0.2.24",
"tiny-invariant": "^1.2.0",
+2 -2
View File
@@ -1,6 +1,6 @@
export const DEFAULT_API_KEY =
"c6634ad2d97b74baf15ff556016830c251050e6c36b9da508ce3ec80095d3dc1";
export function getRpcUrl(network: string) {
return `https://${network}.rpc.thirdweb.com/${DEFAULT_API_KEY}`;
export function getRpcUrl(network: string, apikey = DEFAULT_API_KEY) {
return `https://${network}.rpc.thirdweb.com/${apikey}`;
}
+18 -2
View File
@@ -124,7 +124,7 @@ export async function setErc20Allowance(
signer || provider,
currencyAddress,
ERC20Abi,
{},
contractToApprove.options,
);
const owner = await contractToApprove.getSignerAddress();
@@ -151,7 +151,7 @@ export async function approveErc20Allowance(
signer || provider,
currencyAddress,
ERC20Abi,
{},
contractToApprove.options,
);
const owner = await contractToApprove.getSignerAddress();
const spender = contractToApprove.readContract.address;
@@ -192,3 +192,19 @@ export async function normalizeAmount(
const decimals = await contractWrapper.readContract.decimals();
return utils.parseUnits(AmountSchema.parse(amount), decimals);
}
export function toEther(amount: BigNumberish): string {
return utils.formatEther(amount);
}
export function toWei(amount: Amount): BigNumber {
return utils.parseEther(AmountSchema.parse(amount));
}
export function toUnits(amount: Amount, decimals: BigNumberish): BigNumber {
return utils.parseUnits(AmountSchema.parse(amount), decimals);
}
export function toDisplayValue(amount: BigNumberish, decimals: BigNumberish): string {
return utils.formatUnits(amount, decimals);
}
+14 -5
View File
@@ -286,7 +286,7 @@ export class TransactionError extends Error {
raw: string,
functionInfo: FunctionInfo | undefined,
) {
let builtErrorMsg = "Contract transaction failed\n\n";
let builtErrorMsg = "\n| Contract transaction failed |\n\n";
builtErrorMsg += `Message: ${reason}`;
builtErrorMsg += "\n\n| Transaction info |\n";
builtErrorMsg += withSpaces("from", from);
@@ -320,9 +320,6 @@ export class TransactionError extends Error {
// ignore if can't parse URL
}
builtErrorMsg += "\n\n";
builtErrorMsg +=
"Need help with this error? Join our community: https://discord.gg/thirdweb";
builtErrorMsg += "\n\n\n\n";
builtErrorMsg += "| Raw error |";
builtErrorMsg += "\n\n";
builtErrorMsg += raw;
@@ -401,7 +398,19 @@ export async function convertToTWError(
// not sure what this is, just throw it back
raw = error.toString();
}
const reason = parseMessageParts(/.*?"message[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
let reason =
parseMessageParts(/.*?"message[^a-zA-Z0-9]*([^"\\]*).*?/, raw) ||
parseMessageParts(/.*?"reason[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
if (reason && reason.toLowerCase().includes("cannot estimate gas")) {
// the error might be in the next reason block
const nextReason = parseMessageParts(
/.*?"reason[^a-zA-Z0-9]*([^"\\]*).*?/,
raw.slice(raw.indexOf(reason) + reason.length),
);
if (nextReason) {
reason = nextReason;
}
}
const data = parseMessageParts(/.*?"data[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
const rpcUrl = parseMessageParts(/.*?"url[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
let from = parseMessageParts(/.*?"from[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
+50 -108
View File
@@ -13,16 +13,14 @@ import {
AbiFunction,
AbiSchema,
AbiTypeSchema,
ContractInfoSchema,
ContractSource,
FullPublishMetadata,
FullPublishMetadataSchemaOutput,
PreDeployMetadata,
PreDeployMetadataFetched,
PreDeployMetadataFetchedSchema,
PublishedMetadata,
} from "../schema/contracts/custom";
import { ExtensionNotImplementedError } from "./error";
import { fetchContractMetadata } from "./metadata-resolver";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import bs58 from "bs58";
import { BaseContract, BigNumber, ethers } from "ethers";
@@ -266,6 +264,42 @@ function toJSType(
return jsType;
}
/**
* @internal
* @param bytecode
*/
export function extractMinimalProxyImplementationAddress(
bytecode: string,
): string | undefined {
// EIP-1167 clone minimal proxy - https://eips.ethereum.org/EIPS/eip-1167
if (bytecode.startsWith("0x363d3d373d3d3d363d73")) {
const implementationAddress = bytecode.slice(22, 62);
return `0x${implementationAddress}`;
}
// Minimal Proxy with receive() from 0xSplits - https://github.com/0xSplits/splits-contracts/blob/c7b741926ec9746182d0d1e2c4c2046102e5d337/contracts/libraries/Clones.sol
if (bytecode.startsWith("0x36603057343d5230")) {
// +40 = size of addr
const implementationAddress = bytecode.slice(122, 122 + 40);
return `0x${implementationAddress}`;
}
// 0age's minimal proxy - https://medium.com/coinmonks/the-more-minimal-proxy-5756ae08ee48
if (bytecode.startsWith("0x3d3d3d3d363d3d37363d73")) {
// +40 = size of addr
const implementationAddress = bytecode.slice(24, 24 + 40);
return `0x${implementationAddress}`;
}
// vyper's minimal proxy (uniswap v1) - https://etherscan.io/address/0x09cabec1ead1c0ba254b09efb3ee13841712be14#code
if (bytecode.startsWith("0x366000600037611000600036600073")) {
const implementationAddress = bytecode.slice(32, 32 + 40);
return `0x${implementationAddress}`;
}
return undefined;
}
/**
* @internal
* @param address
@@ -282,14 +316,20 @@ export async function resolveContractUriFromAddress(
`Contract at ${address} does not exist on chain '${chain.name}' (chainId: ${chain.chainId})`,
);
}
// EIP-1167 clone proxy - https://eips.ethereum.org/EIPS/eip-1167
if (bytecode.startsWith("0x363d3d373d3d3d363d")) {
const implementationAddress = bytecode.slice(22, 62);
return await resolveContractUriFromAddress(
`0x${implementationAddress}`,
provider,
);
try {
const implementationAddress =
extractMinimalProxyImplementationAddress(bytecode);
if (implementationAddress) {
return await resolveContractUriFromAddress(
implementationAddress,
provider,
);
}
} catch (e) {
// ignore
}
// EIP-1967 proxy storage slots - https://eips.ethereum.org/EIPS/eip-1967
try {
const proxyStorage = await provider.getStorageAt(
@@ -369,104 +409,6 @@ function isHexStrict(hex: string | number) {
);
}
/**
* @internal
* @param address
* @param provider
* @param storage
*/
export async function fetchContractMetadataFromAddress(
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) {
const compilerMetadataUri = await resolveContractUriFromAddress(
address,
provider,
);
if (!compilerMetadataUri) {
throw new Error(`Could not resolve metadata for contract at ${address}`);
}
return await fetchContractMetadata(compilerMetadataUri, storage);
}
/**
* @internal
* @param compilerMetadataUri
* @param storage
*/
export async function fetchContractMetadata(
compilerMetadataUri: string,
storage: ThirdwebStorage,
): Promise<PublishedMetadata> {
const metadata = await storage.downloadJSON(compilerMetadataUri);
const abi = AbiSchema.parse(metadata.output.abi);
const compilationTarget = metadata.settings.compilationTarget;
const targets = Object.keys(compilationTarget);
const name = compilationTarget[targets[0]];
const info = ContractInfoSchema.parse({
title: metadata.output.devdoc.title,
author: metadata.output.devdoc.author,
details: metadata.output.devdoc.detail,
notice: metadata.output.userdoc.notice,
});
const licenses: string[] = [
...new Set(
Object.entries(metadata.sources).map(([, src]) => (src as any).license),
),
];
return {
name,
abi,
metadata,
info,
licenses,
};
}
/**
* @internal
* @param publishedMetadata
* @param storage
*/
export async function fetchSourceFilesFromMetadata(
publishedMetadata: PublishedMetadata,
storage: ThirdwebStorage,
): Promise<ContractSource[]> {
return await Promise.all(
Object.entries(publishedMetadata.metadata.sources).map(
async ([path, info]) => {
const urls = (info as any).urls as string[];
const ipfsLink = urls
? urls.find((url) => url.includes("ipfs"))
: undefined;
if (ipfsLink) {
const ipfsHash = ipfsLink.split("ipfs/")[1];
// 5 sec timeout for sources that haven't been uploaded to ipfs
const timeout = new Promise<string>((_r, rej) =>
setTimeout(() => rej("timeout"), 5000),
);
const source = await Promise.race([
(await storage.download(`ipfs://${ipfsHash}`)).text(),
timeout,
]);
return {
filename: path,
source,
};
} else {
return {
filename: path,
source:
(info as any).content ||
"Could not find source for this contract",
};
}
},
),
);
}
/**
* @internal
* @param publishMetadataUri
+1
View File
@@ -1,6 +1,7 @@
export * from "./error";
export * from "./snapshots";
export * from "./role";
export * from "./metadata-resolver";
export * from "./feature-detection";
export * from "./version-checker";
// export helpful util
+16 -12
View File
@@ -3,7 +3,6 @@ import {
InterfaceId_IERC1155,
InterfaceId_IERC721,
} from "../constants/contract";
import { SignerOrProvider } from "../core";
import { ContractWrapper } from "../core/classes/contract-wrapper";
import {
NewAuctionListing,
@@ -76,33 +75,38 @@ export async function isTokenApprovedForTransfer(
/**
* Checks if the marketplace is approved to make transfers on the assetContract
* If not, it tries to set the approval.
* @param signerOrProvider
* @param contractWrapper
* @param marketplaceAddress
* @param assetContract
* @param tokenId
* @param from
*/
export async function handleTokenApproval(
signerOrProvider: SignerOrProvider,
contractWrapper: ContractWrapper<any>,
marketplaceAddress: string,
assetContract: string,
tokenId: BigNumberish,
from: string,
): Promise<void> {
const erc165 = new Contract(
const erc165 = new ContractWrapper<IERC165>(
contractWrapper.getSignerOrProvider(),
assetContract,
ERC165Abi,
signerOrProvider,
) as IERC165;
const isERC721 = await erc165.supportsInterface(InterfaceId_IERC721);
const isERC1155 = await erc165.supportsInterface(InterfaceId_IERC1155);
contractWrapper.options,
);
const isERC721 = await erc165.readContract.supportsInterface(
InterfaceId_IERC721,
);
const isERC1155 = await erc165.readContract.supportsInterface(
InterfaceId_IERC1155,
);
// check for token approval
if (isERC721) {
const asset = new ContractWrapper<IERC721>(
signerOrProvider,
contractWrapper.getSignerOrProvider(),
assetContract,
ERC721Abi,
{},
contractWrapper.options,
);
const approved = await asset.readContract.isApprovedForAll(
from,
@@ -122,10 +126,10 @@ export async function handleTokenApproval(
}
} else if (isERC1155) {
const asset = new ContractWrapper<IERC1155>(
signerOrProvider,
contractWrapper.getSignerOrProvider(),
assetContract,
ERC1155Abi,
{},
contractWrapper.options,
);
const approved = await asset.readContract.isApprovedForAll(
@@ -0,0 +1,188 @@
import { ThirdwebSDK } from "../core";
import {
Abi,
PublishedMetadata,
AbiSchema,
ContractInfoSchema,
ContractSource,
} from "../schema";
import { resolveContractUriFromAddress } from "./feature-detection";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { providers } from "ethers";
// Internal static cache
const metadataCache: Record<string, PublishedMetadata> = {};
// polygonSDK to fetch metadata from the multichain registry
const polygonSDK = new ThirdwebSDK("polygon");
function getCacheKey(address: string, chainId: number) {
return `${address}-${chainId}`;
}
function putInCache(
address: string,
chainId: number,
metadata: PublishedMetadata,
) {
metadataCache[getCacheKey(address, chainId)] = metadata;
}
function getFromCache(address: string, chainId: number) {
return metadataCache[getCacheKey(address, chainId)];
}
/**
* @internal
* @param address
* @param provider
* @param storage
*/
export async function fetchContractMetadataFromAddress(
address: string,
provider: providers.Provider,
storage: ThirdwebStorage,
) {
const chainId = (await provider.getNetwork()).chainId;
const cached = getFromCache(address, chainId);
if (cached) {
return cached;
}
let metadata: PublishedMetadata | undefined;
try {
const compilerMetadataUri = await resolveContractUriFromAddress(
address,
provider,
);
if (!compilerMetadataUri) {
throw new Error(`Could not resolve metadata for contract at ${address}`);
}
metadata = await fetchContractMetadata(compilerMetadataUri, storage);
} catch (e) {
try {
// try from multichain registry
const importedUri =
await polygonSDK.multiChainRegistry.getContractMetadataURI(
chainId,
address,
);
metadata = await fetchContractMetadata(importedUri, storage);
} catch (err) {
throw new Error(`Could not resolve metadata for contract at ${address}`);
}
}
if (!metadata) {
throw new Error(`Could not resolve metadata for contract at ${address}`);
}
putInCache(address, chainId, metadata);
return metadata;
}
/**
* @internal
* @param address
* @param provider
* @param storage
* @returns
*/
export async function fetchAbiFromAddress(
address: string,
provider: providers.Provider,
storage: ThirdwebStorage,
): Promise<Abi | undefined> {
try {
const metadata = await fetchContractMetadataFromAddress(
address,
provider,
storage,
);
if (metadata && metadata.abi) {
return metadata.abi;
}
} catch (e) {
// ignore and return undefined
// will fallback to embedded ABIs for prebuilts
}
return undefined;
}
/**
* @internal
* @param compilerMetadataUri
* @param storage
*/
export async function fetchContractMetadata(
compilerMetadataUri: string,
storage: ThirdwebStorage,
): Promise<PublishedMetadata> {
const metadata = await storage.downloadJSON(compilerMetadataUri);
if (!metadata || !metadata.output) {
throw new Error(
`Could not resolve metadata for contract at ${compilerMetadataUri}`,
);
}
const abi = AbiSchema.parse(metadata.output.abi);
const compilationTarget = metadata.settings.compilationTarget;
const targets = Object.keys(compilationTarget);
const name = compilationTarget[targets[0]];
const info = ContractInfoSchema.parse({
title: metadata.output.devdoc.title,
author: metadata.output.devdoc.author,
details: metadata.output.devdoc.detail,
notice: metadata.output.userdoc.notice,
});
const licenses: string[] = [
...new Set(
Object.entries(metadata.sources).map(([, src]) => (src as any).license),
),
];
return {
name,
abi,
metadata,
info,
licenses,
};
}
/**
* @internal
* @param publishedMetadata
* @param storage
*/
export async function fetchSourceFilesFromMetadata(
publishedMetadata: PublishedMetadata,
storage: ThirdwebStorage,
): Promise<ContractSource[]> {
return await Promise.all(
Object.entries(publishedMetadata.metadata.sources).map(
async ([path, info]) => {
const urls = (info as any).urls as string[];
const ipfsLink = urls
? urls.find((url) => url.includes("ipfs"))
: undefined;
if (ipfsLink) {
const ipfsHash = ipfsLink.split("ipfs/")[1];
// 3 sec timeout for sources that haven't been uploaded to ipfs
const timeout = new Promise<string>((_r, rej) =>
setTimeout(() => rej("timeout"), 3000),
);
const source = await Promise.race([
(await storage.download(`ipfs://${ipfsHash}`)).text(),
timeout,
]);
return {
filename: path,
source,
};
} else {
return {
filename: path,
source:
(info as any).content ||
"Could not find source for this contract",
};
}
},
),
);
}
+8 -1
View File
@@ -71,7 +71,14 @@ async function getDomainSeperator(signer: Signer, contractAddress: string) {
try {
return await contract.DOMAIN_SEPARATOR();
} catch (err) {
return await contract.getDomainSeperator();
try {
return await contract.getDomainSeperator();
} catch (err2) {
console.error(
'Error getting domain separator',
err2
)
}
}
}
+11 -2
View File
@@ -49,6 +49,7 @@ export async function signTypedDataInternal(
);
let signature = "";
const signerAddress = (await signer.getAddress()).toLowerCase();
// an indirect way for accessing walletconnect's underlying provider
if ((provider as any)?.provider?.isWalletConnect) {
@@ -66,11 +67,19 @@ export async function signTypedDataInternal(
} catch (err: any) {
if (err?.message?.includes("Method eth_signTypedData_v4 not supported")) {
signature = await provider.send("eth_signTypedData", [
(await signer.getAddress()).toLowerCase(),
signerAddress,
JSON.stringify(payload),
]);
} else {
throw err;
// magic.link signer only supports this way
try {
await provider.send("eth_signTypedData_v4", [
signerAddress,
JSON.stringify(payload),
]);
} catch (finalErr: any) {
throw finalErr;
}
}
}
}
+16 -2
View File
@@ -11,6 +11,7 @@ export const OZ_DEFENDER_FORWARDER_ADDRESS =
const TWRegistry_address = "0x7c487845f98938Bb955B1D5AD069d9a30e4131fd";
const TWFactory_address = "0x5DBC7B840baa9daBcBe9D2492E45D7244B54A2A0";
const ContractPublisher_address = "0x664244560eBa21Bf82d7150C791bE1AbcD5B4cd7"; // Polygon only
const MultichainRegistry_address = "0xcdAD8FA86e18538aC207872E8ff3536501431B73"; // Polygon only
/**
* @internal
@@ -92,7 +93,7 @@ export const CONTRACT_ADDRESSES: Record<
twBYOCRegistry: "0x3E6eE864f850F5e5A98bc950B68E181Cf4010F23",
},
[ChainId.Arbitrum]: {
openzeppelinForwarder: OZ_DEFENDER_FORWARDER_ADDRESS,
openzeppelinForwarder: "0x8cbc8B5d71702032904750A66AEfE8B603eBC538",
openzeppelinForwarderEOA: "0x4f247c69184ad61036EC2Bb3213b69F10FbEDe1F",
biconomyForwarder: "0xfe0fa3C06d03bDC7fb49c892BbB39113B534fB57",
twFactory: "0xd24b3de085CFd8c54b94feAD08a7962D343E6DE0",
@@ -109,7 +110,7 @@ export const CONTRACT_ADDRESSES: Record<
twBYOCRegistry: constants.AddressZero,
},
[ChainId.Optimism]: {
openzeppelinForwarder: OZ_DEFENDER_FORWARDER_ADDRESS,
openzeppelinForwarder: "0x8cbc8B5d71702032904750A66AEfE8B603eBC538",
openzeppelinForwarderEOA: "0x7e80648EB2071E26937F9D42A513ccf4815fc702",
biconomyForwarder: "0xefba8a2a82ec1fb1273806174f5e28fbb917cf95",
twFactory: "0xd24b3de085CFd8c54b94feAD08a7962D343E6DE0",
@@ -291,6 +292,19 @@ export function getContractPublisherAddress() {
}
}
/**
* @internal
*/
export function getMultichainRegistryAddress() {
// eslint-disable-next-line turbo/no-undeclared-env-vars
if (process.env.multiChainRegistryAddress) {
// eslint-disable-next-line turbo/no-undeclared-env-vars
return process.env.multiChainRegistryAddress as string;
} else {
return MultichainRegistry_address;
}
}
/**
*
* @param chainId - chain id
@@ -53,6 +53,7 @@ import {
FEATURE_ROYALTY,
FEATURE_APPURI,
FEATURE_GASLESS,
FEATURE_PACK_VRF,
} from "./thirdweb-features";
/**
@@ -106,7 +107,8 @@ export type Feature =
| typeof FEATURE_METADATA
| typeof FEATURE_APPURI
| typeof FEATURE_OWNER
| typeof FEATURE_GASLESS;
| typeof FEATURE_GASLESS
| typeof FEATURE_PACK_VRF;
/**
* @internal
@@ -135,4 +137,5 @@ export const SUPPORTED_FEATURES: Record<string, Feature> = {
[FEATURE_APPURI.name]: FEATURE_APPURI,
[FEATURE_OWNER.name]: FEATURE_OWNER,
[FEATURE_GASLESS.name]: FEATURE_GASLESS,
[FEATURE_PACK_VRF.name]: FEATURE_PACK_VRF,
};
@@ -176,3 +176,16 @@ export const NATIVE_TOKENS: Record<
export function getNativeTokenByChainId(chainId: ChainId): NativeToken {
return NATIVE_TOKENS[chainId as SUPPORTED_CHAIN_ID];
}
export const LINK_TOKEN_ADDRESS: Record<number, string> = {
[ChainId.Mainnet]: "0x514910771AF9Ca656af840dff83E8264EcF986CA",
[ChainId.Goerli]: "0x326C977E6efc84E512bB9C30f76E30c160eD06FB",
[ChainId.BinanceSmartChainMainnet]:
"0x404460C6A5EdE2D891e8297795264fDe62ADBB75",
[ChainId.Polygon]: "0xb0897686c545045aFc77CF20eC7A532E3120E0F1",
[ChainId.Mumbai]: "0x326C977E6efc84E512bB9C30f76E30c160eD06FB",
[ChainId.Avalanche]: "0x5947BB275c521040051D82396192181b413227A3",
[ChainId.AvalancheFujiTestnet]: "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846",
[ChainId.Fantom]: "0x6F43FF82CCA38001B6699a8AC47A2d0E66939407",
[ChainId.FantomTestnet]: "0xfaFedb041c0DD4fA2Dc0d87a6B0979Ee6FA7af5F",
};
@@ -1,8 +1,8 @@
import DropERC1155_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/DropERC1155_V2.json";
import IBurnableERC1155Abi from "@thirdweb-dev/contracts-js/dist/abis/IBurnableERC1155.json";
import IClaimableERC1155 from "@thirdweb-dev/contracts-js/dist/abis/IClaimableERC1155.json";
import DelayedRevealAbi from "@thirdweb-dev/contracts-js/dist/abis/IDelayedReveal.json";
import IDropMultiPhase1155 from "@thirdweb-dev/contracts-js/dist/abis/IDrop1155.json";
import DropERC1155_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/IDropERC1155_V2.json";
import IDropSinglePhase1155 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase1155.json";
import IDropSinglePhase1155_V1 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase1155_V1.json";
import Erc1155Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC1155.json";
@@ -1,6 +1,6 @@
import DropERC20_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/DropERC20_V2.json";
import IBurnableERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IBurnableERC20.json";
import IDrop from "@thirdweb-dev/contracts-js/dist/abis/IDrop.json";
import DropERC20_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/IDropERC20_V2.json";
import IDropSinglePhase from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase.json";
import IDropSinglePhaseV1 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase_V1.json";
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
@@ -1,8 +1,8 @@
import DropERC721_V3Abi from "@thirdweb-dev/contracts-js/dist/abis/DropERC721_V3.json";
import IBurnableERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/IBurnableERC721.json";
import IClaimableERC721 from "@thirdweb-dev/contracts-js/dist/abis/IClaimableERC721.json";
import DelayedRevealAbi from "@thirdweb-dev/contracts-js/dist/abis/IDelayedReveal.json";
import IDrop from "@thirdweb-dev/contracts-js/dist/abis/IDrop.json";
import DropERC721_V3Abi from "@thirdweb-dev/contracts-js/dist/abis/IDropERC721_V3.json";
import IDropSinglePhase from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase.json";
import IDropSinglePhaseV1 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase_V1.json";
import Erc721Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC721.json";
@@ -12,8 +12,8 @@ import ILazyMintAbi from "@thirdweb-dev/contracts-js/dist/abis/ILazyMint.json";
import IMintableERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/IMintableERC721.json";
import MulticallAbi from "@thirdweb-dev/contracts-js/dist/abis/IMulticall.json";
import SignatureMintERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC721.json";
import SignatureMintERC721_V1Abi from "@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC721_V1.json";
import TieredDropAbi from "@thirdweb-dev/contracts-js/dist/abis/LazyMintWithTier.json";
import TokenERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/TokenERC721.json";
export const FEATURE_NFT_BURNABLE = {
name: "ERC721Burnable",
@@ -163,7 +163,7 @@ export const FEATURE_NFT_SIGNATURE_MINTABLE_V1 = {
sdk: "sdk.erc721signaturemint",
contracts: "ISignatureMintERC721",
},
abis: [TokenERC721Abi],
abis: [SignatureMintERC721_V1Abi],
features: {},
} as const;
@@ -1,6 +1,7 @@
import IERC2771ContextAbi from "@thirdweb-dev/contracts-js/dist/abis/ERC2771Context.json";
import IAppURI from "@thirdweb-dev/contracts-js/dist/abis/IAppURI.json";
import IContractMetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/IContractMetadata.json";
import IPackVRFAbi from "@thirdweb-dev/contracts-js/dist/abis/IPackVRFDirect.json";
import IPermissionsAbi from "@thirdweb-dev/contracts-js/dist/abis/IPermissions.json";
import IPermissionsEnumerableAbi from "@thirdweb-dev/contracts-js/dist/abis/IPermissionsEnumerable.json";
import IThirdwebPlatformFeeAbi from "@thirdweb-dev/contracts-js/dist/abis/IPlatformFee.json";
@@ -109,3 +110,14 @@ export const FEATURE_GASLESS = {
abis: [IERC2771ContextAbi],
features: {},
} as const;
export const FEATURE_PACK_VRF = {
name: "PackVRF",
namespace: "pack.vrf",
docLinks: {
sdk: "sdk.packvrf",
contracts: "IPackVRFDirect",
},
abis: [IPackVRFAbi],
features: {},
} as const;
+32 -1
View File
@@ -123,6 +123,11 @@ export function getProviderForNetwork(network: ChainOrRpc | SignerOrProvider) {
}
}
const READONLY_PROVIDER_MAP: Map<
string,
StaticJsonRpcBatchProvider | providers.JsonRpcBatchProvider
> = new Map();
/**
*
* @param network - the chain name or rpc url
@@ -136,11 +141,19 @@ export function getReadOnlyProvider(network: string, chainId?: number) {
if (match) {
switch (match[1]) {
case "http":
return chainId
const seralizedOpts = `${network}-${chainId || -1}`;
const existingProvider = READONLY_PROVIDER_MAP.get(seralizedOpts);
if (existingProvider) {
return existingProvider;
}
const newProvider = chainId
? // if we know the chainId we should use the StaticJsonRpcBatchProvider
new StaticJsonRpcBatchProvider(network, chainId)
: // otherwise fall back to the built in json rpc batch provider
new providers.JsonRpcBatchProvider(network, chainId);
READONLY_PROVIDER_MAP.set(seralizedOpts, newProvider);
return newProvider;
case "ws":
return new providers.WebSocketProvider(network, chainId);
@@ -155,3 +168,21 @@ export function getReadOnlyProvider(network: string, chainId?: number) {
return ethers.getDefaultProvider(network);
}
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const ChainIdToName: Record<number, string> = {
[ChainId.Polygon]: "polygon",
[ChainId.Mumbai]: "mumbai",
[ChainId.Goerli]: "goerli",
[ChainId.Mainnet]: "mainnet",
[ChainId.Optimism]: "optimism",
[ChainId.OptimismGoerli]: "optimism-goerli",
[ChainId.Arbitrum]: "arbitrum",
[ChainId.ArbitrumGoerli]: "arbitrum-goerli",
[ChainId.Fantom]: "fantom",
[ChainId.FantomTestnet]: "fantom-testnet",
[ChainId.Avalanche]: "avalanche",
[ChainId.AvalancheFujiTestnet]: "avalanche-fuji",
[ChainId.BinanceSmartChainMainnet]: "binance",
[ChainId.BinanceSmartChainTestnet]: "binance-testnet",
};
+150 -65
View File
@@ -1,4 +1,6 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { getPrebuiltInfo } from "../common/legacy";
import { fetchAbiFromAddress } from "../common/metadata-resolver";
import { ALL_ROLES } from "../common/role";
import { getSignerAndProvider } from "../core/classes/rpc-connection-handler";
import type {
@@ -18,10 +20,10 @@ import {
TokenErc721ContractSchema,
VoteContractSchema,
} from "../schema";
import { CustomContractSchema } from "../schema/contracts/custom";
import { Abi, CustomContractSchema } from "../schema/contracts/custom";
import { DropErc20ContractSchema } from "../schema/contracts/drop-erc20";
import { MultiwrapContractSchema } from "../schema/contracts/multiwrap";
import type { ThirdwebStorage } from "@thirdweb-dev/storage";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { ethers } from "ethers";
type InitalizeParams = [
@@ -41,7 +43,7 @@ export const EditionDropInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
await EditionDropInitializer.getAbi(address, provider),
await EditionDropInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/edition-drop"),
provider.getNetwork(),
]);
@@ -55,13 +57,18 @@ export const EditionDropInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
const contractInfo = await assertContractType(
address,
provider,
"edition-drop",
);
return contractInfo.version > 2
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
const contractInfo = await getContractInfo(address, provider);
return !contractInfo || contractInfo.version > 2
? (await import("@thirdweb-dev/contracts-js/dist/abis/DropERC1155.json"))
.default
: (
@@ -82,7 +89,7 @@ export const EditionInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
EditionInitializer.getAbi(address, provider),
EditionInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/edition"),
provider.getNetwork(),
]);
@@ -96,8 +103,16 @@ export const EditionInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
await assertContractType(address, provider, "edition");
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
return (
await import("@thirdweb-dev/contracts-js/dist/abis/TokenERC1155.json")
).default;
@@ -114,7 +129,7 @@ export const MarketplaceInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
MarketplaceInitializer.getAbi(address, provider),
MarketplaceInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/marketplace"),
provider.getNetwork(),
]);
@@ -128,8 +143,16 @@ export const MarketplaceInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
await assertContractType(address, provider, "marketplace");
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
return (
await import("@thirdweb-dev/contracts-js/dist/abis/Marketplace.json")
).default;
@@ -146,7 +169,7 @@ export const MultiwrapInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
MultiwrapInitializer.getAbi(address, provider),
MultiwrapInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/multiwrap"),
provider.getNetwork(),
]);
@@ -160,8 +183,16 @@ export const MultiwrapInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
await assertContractType(address, provider, "multiwrap");
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
return (await import("@thirdweb-dev/contracts-js/dist/abis/Multiwrap.json"))
.default;
},
@@ -178,7 +209,7 @@ export const NFTCollectionInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
NFTCollectionInitializer.getAbi(address, provider),
NFTCollectionInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/nft-collection"),
provider.getNetwork(),
]);
@@ -192,8 +223,16 @@ export const NFTCollectionInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
await assertContractType(address, provider, "nft-collection");
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
return (
await import("@thirdweb-dev/contracts-js/dist/abis/TokenERC721.json")
).default;
@@ -210,7 +249,7 @@ export const NFTDropInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
NFTDropInitializer.getAbi(address, provider),
NFTDropInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/nft-drop"),
provider.getNetwork(),
]);
@@ -224,13 +263,18 @@ export const NFTDropInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
const contractInfo = await assertContractType(
address,
provider,
"nft-drop",
);
return contractInfo.version > 3
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
const contractInfo = await getContractInfo(address, provider);
return !contractInfo || contractInfo.version > 3
? (await import("@thirdweb-dev/contracts-js/dist/abis/DropERC721.json"))
.default
: (
@@ -252,7 +296,7 @@ export const PackInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
PackInitializer.getAbi(address, provider),
PackInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/pack"),
provider.getNetwork(),
]);
@@ -266,8 +310,16 @@ export const PackInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
await assertContractType(address, provider, "pack");
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
): Promise<Abi> => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
return (await import("@thirdweb-dev/contracts-js/dist/abis/Pack.json"))
.default;
},
@@ -284,7 +336,7 @@ export const SignatureDropInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
SignatureDropInitializer.getAbi(address, provider),
SignatureDropInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/signature-drop"),
provider.getNetwork(),
]);
@@ -298,13 +350,18 @@ export const SignatureDropInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
const contractInfo = await assertContractType(
address,
provider,
"signature-drop",
);
return contractInfo.version > 4
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
const contractInfo = await getContractInfo(address, provider);
return !contractInfo || contractInfo.version > 4
? (
await import(
"@thirdweb-dev/contracts-js/dist/abis/SignatureDrop.json"
@@ -329,7 +386,7 @@ export const SplitInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
SplitInitializer.getAbi(address, provider),
SplitInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/split"),
provider.getNetwork(),
]);
@@ -343,8 +400,16 @@ export const SplitInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
await assertContractType(address, provider, "split");
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
return (await import("@thirdweb-dev/contracts-js/dist/abis/Split.json"))
.default;
},
@@ -361,7 +426,7 @@ export const TokenDropInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
TokenDropInitializer.getAbi(address, provider),
TokenDropInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/token-drop"),
provider.getNetwork(),
]);
@@ -375,13 +440,18 @@ export const TokenDropInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
const contractInfo = await assertContractType(
address,
provider,
"token-drop",
);
return contractInfo.version > 2
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
const contractInfo = await getContractInfo(address, provider);
return !contractInfo || contractInfo.version > 2
? (await import("@thirdweb-dev/contracts-js/dist/abis/DropERC20.json"))
.default
: (await import("@thirdweb-dev/contracts-js/dist/abis/DropERC20_V2.json"))
@@ -399,7 +469,7 @@ export const TokenInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
TokenInitializer.getAbi(address, provider),
TokenInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/token"),
provider.getNetwork(),
]);
@@ -413,8 +483,16 @@ export const TokenInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
await assertContractType(address, provider, "token");
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
return (
await import("@thirdweb-dev/contracts-js/dist/abis/TokenERC20.json")
).default;
@@ -432,7 +510,7 @@ export const VoteInitializer = {
) => {
const [, provider] = getSignerAndProvider(network, options);
const [abi, contract, _network] = await Promise.all([
VoteInitializer.getAbi(address, provider),
VoteInitializer.getAbi(address, provider, storage),
import("./prebuilt-implementations/vote"),
provider.getNetwork(),
]);
@@ -446,23 +524,30 @@ export const VoteInitializer = {
_network.chainId,
);
},
getAbi: async (address: string, provider: ethers.providers.Provider) => {
await assertContractType(address, provider, "vote");
getAbi: async (
address: string,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
) => {
const abi = await fetchAbiFromAddress(address, provider, storage);
if (abi) {
return abi;
}
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
return (await import("@thirdweb-dev/contracts-js/dist/abis/VoteERC20.json"))
.default;
},
};
async function assertContractType(
async function getContractInfo(
address: string,
provider: ethers.providers.Provider,
type: PrebuiltContractType,
) {
const contractInfo = await getPrebuiltInfo(address, provider);
if (!contractInfo || contractInfo.type !== getContractName(type)) {
throw new Error(`Contract is not a ${type}`);
try {
return await getPrebuiltInfo(address, provider);
} catch (e) {
return undefined;
}
return contractInfo;
}
/**
@@ -487,7 +572,7 @@ export const PREBUILT_CONTRACTS_MAP = {
const SmartContract = {
name: "SmartContract" as const,
contractType: "custom" as const,
schema: CustomContractSchema,
schema: {},
roles: ALL_ROLES,
};
@@ -23,10 +23,10 @@ import {
TransactionResultWithId,
} from "../../core/types";
import { PaperCheckout } from "../../integrations/thirdweb-checkout";
import { Abi } from "../../schema/contracts/custom";
import { DropErc1155ContractSchema } from "../../schema/contracts/drop-erc1155";
import { SDKOptions } from "../../schema/sdk-options";
import { PrebuiltEditionDrop } from "../../types/eips";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/DropERC1155.json";
import { ThirdwebStorage, UploadProgressEvent } from "@thirdweb-dev/storage";
import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
@@ -47,7 +47,7 @@ import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
export class EditionDrop extends StandardErc1155<PrebuiltEditionDrop> {
private static contractRoles = ["admin", "minter", "transfer"] as const;
public abi: typeof ABI;
public abi: Abi;
public sales: ContractPrimarySale<PrebuiltEditionDrop>;
public platformFees: ContractPlatformFee<PrebuiltEditionDrop>;
public encoder: ContractEncoder<PrebuiltEditionDrop>;
@@ -124,7 +124,7 @@ export class EditionDrop extends StandardErc1155<PrebuiltEditionDrop> {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<PrebuiltEditionDrop>(
network,
@@ -20,11 +20,11 @@ import {
TransactionResult,
TransactionResultWithId,
} from "../../core/types";
import { Abi } from "../../schema/contracts/custom";
import { TokenErc1155ContractSchema } from "../../schema/contracts/token-erc1155";
import { SDKOptions } from "../../schema/sdk-options";
import { EditionMetadataOrUri } from "../../schema/tokens/edition";
import type { TokenERC1155 } from "@thirdweb-dev/contracts-js";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/TokenERC1155.json";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
@@ -45,7 +45,7 @@ import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
export class Edition extends StandardErc1155<TokenERC1155> {
static contractRoles = ["admin", "minter", "transfer"] as const;
public abi: typeof ABI;
public abi: Abi;
public metadata: ContractMetadata<
TokenERC1155,
typeof TokenErc1155ContractSchema
@@ -104,7 +104,7 @@ export class Edition extends StandardErc1155<TokenERC1155> {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<TokenERC1155>(
network,
@@ -17,6 +17,7 @@ import { MarketplaceDirect } from "../../core/classes/marketplace-direct";
import { UpdateableNetwork } from "../../core/interfaces/contract";
import { NetworkOrSignerOrProvider, TransactionResult } from "../../core/types";
import { ListingType } from "../../enums";
import { Abi } from "../../schema/contracts/custom";
import { MarketplaceContractSchema } from "../../schema/contracts/marketplace";
import { SDKOptions } from "../../schema/sdk-options";
import { Price } from "../../types/currency";
@@ -24,7 +25,6 @@ import { AuctionListing, DirectListing, Offer } from "../../types/marketplace";
import { MarketplaceFilter } from "../../types/marketplace/MarketPlaceFilter";
import { UnmappedOffer } from "../../types/marketplace/UnmappedOffer";
import type { Marketplace as MarketplaceContract } from "@thirdweb-dev/contracts-js";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/Marketplace.json";
import { NewOfferEventObject } from "@thirdweb-dev/contracts-js/dist/declarations/src/Marketplace";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
@@ -47,7 +47,7 @@ import invariant from "tiny-invariant";
export class Marketplace implements UpdateableNetwork {
static contractRoles = ["admin", "lister", "asset"] as const;
public abi: typeof ABI;
public abi: Abi;
private contractWrapper: ContractWrapper<MarketplaceContract>;
private storage: ThirdwebStorage;
@@ -148,7 +148,7 @@ export class Marketplace implements UpdateableNetwork {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<MarketplaceContract>(
network,
@@ -20,7 +20,7 @@ import {
TransactionResult,
TransactionResultWithId,
} from "../../core/types";
import { SDKOptions } from "../../schema";
import { Abi, SDKOptions } from "../../schema";
import { MultiwrapContractSchema } from "../../schema/contracts/multiwrap";
import {
ERC1155Wrappable,
@@ -30,7 +30,6 @@ import {
WrappedTokens,
} from "../../types/multiwrap";
import type { Multiwrap as MultiwrapContract } from "@thirdweb-dev/contracts-js";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/Multiwrap.json";
import {
ITokenBundle,
TokensWrappedEvent,
@@ -61,7 +60,7 @@ export class Multiwrap extends StandardErc721<MultiwrapContract> {
"asset",
] as const;
public abi: typeof ABI;
public abi: Abi;
public encoder: ContractEncoder<MultiwrapContract>;
public estimator: GasCostEstimator<MultiwrapContract>;
public metadata: ContractMetadata<
@@ -102,7 +101,7 @@ export class Multiwrap extends StandardErc721<MultiwrapContract> {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<MultiwrapContract>(
network,
@@ -19,10 +19,10 @@ import type {
TransactionResult,
TransactionResultWithId,
} from "../../core/types";
import { Abi } from "../../schema/contracts/custom";
import { TokenErc721ContractSchema } from "../../schema/contracts/token-erc721";
import { SDKOptions } from "../../schema/sdk-options";
import type { TokenERC721 } from "@thirdweb-dev/contracts-js";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/TokenERC721.json";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { BigNumberish, CallOverrides, constants } from "ethers";
@@ -43,7 +43,7 @@ import { BigNumberish, CallOverrides, constants } from "ethers";
export class NFTCollection extends StandardErc721<TokenERC721> {
static contractRoles = ["admin", "minter", "transfer"] as const;
public abi: typeof ABI;
public abi: Abi;
public metadata: ContractMetadata<
TokenERC721,
typeof TokenErc721ContractSchema
@@ -107,7 +107,7 @@ export class NFTCollection extends StandardErc721<TokenERC721> {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<TokenERC721>(
network,
@@ -27,11 +27,11 @@ import {
TransactionResultWithId,
} from "../../core/types";
import { PaperCheckout } from "../../integrations/thirdweb-checkout";
import { Abi } from "../../schema/contracts/custom";
import { DropErc721ContractSchema } from "../../schema/contracts/drop-erc721";
import { SDKOptions } from "../../schema/sdk-options";
import { PrebuiltNFTDrop } from "../../types/eips";
import { UploadProgressEvent } from "../../types/events";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/DropERC721.json";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
@@ -52,7 +52,7 @@ import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
export class NFTDrop extends StandardErc721<PrebuiltNFTDrop> {
static contractRoles = ["admin", "minter", "transfer"] as const;
public abi: typeof ABI;
public abi: Abi;
public encoder: ContractEncoder<PrebuiltNFTDrop>;
public estimator: GasCostEstimator<PrebuiltNFTDrop>;
public metadata: ContractMetadata<
@@ -161,7 +161,7 @@ export class NFTDrop extends StandardErc721<PrebuiltNFTDrop> {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<PrebuiltNFTDrop>(
network,
@@ -1,5 +1,6 @@
import { QueryAllParams } from "../../../core/schema/QueryParams";
import { NFT } from "../../../core/schema/nft";
import { assertEnabled, detectContractFeature } from "../../common";
import {
fetchCurrencyMetadata,
hasERC20Allowance,
@@ -8,6 +9,7 @@ import {
import { isTokenApprovedForTransfer } from "../../common/marketplace";
import { uploadOrExtractURI } from "../../common/nft";
import { getRoleHash } from "../../common/role";
import { FEATURE_PACK_VRF } from "../../constants/thirdweb-features";
import { ContractEncoder } from "../../core/classes/contract-encoder";
import { ContractEvents } from "../../core/classes/contract-events";
import { ContractInterceptor } from "../../core/classes/contract-interceptor";
@@ -19,10 +21,12 @@ import { ContractWrapper } from "../../core/classes/contract-wrapper";
import { Erc1155 } from "../../core/classes/erc-1155";
import { StandardErc1155 } from "../../core/classes/erc-1155-standard";
import { GasCostEstimator } from "../../core/classes/gas-cost-estimator";
import { PackVRF } from "../../core/classes/pack-vrf";
import {
NetworkOrSignerOrProvider,
TransactionResultWithId,
} from "../../core/types";
import { Abi } from "../../schema";
import { PackContractSchema } from "../../schema/contracts/packs";
import { SDKOptions } from "../../schema/sdk-options";
import {
@@ -32,8 +36,10 @@ import {
PackRewardsOutput,
PackRewardsOutputSchema,
} from "../../schema/tokens/pack";
import type { Pack as PackContract } from "@thirdweb-dev/contracts-js";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/Pack.json";
import type {
IPackVRFDirect,
Pack as PackContract,
} from "@thirdweb-dev/contracts-js";
import { PackUpdatedEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/IPack";
import {
ITokenBundle,
@@ -60,7 +66,7 @@ import { BigNumber, BigNumberish, CallOverrides, ethers } from "ethers";
export class Pack extends StandardErc1155<PackContract> {
static contractRoles = ["admin", "minter", "asset", "transfer"] as const;
public abi: typeof ABI;
public abi: Abi;
public metadata: ContractMetadata<PackContract, typeof PackContractSchema>;
public roles: ContractRoles<PackContract, typeof Pack.contractRoles[number]>;
public encoder: ContractEncoder<PackContract>;
@@ -92,12 +98,21 @@ export class Pack extends StandardErc1155<PackContract> {
public erc1155: Erc1155<PackContract>;
public owner: ContractOwner<PackContract>;
private _vrf?: PackVRF;
/**
* If enabled in the contract, use the Chainlink VRF functionality to open packs
*/
get vrf(): PackVRF {
return assertEnabled(this._vrf, FEATURE_PACK_VRF);
}
constructor(
network: NetworkOrSignerOrProvider,
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<PackContract>(
network,
@@ -131,6 +146,7 @@ export class Pack extends StandardErc1155<PackContract> {
this.events = new ContractEvents(this.contractWrapper);
this.interceptor = new ContractInterceptor(this.contractWrapper);
this.owner = new ContractOwner(this.contractWrapper);
this._vrf = this.detectVrf();
}
/**
@@ -138,6 +154,7 @@ export class Pack extends StandardErc1155<PackContract> {
*/
onNetworkUpdated(network: NetworkOrSignerOrProvider): void {
this.contractWrapper.updateSignerOrProvider(network);
this._vrf?.onNetworkUpdated(network);
}
getAddress(): string {
@@ -536,10 +553,19 @@ export class Pack extends StandardErc1155<PackContract> {
tokenId: BigNumberish,
amount: BigNumberish = 1,
): Promise<PackRewards> {
const receipt = await this.contractWrapper.sendTransaction("openPack", [
tokenId,
amount,
]);
if (this._vrf) {
throw new Error(
"This contract is using Chainlink VRF, use `contract.vrf.open()` or `contract.vrf.openAndClaim()` instead",
);
}
const receipt = await this.contractWrapper.sendTransaction(
"openPack",
[tokenId, amount],
{
// Higher gas limit for opening packs
gasLimit: 500000,
},
);
const event = this.contractWrapper.parseLogs<PackOpenedEvent>(
"PackOpened",
receipt?.logs,
@@ -712,4 +738,19 @@ export class Pack extends StandardErc1155<PackContract> {
): Promise<any> {
return this.contractWrapper.call(functionName, ...args);
}
private detectVrf() {
if (
detectContractFeature<IPackVRFDirect>(this.contractWrapper, "PackVRF")
) {
return new PackVRF(
this.contractWrapper.getSignerOrProvider(),
this.contractWrapper.readContract.address,
this.storage,
this.contractWrapper.options,
this.chainId,
);
}
return undefined;
}
}
@@ -28,11 +28,11 @@ import {
TransactionResultWithId,
} from "../../core/types";
import { PaperCheckout } from "../../integrations/thirdweb-checkout";
import { Abi } from "../../schema/contracts/custom";
import { DropErc721ContractSchema } from "../../schema/contracts/drop-erc721";
import { SDKOptions } from "../../schema/sdk-options";
import { ClaimOptions, UploadProgressEvent } from "../../types";
import type { SignatureDrop as SignatureDropContract } from "@thirdweb-dev/contracts-js";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/SignatureDrop.json";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
@@ -55,7 +55,7 @@ import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
export class SignatureDrop extends StandardErc721<SignatureDropContract> {
static contractRoles = ["admin", "minter", "transfer"] as const;
public abi: typeof ABI;
public abi: Abi;
public erc721: Erc721<SignatureDropContract>;
public owner: ContractOwner<SignatureDropContract>;
public encoder: ContractEncoder<SignatureDropContract>;
@@ -171,7 +171,7 @@ export class SignatureDrop extends StandardErc721<SignatureDropContract> {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<SignatureDropContract>(
network,
@@ -8,6 +8,7 @@ import { ContractWrapper } from "../../core/classes/contract-wrapper";
import { GasCostEstimator } from "../../core/classes/gas-cost-estimator";
import { UpdateableNetwork } from "../../core/interfaces/contract";
import { NetworkOrSignerOrProvider, TransactionResult } from "../../core/types";
import { Abi } from "../../schema/contracts/custom";
import { SplitsContractSchema } from "../../schema/contracts/splits";
import { SDKOptions } from "../../schema/sdk-options";
import { SplitRecipient } from "../../types/SplitRecipient";
@@ -17,7 +18,6 @@ import type {
Split as SplitContract,
} from "@thirdweb-dev/contracts-js";
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/Split.json";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { BigNumber, CallOverrides, Contract } from "ethers";
@@ -41,7 +41,7 @@ export class Split implements UpdateableNetwork {
private contractWrapper: ContractWrapper<SplitContract>;
private storage: ThirdwebStorage;
public abi: typeof ABI;
public abi: Abi;
public metadata: ContractMetadata<SplitContract, typeof SplitsContractSchema>;
public encoder: ContractEncoder<SplitContract>;
public estimator: GasCostEstimator<SplitContract>;
@@ -65,7 +65,7 @@ export class Split implements UpdateableNetwork {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<SplitContract>(
network,
@@ -11,11 +11,11 @@ import { DropClaimConditions } from "../../core/classes/drop-claim-conditions";
import { StandardErc20 } from "../../core/classes/erc-20-standard";
import { GasCostEstimator } from "../../core/classes/gas-cost-estimator";
import { NetworkOrSignerOrProvider, TransactionResult } from "../../core/types";
import { Abi } from "../../schema/contracts/custom";
import { DropErc20ContractSchema } from "../../schema/contracts/drop-erc20";
import { SDKOptions } from "../../schema/sdk-options";
import { Amount, CurrencyValue } from "../../types";
import { PrebuiltTokenDrop } from "../../types/eips";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/DropERC20.json";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { CallOverrides, constants } from "ethers";
@@ -35,7 +35,7 @@ import { CallOverrides, constants } from "ethers";
export class TokenDrop extends StandardErc20<PrebuiltTokenDrop> {
static contractRoles = ["admin", "transfer"] as const;
public abi: typeof ABI;
public abi: Abi;
public metadata: ContractMetadata<
PrebuiltTokenDrop,
typeof DropErc20ContractSchema
@@ -82,7 +82,7 @@ export class TokenDrop extends StandardErc20<PrebuiltTokenDrop> {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<PrebuiltTokenDrop>(
network,
@@ -12,12 +12,12 @@ import { Erc20SignatureMintable } from "../../core/classes/erc-20-signature-mint
import { StandardErc20 } from "../../core/classes/erc-20-standard";
import { GasCostEstimator } from "../../core/classes/gas-cost-estimator";
import { NetworkOrSignerOrProvider, TransactionResult } from "../../core/types";
import { Abi } from "../../schema/contracts/custom";
import { TokenErc20ContractSchema } from "../../schema/contracts/token-erc20";
import { SDKOptions } from "../../schema/sdk-options";
import { TokenMintInput } from "../../schema/tokens/token";
import { Amount, CurrencyValue } from "../../types";
import type { TokenERC20 } from "@thirdweb-dev/contracts-js";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/TokenERC20.json";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { CallOverrides, constants } from "ethers";
@@ -38,7 +38,7 @@ import { CallOverrides, constants } from "ethers";
export class Token extends StandardErc20<TokenERC20> {
static contractRoles = ["admin", "minter", "transfer"] as const;
public abi: typeof ABI;
public abi: Abi;
public metadata: ContractMetadata<
TokenERC20,
typeof TokenErc20ContractSchema
@@ -74,7 +74,7 @@ export class Token extends StandardErc20<TokenERC20> {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<TokenERC20>(
network,
@@ -15,6 +15,7 @@ import {
TransactionResultWithId,
} from "../../core/types";
import { VoteType } from "../../enums";
import { Abi } from "../../schema";
import { VoteContractSchema } from "../../schema/contracts/vote";
import { SDKOptions } from "../../schema/sdk-options";
import { CurrencyValue } from "../../types/currency";
@@ -26,7 +27,6 @@ import {
} from "../../types/vote";
import type { IERC20, VoteERC20 } from "@thirdweb-dev/contracts-js";
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/VoteERC20.json";
import { ProposalCreatedEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/VoteERC20";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import {
@@ -55,7 +55,7 @@ export class Vote implements UpdateableNetwork {
private contractWrapper: ContractWrapper<VoteERC20>;
private storage: ThirdwebStorage;
public abi: typeof ABI;
public abi: Abi;
public metadata: ContractMetadata<VoteERC20, typeof VoteContractSchema>;
public encoder: ContractEncoder<VoteERC20>;
public estimator: GasCostEstimator<VoteERC20>;
@@ -75,7 +75,7 @@ export class Vote implements UpdateableNetwork {
address: string,
storage: ThirdwebStorage,
options: SDKOptions = {},
abi: typeof ABI,
abi: Abi,
chainId: number,
contractWrapper = new ContractWrapper<VoteERC20>(
network,
@@ -4,7 +4,7 @@ import {
fetchExtendedReleaseMetadata,
fetchPreDeployMetadata,
} from "../../common/index";
import { ChainId } from "../../constants";
import { ChainId, EventType } from "../../constants";
import { getContractAddressByChainId } from "../../constants/addresses";
import {
EditionDropInitializer,
@@ -24,6 +24,7 @@ import {
} from "../../contracts";
import { FactoryDeploymentSchema } from "../../schema/contracts/custom";
import { SDKOptions } from "../../schema/sdk-options";
import { DeployEvent, DeployEvents } from "../../types";
import {
MarketplaceContractDeployMetadata,
MultiwrapContractDeployMetadata,
@@ -39,7 +40,6 @@ import {
PrebuiltContractType,
} from "../types";
import { ContractFactory } from "./factory";
import { FactoryEvents } from "./factory-events";
import { ContractRegistry } from "./registry";
import { RPCConnectionHandler } from "./rpc-connection-handler";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
@@ -50,6 +50,7 @@ import {
ContractInterface,
ethers,
} from "ethers";
import { EventEmitter } from "eventemitter3";
import invariant from "tiny-invariant";
import { z } from "zod";
@@ -68,8 +69,16 @@ export class ContractDeployer extends RPCConnectionHandler {
* should never be accessed directly, use {@link ContractDeployer.getRegistry} instead
*/
private _registry: Promise<ContractRegistry> | undefined;
public events: FactoryEvents | undefined;
private storage: ThirdwebStorage;
private events: EventEmitter<DeployEvents>;
private transactionListener = (event: any) => {
if (event.status === "submitted") {
this.events.emit("contractDeployed", {
status: "submitted",
transactionHash: event.transactionHash,
});
}
};
constructor(
network: NetworkOrSignerOrProvider,
@@ -78,7 +87,7 @@ export class ContractDeployer extends RPCConnectionHandler {
) {
super(network, options);
this.storage = storage;
this.events = new EventEmitter();
// Initialize factory and registry (we don't need to make these calls async)
this.getFactory();
this.getRegistry();
@@ -427,7 +436,15 @@ export class ContractDeployer extends RPCConnectionHandler {
} catch (e) {
parsedVersion = undefined;
}
return await factory.deploy(contractType, parsedMetadata, parsedVersion);
factory.on(EventType.Transaction, this.transactionListener);
const deployedAddress = await factory.deploy(
contractType,
parsedMetadata,
this.events,
parsedVersion,
);
factory.off(EventType.Transaction, this.transactionListener);
return deployedAddress;
}
//
@@ -515,14 +532,18 @@ export class ContractDeployer extends RPCConnectionHandler {
factoryAddress,
this.getSignerOrProvider(),
this.storage,
{},
this.options,
);
return await proxyFactory.deployProxyByImplementation(
proxyFactory.on(EventType.Transaction, this.transactionListener);
const deployedAddress = await proxyFactory.deployProxyByImplementation(
implementationAddress,
implementationAbi,
initializerFunction,
initializerArgs,
this.events,
);
proxyFactory.off(EventType.Transaction, this.transactionListener);
return deployedAddress;
}
/**
@@ -602,8 +623,6 @@ export class ContractDeployer extends RPCConnectionHandler {
this.storage,
this.options,
);
this.events = new FactoryEvents(factory);
return factory;
}));
}
@@ -800,8 +819,39 @@ export class ContractDeployer extends RPCConnectionHandler {
const deployer = await new ethers.ContractFactory(abi, bytecode)
.connect(signer)
.deploy(...constructorParams);
this.events.emit("contractDeployed", {
status: "submitted",
transactionHash: deployer.deployTransaction.hash,
});
const deployedContract = await deployer.deployed();
// TODO parse transaction receipt
this.events.emit("contractDeployed", {
status: "completed",
contractAddress: deployedContract.address,
transactionHash: deployedContract.deployTransaction.hash,
});
return deployedContract.address;
}
/**
* Listen to all deploy transactions from this deployer
* @param listener the listener to add
*/
public addDeployListener(listener: (event: DeployEvent) => void) {
this.events.on("contractDeployed", listener);
}
/**
* Remove a deploy listener
* @param listener the listener to remove
*/
public removeDeployListener(listener: (event: DeployEvent) => void) {
this.events.off("contractDeployed", listener);
}
/**
* Remove all deploy listeners
*/
public removeAllDeployListeners() {
this.events.removeAllListeners("contractDeployed");
}
}
@@ -3,7 +3,7 @@ import { ContractEvent, EventQueryOptions } from "../../types/index";
import { ContractWrapper } from "./contract-wrapper";
import { EventFragment } from "@ethersproject/abi";
import { BaseContract, Event, providers } from "ethers";
import { ListenerFn } from "eventemitter3";
import type { EventEmitter } from "eventemitter3";
/**
* Listen to Contract events in real time
@@ -28,7 +28,7 @@ export class ContractEvents<TContract extends BaseContract> {
* @param listener - the callback function that will be called on every transaction
* @public
*/
public addTransactionListener(listener: ListenerFn) {
public addTransactionListener(listener: EventEmitter.ListenerFn) {
this.contractWrapper.addListener(EventType.Transaction, listener);
}
@@ -44,7 +44,7 @@ export class ContractEvents<TContract extends BaseContract> {
* @param listener - the callback function to remove
* @public
*/
public removeTransactionListener(listener: ListenerFn) {
public removeTransactionListener(listener: EventEmitter.ListenerFn) {
this.contractWrapper.off(EventType.Transaction, listener);
}
@@ -85,7 +85,11 @@ export class ContractEvents<TContract extends BaseContract> {
const parsedLog =
this.contractWrapper.readContract.interface.parseLog(log);
listener(
this.toContractEvent(parsedLog.eventFragment, parsedLog.args, log),
this.toContractEvent<TEvent>(
parsedLog.eventFragment,
parsedLog.args,
log,
),
);
};
@@ -333,15 +337,31 @@ export class ContractEvents<TContract extends BaseContract> {
const results: Record<string, any> = {};
event.inputs.forEach((param, index) => {
if (Array.isArray(args[index])) {
const obj: Record<string, unknown> = {};
const components = param.components;
if (components) {
const arr = args[index];
for (let i = 0; i < components.length; i++) {
const name = components[i].name;
obj[name] = arr[i];
if (param.type === "tuple[]") {
// tuple[]
const objArray: Record<string, unknown>[] = [];
for (let i = 0; i < arr.length; i++) {
const tuple = arr[i];
const obj: Record<string, unknown> = {};
for (let j = 0; j < components.length; j++) {
const name = components[j].name;
obj[name] = tuple[j];
}
objArray.push(obj);
}
results[param.name] = objArray;
} else {
// simple tuple
const obj: Record<string, unknown> = {};
for (let i = 0; i < components.length; i++) {
const name = components[i].name;
obj[name] = arr[i];
}
results[param.name] = obj;
}
results[param.name] = obj;
}
} else {
results[param.name] = args[index];
@@ -1,8 +1,8 @@
import {
detectContractFeature,
ExtensionNotImplementedError,
fetchContractMetadataFromAddress,
hasFunction,
fetchContractMetadataFromAddress,
} from "../../common";
import { FEATURE_METADATA } from "../../constants/thirdweb-features";
import { DetectableFeature } from "../interfaces/DetectableFeature";
@@ -7,7 +7,7 @@ import {
fetchRawPredeployMetadata,
fetchSourceFilesFromMetadata,
resolveContractUriFromAddress,
} from "../../common/feature-detection";
} from "../../common";
import { isIncrementalVersion } from "../../common/version-checker";
import { getContractPublisherAddress } from "../../constants";
import {
@@ -1,4 +1,4 @@
import { hasFunction } from "../../common";
import { detectContractFeature } from "../../common";
import { normalizePriceValue, setErc20Allowance } from "../../common/currency";
import { uploadOrExtractURIs } from "../../common/nft";
import { FEATURE_NFT_SIGNATURE_MINTABLE_V2 } from "../../constants/erc721-features";
@@ -22,7 +22,7 @@ import type {
} from "@thirdweb-dev/contracts-js";
import { TokensMintedWithSignatureEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/SignatureDrop";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { BigNumber, ethers } from "ethers";
import { BigNumber } from "ethers";
import invariant from "tiny-invariant";
/**
@@ -397,17 +397,9 @@ export class Erc721WithQuantitySignatureMintable implements DetectableFeature {
}
private async isLegacyNFTContract() {
if (hasFunction<TokenERC721>("contractType", this.contractWrapper)) {
try {
const contractType = ethers.utils.toUtf8String(
await this.contractWrapper.readContract.contractType(),
);
return contractType.includes("TokenERC721");
} catch (e) {
return false;
}
} else {
return false;
}
return detectContractFeature<ISignatureMintERC721>(
this.contractWrapper,
"ERC721SignatureMintV1",
);
}
}
@@ -1,38 +0,0 @@
import { ContractEvents } from "./contract-events";
import { ContractWrapper } from "./contract-wrapper";
import type { TWFactory } from "@thirdweb-dev/contracts-js";
import { ProxyDeployedEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/TWFactory";
interface DeployEvent {
transactionHash: string;
contractAddress: string;
}
export class FactoryEvents extends ContractEvents<TWFactory> {
constructor(contractWrapper: ContractWrapper<TWFactory>) {
super(contractWrapper);
}
public addDeployListener(listener: (event: DeployEvent) => void) {
this.addTransactionListener(async (event) => {
if (!event.transactionHash) {
return;
}
const receipt = await this.contractWrapper
.getProvider()
.getTransactionReceipt(event.transactionHash);
const events = this.contractWrapper.parseLogs<ProxyDeployedEvent>(
"ProxyDeployed",
receipt.logs,
);
if (events.length > 0) {
listener({
...event,
contractAddress: events[0].args.proxy,
});
}
});
}
}

Some files were not shown because too many files have changed in this diff Show More