Compare commits

...
Author SHA1 Message Date
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
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
a20be881e3 Version Packages (#406)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-11-29 12:09:38 +13:00
Joaquim VergesandGitHub 47f8945325 [SDK] improve error parsing (#414) 2022-11-29 11:45:33 +13:00
Furqan RydhanandGitHub 1b0bf99da7 Improvements to the App Deploy Flow (#413) 2022-11-28 14:23:44 -08:00
f03be398e0 [SDK] Update signTypedData domain to match contract (#412)
Co-authored-by: Joaquim Verges <[email protected]>
2022-11-28 03:00:50 +00:00
27996cb4bc [CLI] - feat: add solana support to cli (#403)
Co-authored-by: Jarrod Watts <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2022-11-24 01:01:00 +00:00
2eaa67acbe [CLI+SDK] app-uri (#283)
Co-authored-by: Furqan Rydhan <[email protected]>
Co-authored-by: Jonas Daniels <[email protected]>
2022-11-23 09:17:29 +00:00
Jonas Daniels aafd7968df bring the registry-url back apparently it was important 2022-11-23 01:05:43 -08:00
Jonas DanielsandGitHub 48797c7cf0 [SDK] - add gasless feature detection (#408) 2022-11-23 00:53:59 -08:00
Jonas DanielsandGitHub 4edcb37100 update prettier & format (#407) 2022-11-23 06:41:39 +00:00
83dcaf7058 Expose sdk.fromWallet and wallet classes (#402)
Co-authored-by: Jonas Daniels <[email protected]>
2022-11-22 18:15:28 -05:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
b4e005be7f Version Packages (#401)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-11-22 14:31:57 -08:00
Nacho IacovinoandGitHub ccb7db4873 [Solana + React] Update hooks for creators/royalties (#405) 2022-11-22 19:22:51 +00:00
Jonas DanielsandGitHub 9151aa7dc8 [SDK] - expose getDefaultTrustedForwarders helper fn (#404) 2022-11-22 03:35:01 +00:00
5a01c537e3 [DO NOT MERGE] Update to Metaplex v0.17 (#305)
Co-authored-by: Jonas Daniels <[email protected]>
2022-11-21 16:14:39 -08:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
f09c153ff7 Version Packages (#391)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-11-21 15:22:56 -08:00
Nacho IacovinoandGitHub 15431621fd [React] Remove console.log (#400) 2022-11-21 20:03:32 +00:00
Jonas DanielsandGitHub 887af24450 [SDK] - fix error handling for nullish error values (#399) 2022-11-21 18:52:02 +00:00
Jonas DanielsandGitHub 15514f190a [SDK] - add default value option to constructorParams schema (#398) 2022-11-21 18:28:18 +00:00
Adam MajmudarandGitHub 72589ec234 Call user callback in getUser (#397) 2022-11-21 17:46:18 +00:00
Jonas DanielsandGitHub f8bceec10c fix solana claim condition native token (#395) 2022-11-19 05:36:42 +00:00
Adam MajmudarandGitHub 7c0744a006 Add support for total supply and pagination on get all (#388) 2022-11-18 02:21:32 +00:00
Nacho IacovinoandGitHub 846022e2cf [React] Fix unlimited price (#392) 2022-11-17 22:25:25 +00:00
Joaquim VergesandGitHub 96bd92e724 [SDK] Expose getAllDetectedFeatures(ABI) helper function (#390) 2022-11-17 14:07:37 -08:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
c2b6d977ed Version Packages (#383)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-11-16 14:02:50 -08:00
7cb8e59be4 [SDK] Add new Drop contract implementation addresses (#364)
Co-authored-by: Jonas Daniels <[email protected]>
Co-authored-by: Adam Majmudar <[email protected]>
2022-11-16 21:52:01 +00:00
Adam MajmudarandGitHub 04a47e8971 Add retroactive creator and royalty update option (#385) 2022-11-16 21:37:45 +00:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
8a6a97a3e9 Bump loader-utils from 2.0.3 to 2.0.4 (#384)
Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-11-16 19:51:40 +00:00
Jonas DanielsandGitHub 612bcdd16f [REACT] - update gnosis connector (#386) 2022-11-16 19:34:27 +00:00
Jonas DanielsandGitHub 0ed77d2c9e [SDK] - add constructorParams to schema for better release -> deploy (#382) 2022-11-15 20:47:54 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
7129aef6e1 Version Packages (#370)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-11-11 08:51:19 -08:00
Joaquim VergesandGitHub f50b74819d [SDK] make isConnected sync, remove useless fn (#381) 2022-11-11 06:14:24 +00:00
Joaquim VergesandGitHub 3eba69afd7 [SDK] expose signer's chain id via sdk.wallet (#380) 2022-11-11 00:42:05 +00:00
Jarrod WattsandGitHub 98c2253e8f [SDK] Docs - Add await before sdk.getContract snippets (#379) 2022-11-10 16:08:31 -08:00
32d91ef709 [REACT] Fix Border Radius for Safari (#378)
Co-authored-by: Jarrod Watts <[email protected]>
2022-11-10 09:53:17 -08:00
Adam MajmudarandGitHub b79dc18f7a Add event filtering on topics (#377) 2022-11-09 11:51:13 -05:00
Adam MajmudarandGitHub 4af785c37c Add TokensClaimed event to tiered-drop (#376) 2022-11-08 20:34:45 +00:00
Adam MajmudarandGitHub 6f818f393e Updated tiered-drop contract (#373) 2022-11-03 17:03:00 -07:00
Adam MajmudarandGitHub 97ed4779a9 Update nft drop claimTo documentation (#372) 2022-11-03 22:42:42 +00:00
Nacho IacovinoandGitHub 2d3fca5237 [React] Add useClaimerProofs hook (#369) 2022-11-03 01:17:15 +01:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
7016019f2a Version Packages (#366)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-11-02 15:16:25 -07:00
Joaquim VergesandGitHub 4e7b293c54 [SDK] Fix handling of old allowlist proof format (#368) 2022-11-02 14:11:13 -07:00
Jonas DanielsandGitHub c9c0e4ff39 [SDK] - make EVM side react native compatible (#365) 2022-11-02 05:38:56 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
06c24c153a Version Packages (#361)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-11-01 16:13:47 -07:00
aa6d9ed75d [SDK] Support new Drop claim conditions mechanics (#333)
Co-authored-by: adam-maj <[email protected]>
Co-authored-by: Adam Majmudar <[email protected]>
2022-11-01 23:07:10 +00:00
Joaquim VergesandGitHub 42a606588d [SDK] Fix fetching NFTs with numbers as ids (#362) 2022-11-01 22:01:01 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
2820761003 Version Packages (#360)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-11-01 13:49:34 -07:00
Adam MajmudarandGitHub 5200d5d7e7 Add support for TieredDrop in extensions (#329) 2022-11-01 13:48:48 -07:00
Joaquim VergesandGitHub e731c1a7c3 [SDK] Allow fetching claimerProofs from any claim condition (#359) 2022-10-31 23:26:27 +00:00
277 changed files with 20362 additions and 6546 deletions
+1 -1
View File
@@ -13,6 +13,6 @@ runs:
- name: Install dependencies
shell: bash
run: yarn install
run: yarn install --frozen-lockfile
env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
+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
+2 -1
View File
@@ -16,4 +16,5 @@ public/dist
.yalc/
yalc.lock
build/
playwright-report/
playwright-report/
.vscode/
-1
View File
@@ -28,7 +28,6 @@
| [/storage](./packages/storage) | Best in class decentralized storage SDK for Browser and Node | <a href="https://www.npmjs.com/package/@thirdweb-dev/storage"><img src="https://img.shields.io/npm/v/@thirdweb-dev/storage?color=red&label=npm&logo=npm" alt="npm version"/></a> |
| [/cli](./packages/cli) | Publish and deploy smart contracts without dealing with private keys | <a href="https://www.npmjs.com/package/thirdweb"><img src="https://img.shields.io/npm/v/thirdweb?color=red&label=npm&logo=npm" alt="npm version"/></a> |
## Documentation
Visit [https://portal.thirdweb.com/](https://portal.thirdweb.com/) to view the full documentation.
+4 -4
View File
@@ -15,8 +15,8 @@
"scripts": {
"test": "turbo run test test:evm test:solana",
"e2e": "turbo run e2e",
"build": "turbo run build",
"build:release": "turbo run build --force",
"build": "turbo run build --filter=./packages/*",
"build:release": "turbo run build --force --filter=./packages/*",
"dev": "turbo run dev --no-cache --parallel --continue",
"fix:repo": "manypkg fix",
"lint": "turbo run lint",
@@ -28,7 +28,7 @@
"release": "node ./scripts/pre-release.mjs && changeset publish",
"version-packages:nightly": "changeset version --snapshot nightly",
"release:nightly": "node ./scripts/pre-release.mjs && changeset publish --tag nightly",
"push": "turbo run push"
"push": "turbo run push --filter=./packages/*"
},
"packageManager": "[email protected]",
"dependencies": {
@@ -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",
+36
View File
@@ -1,5 +1,41 @@
# @thirdweb-dev/auth
## 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
## 2.0.31
### Patch Changes
- [#397](https://github.com/thirdweb-dev/js/pull/397) [`72589ec`](https://github.com/thirdweb-dev/js/commit/72589ec234d86939b67b0ca8b3b789f2e9c54cc2) Thanks [@adam-maj](https://github.com/adam-maj)! - Call user callback in getUser
## 2.0.30
## 2.0.29
## 2.0.28
## 2.0.27
## 2.0.26
## 2.0.25
## 2.0.24
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "2.0.25",
"version": "2.0.39",
"exports": {
"./next": {
"module": "./next/dist/thirdweb-dev-auth-next.esm.js",
@@ -73,7 +73,7 @@
"eslint-plugin-inclusive-language": "^2.2.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-tsdoc": "^0.2.16",
"ethers": "^5.7.1",
"ethers": "^5.7.2",
"express": "^4.18.1",
"next": "^12.2.0",
"next-auth": "^4.10.3",
@@ -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;
}
+7 -1
View File
@@ -70,7 +70,13 @@ export function ThirdwebAuth(cfg: ThirdwebAuthConfig) {
if (token) {
try {
const address = await sdk.auth.authenticate(domain, token);
user = { address };
let data = {};
if (ctx.callbacks?.user) {
data = await ctx.callbacks.user(address);
}
user = { ...data, address };
} catch {
// No-op
}
+1 -1
View File
@@ -47,7 +47,7 @@ export default async function handler(
path: "/",
httpOnly: true,
secure: true,
sameSite: "strict",
sameSite: "none",
}),
);
+7 -1
View File
@@ -70,7 +70,13 @@ export function ThirdwebAuth(cfg: ThirdwebAuthConfig) {
if (token) {
try {
const address = await sdk.auth.authenticate(domain, token);
user = { address };
let data = {};
if (ctx.callbacks?.user) {
data = await ctx.callbacks.user(address);
}
user = { ...data, address };
} catch {
// No-op
}
@@ -47,7 +47,7 @@ export default async function handler(
path: "/",
httpOnly: true,
secure: true,
sameSite: "strict",
sameSite: "none",
}),
);
+136
View File
@@ -1,5 +1,141 @@
# thirdweb
## 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
- [#403](https://github.com/thirdweb-dev/js/pull/403) [`27996cb`](https://github.com/thirdweb-dev/js/commit/27996cb4bc6f054f45b0a66b0a3aca732e0ef610) Thanks [@avneesh0612](https://github.com/avneesh0612)! - Add CLI Support for solana with --solana flag on create command
- [#283](https://github.com/thirdweb-dev/js/pull/283) [`2eaa67a`](https://github.com/thirdweb-dev/js/commit/2eaa67acbe21464e7715d0b696afdc024460a44d) Thanks [@adam-maj](https://github.com/adam-maj)! - add capability to deploy apps
### Patch Changes
- [#413](https://github.com/thirdweb-dev/js/pull/413) [`1b0bf99`](https://github.com/thirdweb-dev/js/commit/1b0bf99da796df88ff307dd004cdaf239fb2b1ba) Thanks [@furqanrydhan](https://github.com/furqanrydhan)! - small interface tweaks
- Updated dependencies [[`48797c7`](https://github.com/thirdweb-dev/js/commit/48797c7cf0695965e33eb6bf602be4652f7085a8), [`83dcaf7`](https://github.com/thirdweb-dev/js/commit/83dcaf70584af8c5cdf0427f9fc1ba82d89f0887), [`f03be39`](https://github.com/thirdweb-dev/js/commit/f03be398e0d7b75c9c5b4fb643f35903e89a17e7), [`2eaa67a`](https://github.com/thirdweb-dev/js/commit/2eaa67acbe21464e7715d0b696afdc024460a44d), [`47f8945`](https://github.com/thirdweb-dev/js/commit/47f8945325447874b1ace0359919c1d54fd55436)]:
- @thirdweb-dev/sdk@3.6.3
## 0.8.18
### Patch Changes
- Updated dependencies [[`ccb7db4`](https://github.com/thirdweb-dev/js/commit/ccb7db48739b8dddcb2c032b3b6e3e5200485715), [`9151aa7`](https://github.com/thirdweb-dev/js/commit/9151aa7dc80754a7aa4fd3f6ce0207bccbb6451f), [`5a01c53`](https://github.com/thirdweb-dev/js/commit/5a01c537e30bd7ef562aad1012413990de6faedf)]:
- @thirdweb-dev/sdk@3.6.2
## 0.8.17
### Patch Changes
- Updated dependencies [[`15514f1`](https://github.com/thirdweb-dev/js/commit/15514f190a844d809ae5b1edb580aab46a682485), [`7c0744a`](https://github.com/thirdweb-dev/js/commit/7c0744a006e78987ad8b271b2c64f4bac7759510), [`f8bceec`](https://github.com/thirdweb-dev/js/commit/f8bceec10c60b30dc3d6f45926e2a9e018202578), [`887af24`](https://github.com/thirdweb-dev/js/commit/887af24450e316c2ea390cd49c0563cebe793c0f), [`96bd92e`](https://github.com/thirdweb-dev/js/commit/96bd92e724ec7d880d23348071b26ab8c21dd868)]:
- @thirdweb-dev/sdk@3.6.1
## 0.8.16
### Patch Changes
- Updated dependencies [[`7cb8e59`](https://github.com/thirdweb-dev/js/commit/7cb8e59be48dc923316eb36ab43a1bef7364f6b1), [`0ed77d2`](https://github.com/thirdweb-dev/js/commit/0ed77d2c9e7526444ef660aab82a950865234aa6), [`04a47e8`](https://github.com/thirdweb-dev/js/commit/04a47e8971d28da2532ebd9db824eeb459c17bd4)]:
- @thirdweb-dev/sdk@3.6.0
## 0.8.15
### Patch Changes
- Updated dependencies [[`3eba69a`](https://github.com/thirdweb-dev/js/commit/3eba69afd78b7aa472a9c00c9d4220bb69ad1d3e), [`4af785c`](https://github.com/thirdweb-dev/js/commit/4af785c37c831ecd7087c1c9eb9095922cac0855), [`6f818f3`](https://github.com/thirdweb-dev/js/commit/6f818f393eb9023b53a3358d62d60ec23a9246bd), [`b79dc18`](https://github.com/thirdweb-dev/js/commit/b79dc18f7ab5155bbf4af02dc1a953546160bad0)]:
- @thirdweb-dev/sdk@3.5.2
## 0.8.14
### Patch Changes
- Updated dependencies [[`4e7b293`](https://github.com/thirdweb-dev/js/commit/4e7b293c543244de79c150ca8c37d941221fc9a3), [`c9c0e4f`](https://github.com/thirdweb-dev/js/commit/c9c0e4ff39b054af746f3aec75fcbd0a3ef7239d)]:
- @thirdweb-dev/sdk@3.5.1
## 0.8.13
### Patch Changes
- Updated dependencies [[`5200d5d`](https://github.com/thirdweb-dev/js/commit/5200d5d7e730da58bd4d3e7c222e3c661265f913), [`42a6065`](https://github.com/thirdweb-dev/js/commit/42a606588dfed03c67c57357dd0ee1ad19fad6ea)]:
- @thirdweb-dev/sdk@3.5.0
## 0.8.12
### Patch Changes
- Updated dependencies [[`e731c1a`](https://github.com/thirdweb-dev/js/commit/e731c1a7c341e6f2b9cc42c88d5c1b036dcf4a7c)]:
- @thirdweb-dev/sdk@3.4.5
## 0.8.11
### Patch 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.
---
+3 -1
View File
@@ -1,6 +1,8 @@
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?",
contract: "What type of contract do you want to start from?",
@@ -9,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",
};
+3 -1
View File
@@ -2,7 +2,7 @@ import { CREATE_MESSAGES } from "../constants/constants";
import { prepareEnvironment } from "@gmrchk/cli-testing-library";
// this creates an app, can take some time that's fine
jest.setTimeout(120_000);
jest.setTimeout(150_000);
describe("npx thirdweb create", () => {
it("should create app (CRA) successfully", async () => {
@@ -16,6 +16,8 @@ describe("npx thirdweb create", () => {
await pressKey("enter");
await waitForText(CREATE_MESSAGES.projectName);
await pressKey("enter");
await waitForText(CREATE_MESSAGES.chain);
await pressKey("enter");
await waitForText(CREATE_MESSAGES.framework);
// select CRA
await pressKey("arrowDown");
+3 -3
View File
@@ -15,8 +15,8 @@ describe("npx thirdweb deploy", () => {
`${path}/BasicContract.sol`,
);
const { waitForText, waitForFinish, getExitCode, writeText, getStdout } =
await spawn("node", "./dist/cli/index.js deploy");
const { waitForText, waitForFinish, getExitCode, writeText, getStderr } =
await spawn("node", "./dist/cli/index.js deploy --contract");
expect(await exists("BasicContract.sol")).toEqual(true);
@@ -26,7 +26,7 @@ describe("npx thirdweb deploy", () => {
// wait for program to finish
await waitForFinish();
expect(getStdout().at(-1)).toContain(
expect(getStderr().at(-1)).toContain(
"https://thirdweb.com/contracts/deploy/",
);
+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");
+2 -2
View File
@@ -15,7 +15,7 @@ describe("npx thirdweb release", () => {
`${path}/BasicContract.sol`,
);
const { waitForText, waitForFinish, getExitCode, writeText, getStdout } =
const { waitForText, waitForFinish, getExitCode, writeText, getStderr } =
await spawn("node", "./dist/cli/index.js release");
expect(await exists("BasicContract.sol")).toEqual(true);
@@ -26,7 +26,7 @@ describe("npx thirdweb release", () => {
// wait for program to finish
await waitForFinish();
expect(getStdout().at(-1)).toContain(
expect(getStderr().at(-1)).toContain(
"https://thirdweb.com/contracts/release/",
);
+8 -7
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.8.11",
"version": "0.9.8",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -10,7 +10,7 @@
},
"devDependencies": {
"@gmrchk/cli-testing-library": "^0.1.2",
"@types/async-retry": "1.3.0",
"@types/async-retry": "^1.3.0",
"@types/cross-spawn": "^6.0.2",
"@types/inquirer": "^8.2.1",
"@types/jest": "^29.0.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,14 +32,15 @@
"@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.0",
"ethers": "^5.7.2",
"got": "11.8.5",
"inquirer": "^8.2.3",
"open": "^8.4.0",
"prompts": "^2.4.2",
"rimraf": "^3.0.2",
"solc": "0.8.13",
"solc": "0.8.17",
"tar": "^6.1.11",
"tslog": "^3.3.3",
"update-notifier": "^6.0.2",
+229 -68
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 generateDashboardUrl from "../helpers/generate-dashboard-url";
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")
@@ -40,34 +40,40 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
.version(cliVersion, "-v, --version");
program
.command("create [projectPath]")
.command("create [projectType] [projectPath]")
.description(
"Create a web3 app from any of our official templates: https://github.com/thirdweb-example/",
)
.option("--app", `Create a web3 app.`)
.option("--contract", `Create a web3 contract project`)
.option("--ts, --typescript", `Initialize as a TypeScript project.`)
.option("--js, --javascript", `Initialize as a JavaScript project.`)
.option("--forge", `Initialize as a Forge project.`)
.option("--hardhat", `Initialize as a Hardhat project.`)
.option("--cra", `Initialize as a Create React App project.`)
.option("--next", `Initialize as a Next.js project.`)
.option("--vite", `Initialize as a Vite project.`)
.option("--app", "Create a web3 app.")
.option("--contract", "Create a web3 contract project")
.option("--ts, --typescript", "Initialize as a TypeScript project.")
.option("--js, --javascript", "Initialize as a JavaScript project.")
.option("--forge", "Initialize as a Forge project.")
.option("--hardhat", "Initialize as a Hardhat project.")
.option("--cra", "Initialize as a Create React App project.")
.option("--next", "Initialize as a Next.js project.")
.option("--vite", "Initialize as a Vite project.")
.option(
"--use-npm",
`Explicitly tell the CLI to bootstrap the app using npm`,
"Explicitly tell the CLI to bootstrap the app using npm",
)
.option(
"--use-pnpm",
`Explicitly tell the CLI to bootstrap the app using pnpm`,
"Explicitly tell the CLI to bootstrap the app using pnpm",
)
.option("--framework [name]", `The preferred framework.`)
.option("--framework [name]", "The preferred framework.")
.option("--solana", "Initialize as a Solana project.")
.option("--evm", "Initialize as an Ethereum project.")
.option(
"-t, --template [name]",
`A template to start your project from. You can use an template repository name from the official thirdweb-example org.`,
"A template to start your project from. You can use an template repository name from the official thirdweb-example org.",
)
.action(async (path, options) => {
await twCreate(path, options);
.option(
"-c, --contract-name [name]",
"Name of the new smart contract to create",
)
.action(async (type, path, options) => {
await twCreate(type, path, options);
});
program
@@ -87,39 +93,33 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
.option("--dry-run", "dry run (skip actually publishing)")
.option("-d, --debug", "show debug logs")
.option("--ci", "Continuous Integration mode")
.option(
"--dist-path [distPath]",
"Path to the dist folder where the HTML based App is",
)
.option(
"-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",
)
.option("--app", "Deploy a web app to decentralized storage")
.option("--contract", "Deploy a smart contract to blockchains")
.action(async (options) => {
if (options.name) {
const url = generateDashboardUrl(options.name, options.contractVersion);
if (!url) {
logger.error(
chalk.red(
`Could not find a contract named ${options.name} ${
options.contractVersion || ""
}`,
),
);
return;
}
info(`Open this link to deploy your contract:`);
logger.info(chalk.blueBright(url));
open(url.toString());
return;
const url = await deploy(options);
if (url) {
open(url);
}
const url = await processProject(options, "deploy");
info(`Open this link to deploy your contracts:`);
logger.info(chalk.blueBright(url.toString()));
open(url.toString());
});
program
@@ -128,13 +128,24 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
"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")
.action(async (options) => {
const url = await processProject(options, "release");
info(`Open this link to release your contracts:`);
logger.info(chalk.blueBright(url.toString()));
info(
`Open this link to release your contracts: ${chalk.blueBright(
url.toString(),
)}`,
);
open(url.toString());
});
@@ -144,13 +155,35 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
.argument("[upload]", "path to file or directory to upload")
.action(async (path) => {
const storage = new ThirdwebStorage();
const uri = await upload(storage, path);
info(`Files stored at the following IPFS URI:`);
logger.info(chalk.blueBright(uri.toString()));
try {
const uri = await upload(storage, path);
info(
`Files stored at the following IPFS URI: ${chalk.blueBright(
uri.toString(),
)}`,
);
const url = storage.resolveScheme(uri);
info(`Open this link to view your upload:`);
logger.info(chalk.blueBright(url.toString()));
const url = storage.resolveScheme(uri);
info(
`Open this link to view your upload: ${chalk.blueBright(
url.toString(),
)}`,
);
} catch (err: any) {
if (
err.toString() === "No files detected in specified directory" ||
err.toString() === "Invalid path provided" ||
err.toString() === "No path provided"
) {
logger.error(
chalk.redBright(
"Please specify a valid file or directory to upload",
),
);
} else {
logger.error(chalk.redBright("Failed to upload files"), err);
}
}
});
program
@@ -165,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) {
+11
View File
@@ -0,0 +1,11 @@
import { ProjectType } from "../types/ProjectType";
import { Detector } from "./detector";
import { existsSync } from "fs";
export default class NPMDetector implements Detector {
public projectType: ProjectType = "npm";
public matches(path: string): boolean {
return existsSync(path + "/package-lock.json");
}
}
+14
View File
@@ -0,0 +1,14 @@
import { ProjectType } from "../types/ProjectType";
import { Detector } from "./detector";
import { existsSync } from "fs";
export default class ViteDetector implements Detector {
public projectType: ProjectType = "vite";
public matches(path: string): boolean {
return (
existsSync(path + "/vite.config.js") ||
existsSync(path + "/vite.config.ts")
);
}
}
+11
View File
@@ -0,0 +1,11 @@
import { ProjectType } from "../types/ProjectType";
import { Detector } from "./detector";
import { existsSync } from "fs";
export default class YarnDetector implements Detector {
public projectType: ProjectType = "yarn";
public matches(path: string): boolean {
return existsSync(path + "/yarn.lock");
}
}
@@ -17,6 +17,11 @@ export interface ContractPayload {
*/
metadata: any;
/**
* The file name of the original compiled file
*/
fileName: string;
/**
* The source file paths
*/
@@ -4,4 +4,10 @@ export type ProjectType =
| "hardhat"
| "truffle"
| "solc"
| "vite"
| "next"
| "cra"
| "spa-webapp"
| "yarn"
| "npm"
| "none";
+262 -131
View File
@@ -2,60 +2,82 @@
/* 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 projectType: string = "";
let contractName: string = "";
let projectPath: string = "";
let projectType: string = "";
let framework: string = "";
let language: string = "";
let baseContract: string = "";
let chain: string = "";
/* let createType: string = "app"; */
export async function twCreate(pPath: string = "", options: any) {
export async function twCreate(
pType: string,
pPath: string = "",
options: any,
) {
if (typeof pPath === "string") {
projectPath = pPath;
}
if (options.app) {
projectType = "app";
if (typeof options.contractName === "string") {
contractName = options.contractName;
}
if (options.contract) {
if (pType === "app" || options.app) {
projectType = "app";
} else if (pType === "contract" || options.contract) {
projectType = "contract";
}
if (options.typescript) {
language = "typescript";
if (projectType === "app") {
if (options.typescript) {
language = "typescript";
}
if (options.javascript) {
language = "javascript";
}
if (options.next) {
framework = "next";
}
if (options.cra) {
framework = "cra";
}
if (options.vite) {
framework = "vite";
}
if (options.solana) {
chain = "solana";
}
if (options.evm) {
chain = "evm";
}
}
if (options.javascript) {
language = "javascript";
}
if (projectType === "contract") {
if (options.forge) {
framework = "forge";
}
if (options.next) {
framework = "next";
}
if (options.cra) {
framework = "cra";
}
if (options.vite) {
framework = "vite";
}
if (options.forge) {
framework = "forge";
}
if (options.hardhat) {
framework = "hardhat";
if (options.hardhat) {
framework = "hardhat";
}
}
if (options.framework) {
@@ -76,103 +98,216 @@ export async function twCreate(pPath: string = "", options: any) {
if (typeof res.projectType === "string") {
projectType = res.projectType.trim();
}
} else if (!projectType && options.template) {
} else if (!projectType || options.template) {
// If no project type is specified, but a template is, we assume the user wants to create an app.
// We do this so old users can still use the --template flag to create an app.
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" && !framework) {
const res = await prompts({
type: "select",
name: "framework",
message: CREATE_MESSAGES.framework,
choices: [
{ 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);
}
}
@@ -184,7 +319,9 @@ export async function twCreate(pPath: string = "", options: any) {
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" },
@@ -238,20 +375,11 @@ export async function twCreate(pPath: string = "", options: any) {
}
}
}
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) {
@@ -283,18 +411,21 @@ export async function twCreate(pPath: string = "", options: any) {
try {
if (projectType === "app") {
await createApp({
appPath: resolvedProjectPath,
appPath: projectPath,
packageManager,
framework,
language,
template,
chain,
});
} else {
await createContract({
contractPath: resolvedProjectPath,
await createContractProject({
contractPath: projectPath,
packageManager,
framework,
contractName,
baseContract,
onlyContract,
});
}
} catch (reason) {
@@ -22,12 +22,14 @@ export async function createApp({
framework,
language,
template,
chain,
}: {
appPath: string;
packageManager: PackageManager;
framework?: string;
language?: string;
template?: string;
chain?: string;
}): Promise<void> {
let frameworkPath = "";
@@ -43,7 +45,9 @@ export async function createApp({
process.exit(1);
}
} else if (framework) {
frameworkPath = `${framework}-${language || "javascript"}-starter`;
frameworkPath = `${framework}-${language || "javascript"}-${
chain === "solana" ? "solana-" : ""
}starter`;
const found = await hasTemplate(frameworkPath);
if (!found) {
@@ -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);
});
});
}
+16 -1
View File
@@ -1,11 +1,26 @@
import spawn from "cross-spawn";
export async function runCommand(command: string, args: string[]) {
export async function runCommand(
command: string,
args: string[],
logging: boolean = false,
) {
return new Promise<void>((resolve, reject) => {
/**
* Spawn the installation process.
*/
const child = spawn(command, args);
child.stdout?.on("data", (data) => {
if (logging) {
console.log(data.toString());
}
});
child.stderr?.on("error", (err) => {
if (logging) {
console.error(err);
}
});
child.on("close", (code) => {
if (code !== 0) {
reject({ command: `${command}` });
+43
View File
@@ -0,0 +1,43 @@
import NPMDetector from "../core/detection/npm";
import ViteDetector from "../core/detection/vite";
import YarnDetector from "../core/detection/yarn";
import { runCommand } from "../create/helpers/run-command";
import { upload } from "../storage/command";
import { DEFAULT_IPFS_GATEWAY } from "@thirdweb-dev/sdk";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
export async function deployApp(distPath = "dist", projectPath = ".") {
const storage = new ThirdwebStorage();
const supportedFrameworks = [new ViteDetector()];
const possibleProjects = supportedFrameworks
.filter((detector) => detector.matches(projectPath))
.map((detector) => detector.projectType);
const hasYarn = new YarnDetector().matches(".");
const hasNPM = new NPMDetector().matches(".");
if (possibleProjects.length === 0) {
throw new Error("No supported project detected");
}
try {
if (hasYarn) {
await runCommand("yarn", ["build"]);
} else if (hasNPM) {
await runCommand("npm", ["build"]);
}
} catch (err) {
console.error("Can't build project");
return Promise.reject("Can't build project");
}
try {
let url = await upload(storage, distPath);
url = url.replace("ipfs://", DEFAULT_IPFS_GATEWAY);
return `${url}/index.html`;
} catch (err) {
console.error("Can't upload project");
return Promise.reject("Can't upload project");
}
}
+54
View File
@@ -0,0 +1,54 @@
import { processProject } from "../common/processor";
import { info, logger } from "../core/helpers/logger";
import generateDashboardUrl from "../helpers/generate-dashboard-url";
import { deployApp } from "./app";
import chalk from "chalk";
type DeployOptions = {
name: string;
contractVersion: string;
app: boolean;
path?: string;
distPath?: string;
};
export async function deploy(options: DeployOptions) {
if (options.name) {
const url = generateDashboardUrl(options.name, options.contractVersion);
if (!url) {
logger.error(
chalk.red(
`Could not find a contract named ${options.name} ${
options.contractVersion || ""
}`,
),
);
return;
}
info(`Open this link to deploy your contract: ${chalk.blueBright(url)}`);
return url.toString();
}
if (options.app) {
try {
let url = await deployApp(options.distPath, options.path);
info(`Here is the link to your app: ${chalk.blueBright(url.toString())}`);
return url.toString();
} catch (err) {
logger.error("Failed to deploy app, No compatible project found", err);
return Promise.reject(
"failed to deploy app, no compatible project found",
);
}
}
const url = await processProject(options, "deploy");
info(
`Open this link to deploy your contracts: ${chalk.blueBright(
url.toString(),
)}`,
);
return url.toString();
}
@@ -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}`;
}
}
+4 -26
View File
@@ -1,7 +1,5 @@
import { logger } from "../core/helpers/logger";
import { spinner } from "../core/helpers/logger";
import { BufferOrStringWithName, ThirdwebStorage } from "@thirdweb-dev/storage";
import chalk from "chalk";
import fs from "fs";
import path from "path";
@@ -33,22 +31,12 @@ export async function upload(
uploadPath: string,
): Promise<string> {
if (!uploadPath) {
logger.error(
`Please pass a path to a file or directory to upload with the following format:\n ${chalk.blueBright(
`npx thirdweb@latest upload path/to/file.jpg`,
)}\n`,
);
process.exit(1);
return Promise.reject("No path provided");
}
const pathExists = fs.existsSync(uploadPath);
if (!pathExists) {
logger.error(
`Invalid path ${chalk.blueBright(
uploadPath,
)} provided. Please provide a valid path to a file or directory to upload."`,
);
process.exit(1);
return Promise.reject("Invalid path provided");
}
let uri = "";
@@ -57,12 +45,7 @@ export async function upload(
const files = recurseFiles(uploadPath, uploadPath);
if (files.length === 0) {
logger.error(
`No files detected in specified directory ${chalk.blueBright(
uploadPath,
)} to upload.`,
);
process.exit(1);
return Promise.reject("No files detected in specified directory");
}
const spin = spinner(
@@ -82,12 +65,7 @@ export async function upload(
uri = await storage.upload(file, { uploadWithoutDirectory: true });
spin.succeed("Succesfully uploaded file to IPFS.");
} else {
logger.error(
`Path ${chalk.blueBright(
uploadPath,
)} does not point to a valid file or directory. Please provide a valid path to a file or directory to upload`,
);
process.exit(1);
return Promise.reject("Invalid path provided");
}
return uri;
+20
View File
@@ -1,5 +1,25 @@
# @thirdweb-dev/contracts-js
## 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
- [#376](https://github.com/thirdweb-dev/js/pull/376) [`4af785c`](https://github.com/thirdweb-dev/js/commit/4af785c37c831ecd7087c1c9eb9095922cac0855) Thanks [@adam-maj](https://github.com/adam-maj)! - Update tiered-drop with tokens claimed
- [#373](https://github.com/thirdweb-dev/js/pull/373) [`6f818f3`](https://github.com/thirdweb-dev/js/commit/6f818f393eb9023b53a3358d62d60ec23a9246bd) Thanks [@adam-maj](https://github.com/adam-maj)! - Update tiered-drop contract version
## 1.2.0
### Minor Changes
- [#333](https://github.com/thirdweb-dev/js/pull/333) [`aa6d9ed`](https://github.com/thirdweb-dev/js/commit/aa6d9ed75d126d7a0cca9fb8fc389ff94e9d1e14) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Update to contracts package v3.2.0
## 1.1.9
### Patch Changes
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistry__factory.cjs.js",
"module": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistry__factory.esm.js"
}
+3 -3
View File
@@ -1,19 +1,19 @@
{
"name": "@thirdweb-dev/contracts-js",
"version": "1.1.9",
"version": "1.2.2",
"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.1.8-0"
"@thirdweb-dev/contracts": "3.2.8-0"
},
"devDependencies": {
"@babel/preset-env": "^7.18.10",
"@babel/preset-typescript": "^7.18.6",
"@preconstruct/cli": "^2.2.1",
"@typechain/ethers-v5": "10.0.0",
"ethers": "^5.7.0",
"ethers": "^5.7.2",
"typechain": "^8.1.0",
"typescript": "^4.7.4"
},
+1 -1
View File
@@ -6,7 +6,7 @@
"dependencies": {
"@typescript-eslint/eslint-plugin": "^5.33.0",
"@typescript-eslint/parser": "^5.33.0",
"eslint-config-next": "^12.0.8",
"eslint-config-next": "12.3.1",
"eslint-config-prettier": "^8.3.0",
"eslint-config-turbo": "latest",
"eslint-plugin-react": "^7.28.0"
+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"]
}
+72
View File
@@ -1,5 +1,77 @@
# @thirdweb-dev/react
## 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
### Patch Changes
- [#405](https://github.com/thirdweb-dev/js/pull/405) [`ccb7db4`](https://github.com/thirdweb-dev/js/commit/ccb7db48739b8dddcb2c032b3b6e3e5200485715) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add updateAll param to creators and royalty update hooks for Solana
## 3.6.1
### Patch Changes
- [#392](https://github.com/thirdweb-dev/js/pull/392) [`846022e`](https://github.com/thirdweb-dev/js/commit/846022e2cfb12b846aae029b85899fb72fd2c9ad) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix unlimited price for useActiveClaimConditionForWallet
- [#388](https://github.com/thirdweb-dev/js/pull/388) [`7c0744a`](https://github.com/thirdweb-dev/js/commit/7c0744a006e78987ad8b271b2c64f4bac7759510) Thanks [@adam-maj](https://github.com/adam-maj)! - Add support for total supply and pagination on get all
## 3.6.0
### Patch Changes
- [#386](https://github.com/thirdweb-dev/js/pull/386) [`612bcdd`](https://github.com/thirdweb-dev/js/commit/612bcdd16fc242d8b04bc70d609e44b0df47ed3f) Thanks [@jnsdls](https://github.com/jnsdls)! - [Gnosis Connector] - switch to safe.global hostname & add support for bsc and optimism chains
- [#364](https://github.com/thirdweb-dev/js/pull/364) [`7cb8e59`](https://github.com/thirdweb-dev/js/commit/7cb8e59be48dc923316eb36ab43a1bef7364f6b1) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add experimental `useActiveClaimConditionForWallet()` hook
## 3.5.2
### Patch Changes
- [#369](https://github.com/thirdweb-dev/js/pull/369) [`2d3fca5`](https://github.com/thirdweb-dev/js/commit/2d3fca52373046c88392139922e9c9da79f9a2d4) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add useClaimerProofs hook
- [#378](https://github.com/thirdweb-dev/js/pull/378) [`32d91ef`](https://github.com/thirdweb-dev/js/commit/32d91ef709c8fb92a903e52c65b27538a80ea4eb) Thanks [@mykcryptodev](https://github.com/mykcryptodev)! - round borders for buttons and menus on safari
- [#377](https://github.com/thirdweb-dev/js/pull/377) [`b79dc18`](https://github.com/thirdweb-dev/js/commit/b79dc18f7ab5155bbf4af02dc1a953546160bad0) Thanks [@adam-maj](https://github.com/adam-maj)! - Add event filters
## 3.5.1
## 3.5.0
## 3.4.5
## 3.4.4
### Patch Changes
+10 -9
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "3.4.4",
"version": "3.6.9",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -62,7 +62,7 @@
},
"sideEffects:": false,
"devDependencies": {
"@babel/core": "^7.18.10",
"@babel/core": "^7.19.3",
"@babel/preset-env": "^7.18.10",
"@babel/preset-react": "^7.18.6",
"@babel/preset-typescript": "^7.18.6",
@@ -73,6 +73,7 @@
"@preconstruct/cli": "^2.2.1",
"@solana/wallet-adapter-base": "^0.9.17",
"@solana/wallet-adapter-react": "^0.15.19",
"@solana/wallet-adapter-wallets": "^0.19.0",
"@solana/web3.js": "^1.62.0",
"@thirdweb-dev/sdk": "*",
"@types/color": "^3.0.3",
@@ -87,7 +88,7 @@
"eslint-plugin-inclusive-language": "^2.2.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-tsdoc": "^0.2.16",
"ethers": "^5.7.1",
"ethers": "^5.7.2",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
@@ -96,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>
@@ -15,7 +15,7 @@ export interface ThirdwebNftMediaProps extends SharedMediaProps {
/**
* This component can be used to render NFTs from the thirdweb SDK.
* Props: {@link ThirdwebNftMediaProps}
*
*
* @example
* ```jsx
* import { ThirdwebNftMedia, useContract, useNFT } from "@thirdweb-dev/react";
@@ -37,8 +37,19 @@ const BaseButton = styled.button<BaseButtonProps>`
cursor: not-allowed;
}
&:focus {
outline: 2px solid ${(props) => (props.theme as TwUiTheme).colors.accent};
outline-offset: 1px;
position: relative;
border-radius: 0.5em;
outline: 0;
}
&:focus:after {
content: "";
position: absolute;
top: -5px;
right: -5px;
bottom: -5px;
left: -5px;
border: 2px solid ${(props) => (props.theme as TwUiTheme).colors.accent};
border-radius: 11px;
}
`;
@@ -8,10 +8,23 @@ export const Menu = styled.ul<MenuProps>`
margin: 0;
background: ${(props) => (props.theme as TwUiTheme).colors.background};
color: ${(props) => (props.theme as TwUiTheme).colors.text};
outline-color: ${(props) => (props.theme as TwUiTheme).colors.accent};
outline-style: solid;
outline-offset: 0px;
list-style: none;
border-radius: 0.5em;
overflow: hidden;
position: relative;
pointer-events: auto;
&:focus {
outline: 0;
}
&:after {
content: "";
position: absolute;
border: 1px solid ${(props) => (props.theme as TwUiTheme).colors.accent};
border-radius: 0.5em;
pointer-events: none;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
`;
@@ -9,16 +9,21 @@ import {
useContext as useWagmiContext,
} from "wagmi";
// exerpt from https://docs.gnosis-safe.io/backend/available-services
const CHAIN_ID_TO_GNOSIS_SERVER_URL = {
// mainnet
1: "https://safe-transaction.mainnet.gnosis.io",
1: "https://safe-transaction-mainnet.safe.global",
// avalanche
43114: "https://safe-transaction.avalanche.gnosis.io",
43114: "https://safe-transaction-avalanche.safe.global",
// polygon
137: "https://safe-transaction.polygon.gnosis.io",
137: "https://safe-transaction-polygon.safe.global",
// goerli
5: "https://safe-transaction.goerli.gnosis.io",
};
5: "https://safe-transaction-goerli.safe.global",
// bsc
56: "https://safe-transaction-bsc.safe.global",
// optimism
10: "https://safe-transaction-optimism.safe.global",
} as const;
export interface GnosisConnectorArguments {
safeAddress: string;
@@ -28,6 +33,8 @@ export interface GnosisConnectorArguments {
const __IS_SERVER__ = typeof window === "undefined";
export class GnosisSafeConnector extends Connector {
static supportedChains = Object.keys(CHAIN_ID_TO_GNOSIS_SERVER_URL);
public supportedChains = GnosisSafeConnector.supportedChains;
id = "gnosis";
ready = __IS_SERVER__;
name = "Gnosis Safe";
@@ -60,6 +67,11 @@ export class GnosisSafeConnector extends Connector {
};
}
public isChainSupported(chainId: string | number) {
const id = normalizeChainId(chainId);
return !this.isChainUnsupported(id);
}
private async createSafeSigner() {
const signer = await this.previousConnector?.getSigner();
const safeAddress = this.config?.safeAddress;
@@ -86,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,
@@ -2,7 +2,7 @@ import {
RequiredParam,
requiredParamInvariant,
} from "../../../core/query-utils/required-param";
import { useSDKChainId } from "../../providers/base";
import { useSDK, useSDKChainId } from "../../providers/base";
import { getErcs, DropContract, WalletAddress } from "../../types";
import {
cacheKeys,
@@ -14,8 +14,12 @@ import {
ClaimCondition,
ClaimConditionFetchOptions,
ClaimConditionInput,
SnapshotEntryWithProof,
fetchCurrencyValue,
convertToReadableQuantity,
fetchCurrencyMetadata,
} from "@thirdweb-dev/sdk";
import { BigNumberish } from "ethers";
import { BigNumberish, constants, utils } from "ethers";
import invariant from "tiny-invariant";
/**
@@ -45,7 +49,7 @@ export type SetClaimConditionsParams = {
/** **********************/
/**
* Use this to get the active claim conditon for ERC20, ERC721 or ERC1155 based contracts. They need to extend the `claimCondition` extension for this hook to work.
* Use this to get the active claim condition for ERC20, ERC721 or ERC1155 based contracts. They need to extend the `claimCondition` extension for this hook to work.
*
* @example
* ```javascript
@@ -60,7 +64,7 @@ export type SetClaimConditionsParams = {
* const { data: activeClaimCondition, isLoading, error } = useActiveClaimCondition(<YourERC1155ContractInstance>, <tokenId>);
* ```
*
* @param contract - an instance of a contract that extends the ERC721 or ERC1155 spec and implements the `claimConditions` extension.
* @param contract - an instance of a contract that extends the ERC721, ERC1155 or ERC20 spec and implements the `claimConditions` extension.
* @param tokenId - the id of the token to fetch the claim conditions for (if the contract is an ERC1155 contract)
* @returns a response object with the currently active claim condition
* @twfeature ERC721ClaimableWithConditions | ERC1155ClaimableWithConditions | ERC20ClaimableWithConditions
@@ -106,7 +110,80 @@ export function useActiveClaimCondition(
}
/**
* Use this to get all claim conditons for ERC20, ERC721 or ERC1155 based contracts. They need to extend the `claimCondition` extension for this hook to work.
* Use this to get the claimer proofs for an adddress for ERC20, ERC721 or ERC1155 based contracts. They need to extend the `claimCondition` extension for this hook to work.
*
* @example
* ```javascript
* const { data: claimerProofs, isLoading, error } = useClaimerProofs(<YourERC20ContractInstance>);
* ```
* @example
* ```javascript
* const { data: claimerProofs, isLoading, error } = useClaimerProofs(<YourERC721ContractInstance>);
* ```
* @example
* ```javascript
* const { data: claimerProofs, isLoading, error } = useClaimerProofs(<YourERC1155ContractInstance>, <tokenId>);
* ```
*
* @param contract - an instance of a contract that extends the ERC721, ERC1155 or ERC20 spec and implements the `claimConditions` extension.
* @param claimerAddress - the address of the claimer to fetch the claimer proofs for
* @param tokenId - the id of the token to fetch the claimer proofs for (if the contract is an ERC1155 contract)
* @param claimConditionId - optional the claim condition id to get the proofs for
* @returns a response object with the snapshot for the provided address
* @twfeature ERC721ClaimableWithConditions | ERC1155ClaimableWithConditions | ERC20ClaimableWithConditions
* @beta
*/
export function useClaimerProofs(
contract: RequiredParam<DropContract>,
claimerAddress: string,
tokenId?: BigNumberish,
claimConditionId?: BigNumberish,
) {
const contractAddress = contract?.getAddress();
const { erc1155, erc721, erc20 } = getErcs(contract);
return useQueryWithNetwork(
cacheKeys.extensions.claimConditions.getClaimerProofs(
contractAddress,
tokenId,
),
() => {
if (erc1155) {
requiredParamInvariant(
tokenId,
"tokenId is required for ERC1155 claim conditions",
);
return erc1155.claimConditions.getClaimerProofs(
tokenId,
claimerAddress,
claimConditionId,
);
}
if (erc721) {
return erc721.claimConditions.getClaimerProofs(
claimerAddress,
claimConditionId,
);
}
if (erc20) {
return erc20.claimConditions.getClaimerProofs(
claimerAddress,
claimConditionId,
);
}
throw new Error("Contract must be ERC721, ERC1155 or ERC20");
},
{
// Checks that happen here:
// 1. if the contract is based on ERC1155 contract => tokenId cannot be `undefined`
// 2. if the contract is NOT based on ERC1155 => we have to have either an ERC721 or ERC20 contract
enabled: erc1155 ? tokenId !== undefined : !!erc721 || !!erc20,
},
);
}
/**
* Use this to get all claim conditions for ERC20, ERC721 or ERC1155 based contracts. They need to extend the `claimCondition` extension for this hook to work.
*
* @example
* ```javascript
@@ -121,7 +198,7 @@ export function useActiveClaimCondition(
* const { data: claimConditions, isLoading, error } = useClaimConditions(<YourERC1155ContractInstance>, <tokenId>);
* ```
*
* @param contract - an instance of a contract that extends the ERC721 or ERC1155 spec and implements the `claimConditions` extension.
* @param contract - an instance of a contract that extends the ERC721, ERC1155 or ERC20 spec and implements the `claimConditions` extension.
* @param tokenId - the id of the token to fetch the claim conditions for (if the contract is an ERC1155 contract)
* @returns a response object with the list of claim conditions
* @twfeature ERC721ClaimableWithConditions | ERC1155ClaimableWithConditions | ERC20ClaimableWithConditions
@@ -242,6 +319,136 @@ export function useClaimIneligibilityReasons(
);
}
/**
* Use this to check the claim condition for a given wallet address (including checking for overrides that may exist for that given wallet address).
*
* @param contract - an instance of a contract that extends the ERC20, ERC721 or ERC1155 spec and implements the `claimConditions` extension.
* @param walletAddress - the wallet address to check the active claim condition for
* @param tokenId - the id of the token to fetch the claim conditions for (if the contract is an ERC1155 contract)
* @returns the active claim conditon for the wallet address or null if there is no active claim condition
*
* @beta
*/
export function useActiveClaimConditionForWallet(
contract: RequiredParam<DropContract>,
walletAddress: RequiredParam<WalletAddress>,
tokenId?: BigNumberish,
) {
const sdk = useSDK();
const contractAddress = contract?.getAddress();
const { erc1155, erc721, erc20 } = getErcs(contract);
return useQueryWithNetwork<ClaimCondition | null>(
cacheKeys.extensions.claimConditions.useActiveClaimConditionForWallet(
contractAddress,
walletAddress || "_NO_WALLET_",
tokenId,
),
async () => {
// if we do not have a walletAddress just do the same logic as basic useClaimCondition
if (!walletAddress) {
if (erc1155) {
requiredParamInvariant(
tokenId,
"tokenId is required for ERC1155 claim conditions",
);
return erc1155.claimConditions.getActive(tokenId);
}
if (erc721) {
return erc721.claimConditions.getActive();
}
if (erc20) {
return erc20.claimConditions.getActive();
}
throw new Error("Contract must be ERC721, ERC1155 or ERC20");
}
invariant(sdk, "sdk is required");
let activeGeneralClaimCondition: ClaimCondition | null = null;
let claimerProofForWallet: SnapshotEntryWithProof | null = null;
if (erc1155) {
requiredParamInvariant(tokenId, "tokenId is required for ERC1155");
const [cc, cp] = await Promise.all([
erc1155.claimConditions.getActive(tokenId),
erc1155.claimConditions.getClaimerProofs(tokenId, walletAddress),
]);
activeGeneralClaimCondition = cc;
claimerProofForWallet = cp;
}
if (erc721) {
const [cc, cp] = await Promise.all([
erc721.claimConditions.getActive(),
erc721.claimConditions.getClaimerProofs(walletAddress),
]);
activeGeneralClaimCondition = cc;
claimerProofForWallet = cp;
}
if (erc20) {
const [cc, cp] = await Promise.all([
erc20.claimConditions.getActive(),
erc20.claimConditions.getClaimerProofs(walletAddress),
]);
activeGeneralClaimCondition = cc;
claimerProofForWallet = cp;
}
// if there is no active claim condition nothing matters, return null
if (!activeGeneralClaimCondition) {
return null;
}
// if there is no claimer proof then just fall back to the active general claim condition
if (!claimerProofForWallet) {
return activeGeneralClaimCondition;
}
const { maxClaimable, currencyAddress, price } = claimerProofForWallet;
const currencyWithOverride =
currencyAddress || activeGeneralClaimCondition.currencyAddress;
const currencyMetadata = await fetchCurrencyMetadata(
sdk.getProvider(),
currencyWithOverride,
);
const normalizedPrize = price
? price === "unlimited"
? constants.MaxUint256
: utils.parseUnits(price, currencyMetadata.decimals)
: null;
const priceWithOverride =
normalizedPrize || activeGeneralClaimCondition.price;
const maxClaimableWithOverride =
// have to transform this the same way that claim conditions do it in SDK
convertToReadableQuantity(maxClaimable, currencyMetadata.decimals) ||
activeGeneralClaimCondition.maxClaimablePerWallet;
const currencyValueWithOverride = await fetchCurrencyValue(
sdk.getProvider(),
currencyWithOverride,
priceWithOverride,
);
return {
// inherit the entire claim condition
...activeGeneralClaimCondition,
// overwrite all keys that could be changed based on overwrites
maxClaimablePerWallet: maxClaimableWithOverride,
price: priceWithOverride,
currency: currencyWithOverride,
currencyAddress: currencyWithOverride,
currencyMetadata: currencyValueWithOverride,
};
},
{
// Checks that happen here:
// 1. if the contract is based on ERC1155 contract => tokenId cannot be `undefined`
// 2. if the contract is NOT based on ERC1155 => we have to have either an ERC721 or ERC20 contract
enabled: erc1155 ? tokenId !== undefined : !!erc721 || !!erc20,
},
);
}
/** **********************/
/** WRITE HOOKS **/
/** **********************/
@@ -368,8 +575,6 @@ export function useResetClaimConditions(
return conditions.map((c) => ({
...c,
price: c.currencyMetadata.displayValue,
maxQuantity: c.maxQuantity.toString(),
quantityLimitPerTransaction: c.quantityLimitPerTransaction.toString(),
}));
};
@@ -23,7 +23,7 @@ import {
ContractEvent,
ContractForPrebuiltContractType,
ContractType,
EventQueryFilter,
EventQueryOptions,
PrebuiltContractType,
SUPPORTED_CHAIN_ID,
ThirdwebSDK,
@@ -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,
},
);
@@ -346,7 +348,7 @@ export function useContractMetadataUpdate(
export function useContractEvents(
contract: RequiredParam<ValidContractInstance>,
eventName?: string,
options: { queryFilter?: EventQueryFilter; subscribe?: boolean } = {
options: { queryFilter?: EventQueryOptions; subscribe?: boolean } = {
subscribe: true,
},
) {
+2 -2
View File
@@ -106,7 +106,7 @@ export function useUnclaimedNFTSupply(contract: RequiredParam<DropContract>) {
invariant(erc721, "No ERC721 Contract instance provided");
return erc721.totalUnclaimedSupply();
}
invariant(false, "Contract is not an instance of ERC721")
invariant(false, "Contract is not an instance of ERC721");
},
{ enabled: !!erc721 },
);
@@ -129,7 +129,7 @@ export function useClaimedNFTSupply(contract: RequiredParam<DropContract>) {
if (erc721) {
return erc721.totalClaimedSupply();
}
invariant(false, "Contract is not an instance of ERC721")
invariant(false, "Contract is not an instance of ERC721");
},
{ enabled: !!erc721 },
);
+3 -5
View File
@@ -232,11 +232,9 @@ export function useClaimToken(contract: RequiredParam<TokenContract>) {
invariant(data.to, 'No "to" address provided');
if (erc20) {
invariant(erc20?.claimTo, "contract does not support claimTo");
return await erc20.claimTo(
data.to,
data.amount,
data.checkERC20Allowance,
);
return await erc20.claimTo(data.to, data.amount, {
checkERC20Allowance: data.checkERC20Allowance,
});
}
invariant(false, "Smart contract is not a valid erc20 contract");
},
+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;
},
{
@@ -11,7 +11,7 @@ import { useContract } from "../async/contracts";
* import { useContract } from '@thirdweb-dev/react'
*
* export default function Component() {
* const { contract } = useNFTCollection("<YOUR-CONTRACT-ADDRESS>", "nft-collection")
* const { contract, isLoading, error } = useContract("<YOUR-CONTRACT-ADDRESS>", "nft-collection")
*
* // Now you can use the nftCollection contract in the rest of the component
*
@@ -287,6 +287,16 @@ export const cacheKeys = {
? ["claimConditions", "getAll", { tokenId }, options]
: ["claimConditions", "getAll", options],
),
getClaimerProofs: (
contractAddress: RequiredParam<ContractAddress>,
tokenId?: BigNumberish,
) =>
createContractCacheKey(
contractAddress,
tokenId
? ["claimConditions", "getClaimerProofs", { tokenId }]
: ["claimConditions", "getClaimerProofs"],
),
getClaimIneligibilityReasons: (
contractAddress: RequiredParam<ContractAddress>,
params: { walletAddress?: WalletAddress; quantity: string | number },
@@ -303,6 +313,23 @@ export const cacheKeys = {
]
: ["claimConditions", "getIneligibilityReasons", params],
),
// combinations of queries cache keys
useActiveClaimConditionForWallet: (
contractAddress: RequiredParam<ContractAddress>,
walletAddress: WalletAddress,
tokenId?: BigNumberish,
) =>
createContractCacheKey(
contractAddress,
tokenId
? [
"claimConditions",
"useActiveClaimConditionForWallet",
{ tokenId, walletAddress },
,
]
: ["claimConditions", "getIneligibilityReasons", { walletAddress }],
),
},
// primary sale contracts
@@ -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;
},
{
+12 -4
View File
@@ -4,17 +4,22 @@ import {
RequiredParam,
} from "../../../core/query-utils/required-param";
import { useQuery } from "@tanstack/react-query";
import { QueryAllParams } from "@thirdweb-dev/sdk";
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
export function nftGetAllQuery(
program: RequiredParam<NFTCollection | NFTDrop>,
queryParams?: QueryAllParams,
) {
return {
queryKey: createSOLProgramQueryKey(program, ["getAll"] as const),
queryKey: createSOLProgramQueryKey(program, [
"getAll",
queryParams,
] as const),
queryFn: async () => {
requiredParamInvariant(program, "program is required");
return await program.getAll();
return program.getAll(queryParams);
},
enabled: !!program,
};
@@ -40,6 +45,9 @@ export function nftGetAllQuery(
*
* @public
*/
export function useNFTs(program: RequiredParam<NFTCollection | NFTDrop>) {
return useQuery(nftGetAllQuery(program));
export function useNFTs(
program: RequiredParam<NFTCollection | NFTDrop>,
queryParams?: QueryAllParams,
) {
return useQuery(nftGetAllQuery(program, queryParams));
}
@@ -40,6 +40,8 @@ export function nftRoyaltyQuery(
*
* @public
*/
export function useRoyaltySettings(program: RequiredParam<NFTCollection | NFTDrop>) {
export function useRoyaltySettings(
program: RequiredParam<NFTCollection | NFTDrop>,
) {
return useQuery(nftRoyaltyQuery(program));
}
@@ -0,0 +1,47 @@
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
import {
requiredParamInvariant,
RequiredParam,
} from "../../../core/query-utils/required-param";
import { useQuery } from "@tanstack/react-query";
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
export function nftTotalSupplyQuery(
program: RequiredParam<NFTCollection | NFTDrop>,
) {
return {
queryKey: createSOLProgramQueryKey(program, ["supply"] as const),
queryFn: async () => {
requiredParamInvariant(program, "program is required");
return program.totalSupply();
},
enabled: !!program,
};
}
/**
* Get the totaly supply of NFTs on the program
* @param program - The NFT program to get the total supply of
*
* @example
* ```jsx
* import { useProgram, useTotalSupply } from "@thirdweb-dev/react/solana";
*
* export default function Component() {
* const { program } = useProgram("{{program_address}}");
* const { data: supply, isLoading } = useTotalSupply(program);
*
* return (
* <pre>{JSON.stringify(supply)}</pre>
* )
* }
* ```
*
* @public
*/
export function useTotalSupply(
program: RequiredParam<NFTCollection | NFTDrop>,
) {
return useQuery(nftTotalSupplyQuery(program));
}
@@ -4,7 +4,11 @@ import {
RequiredParam,
} from "../../../core/query-utils/required-param";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import type { CreatorInput, NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
import type {
NFTCollection,
NFTDrop,
UpdateCreatorInput,
} from "@thirdweb-dev/sdk/solana";
/**
* Update the creators for an NFT program
@@ -35,9 +39,9 @@ export function useUpdateCreators(
) {
const queryClient = useQueryClient();
return useMutation(
async (creators: CreatorInput[]) => {
async ({ creators, updateAll }: UpdateCreatorInput) => {
requiredParamInvariant(program, "program is required");
return await program.updateCreators(creators);
return await program.updateCreators(creators, updateAll);
},
{
onSettled: () =>
@@ -4,7 +4,11 @@ import {
RequiredParam,
} from "../../../core/query-utils/required-param";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
import type {
NFTCollection,
NFTDrop,
UpdateRoyaltySettingsInput,
} from "@thirdweb-dev/sdk/solana";
/**
* Update the royalty for an NFT program
@@ -35,9 +39,9 @@ export function useUpdateRoyaltySettings(
) {
const queryClient = useQueryClient();
return useMutation(
async (sellerFeeBasisPoints: number) => {
async ({ sellerFeeBasisPoints, updateAll }: UpdateRoyaltySettingsInput) => {
requiredParamInvariant(program, "program is required");
return await program.updateRoyalty(sellerFeeBasisPoints);
return await program.updateRoyalty(sellerFeeBasisPoints, updateAll);
},
{
onSettled: () =>
@@ -4,7 +4,8 @@ import {
RequiredParam,
} from "../../../core/query-utils/required-param";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import type { Amount, Token } from "@thirdweb-dev/sdk/solana";
import type { Amount } from "@thirdweb-dev/sdk";
import type { Token } from "@thirdweb-dev/sdk/solana";
export type TransferTokenMutationParams = {
amount: Amount;
+1
View File
@@ -18,6 +18,7 @@ export * from "./hooks/nft/useRoyaltySettings";
export * from "./hooks/nft/useUpdateRoyaltySettings";
export * from "./hooks/nft/useCreators";
export * from "./hooks/nft/useUpdateCreators";
export * from "./hooks/nft/useTotalSupply";
// NFT Collection
export * from "./hooks/nft/collection/useMintNFT";
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+176
View File
@@ -1,5 +1,181 @@
# @thirdweb-dev/sdk
## 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
- [#408](https://github.com/thirdweb-dev/js/pull/408) [`48797c7`](https://github.com/thirdweb-dev/js/commit/48797c7cf0695965e33eb6bf602be4652f7085a8) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - add `Gasless` as a possible extension to feature-detect
- [#402](https://github.com/thirdweb-dev/js/pull/402) [`83dcaf7`](https://github.com/thirdweb-dev/js/commit/83dcaf70584af8c5cdf0427f9fc1ba82d89f0887) Thanks [@adam-maj](https://github.com/adam-maj)! - Expose sdk.fromWallet and wallet classes
- [#412](https://github.com/thirdweb-dev/js/pull/412) [`f03be39`](https://github.com/thirdweb-dev/js/commit/f03be398e0d7b75c9c5b4fb643f35903e89a17e7) Thanks [@easonchai](https://github.com/easonchai)! - Correctly handle contracts using the SignatureMintERC1155 ContractKit extension
- [#283](https://github.com/thirdweb-dev/js/pull/283) [`2eaa67a`](https://github.com/thirdweb-dev/js/commit/2eaa67acbe21464e7715d0b696afdc024460a44d) Thanks [@adam-maj](https://github.com/adam-maj)! - AppURI detection now enabled
- [#414](https://github.com/thirdweb-dev/js/pull/414) [`47f8945`](https://github.com/thirdweb-dev/js/commit/47f8945325447874b1ace0359919c1d54fd55436) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Improve error parsing
## 3.6.2
### Patch Changes
- [#405](https://github.com/thirdweb-dev/js/pull/405) [`ccb7db4`](https://github.com/thirdweb-dev/js/commit/ccb7db48739b8dddcb2c032b3b6e3e5200485715) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add updateAll param to creators and royalty update hooks for Solana
- [#404](https://github.com/thirdweb-dev/js/pull/404) [`9151aa7`](https://github.com/thirdweb-dev/js/commit/9151aa7dc80754a7aa4fd3f6ce0207bccbb6451f) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - expose `getDefaultTrustedForwarders` helper function
- [#305](https://github.com/thirdweb-dev/js/pull/305) [`5a01c53`](https://github.com/thirdweb-dev/js/commit/5a01c537e30bd7ef562aad1012413990de6faedf) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Update to Metaplex 0.17
## 3.6.1
### Patch Changes
- [#398](https://github.com/thirdweb-dev/js/pull/398) [`15514f1`](https://github.com/thirdweb-dev/js/commit/15514f190a844d809ae5b1edb580aab46a682485) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - add `defaultValue` to constructorParams schema for releases
- [#388](https://github.com/thirdweb-dev/js/pull/388) [`7c0744a`](https://github.com/thirdweb-dev/js/commit/7c0744a006e78987ad8b271b2c64f4bac7759510) Thanks [@adam-maj](https://github.com/adam-maj)! - Add support for total supply and pagination on get all
- [#395](https://github.com/thirdweb-dev/js/pull/395) [`f8bceec`](https://github.com/thirdweb-dev/js/commit/f8bceec10c60b30dc3d6f45926e2a9e018202578) Thanks [@jnsdls](https://github.com/jnsdls)! - [Solana] - fix claim condition reset to native token from custom
- [#399](https://github.com/thirdweb-dev/js/pull/399) [`887af24`](https://github.com/thirdweb-dev/js/commit/887af24450e316c2ea390cd49c0563cebe793c0f) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - fix custom error handling for null-ish error values
- [#390](https://github.com/thirdweb-dev/js/pull/390) [`96bd92e`](https://github.com/thirdweb-dev/js/commit/96bd92e724ec7d880d23348071b26ab8c21dd868) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SDK] Expose `getAllDetectedFeatures(ABI)` helper function
## 3.6.0
### Minor Changes
- [#364](https://github.com/thirdweb-dev/js/pull/364) [`7cb8e59`](https://github.com/thirdweb-dev/js/commit/7cb8e59be48dc923316eb36ab43a1bef7364f6b1) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Enable new Drop contracts
### Patch Changes
- [#382](https://github.com/thirdweb-dev/js/pull/382) [`0ed77d2`](https://github.com/thirdweb-dev/js/commit/0ed77d2c9e7526444ef660aab82a950865234aa6) Thanks [@jnsdls](https://github.com/jnsdls)! - Add `constructorParams` to `ExtraPublishMetadataSchemaInput` schema to support better deploys from releases.
- [#385](https://github.com/thirdweb-dev/js/pull/385) [`04a47e8`](https://github.com/thirdweb-dev/js/commit/04a47e8971d28da2532ebd9db824eeb459c17bd4) Thanks [@adam-maj](https://github.com/adam-maj)! - Add retroactive royalty and creator setting
## 3.5.2
### Patch Changes
- [#380](https://github.com/thirdweb-dev/js/pull/380) [`3eba69a`](https://github.com/thirdweb-dev/js/commit/3eba69afd78b7aa472a9c00c9d4220bb69ad1d3e) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose sdk.wallet.getChainId()
- [#376](https://github.com/thirdweb-dev/js/pull/376) [`4af785c`](https://github.com/thirdweb-dev/js/commit/4af785c37c831ecd7087c1c9eb9095922cac0855) Thanks [@adam-maj](https://github.com/adam-maj)! - Update tiered-drop with tokens claimed
- [#373](https://github.com/thirdweb-dev/js/pull/373) [`6f818f3`](https://github.com/thirdweb-dev/js/commit/6f818f393eb9023b53a3358d62d60ec23a9246bd) Thanks [@adam-maj](https://github.com/adam-maj)! - Update tiered-drop contract version
- [#377](https://github.com/thirdweb-dev/js/pull/377) [`b79dc18`](https://github.com/thirdweb-dev/js/commit/b79dc18f7ab5155bbf4af02dc1a953546160bad0) Thanks [@adam-maj](https://github.com/adam-maj)! - Add event filters
- Updated dependencies [[`4af785c`](https://github.com/thirdweb-dev/js/commit/4af785c37c831ecd7087c1c9eb9095922cac0855), [`6f818f3`](https://github.com/thirdweb-dev/js/commit/6f818f393eb9023b53a3358d62d60ec23a9246bd)]:
- @thirdweb-dev/contracts-js@1.2.1
## 3.5.1
### Patch Changes
- [#368](https://github.com/thirdweb-dev/js/pull/368) [`4e7b293`](https://github.com/thirdweb-dev/js/commit/4e7b293c543244de79c150ca8c37d941221fc9a3) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix handling of old allowlist proof format
- [#365](https://github.com/thirdweb-dev/js/pull/365) [`c9c0e4f`](https://github.com/thirdweb-dev/js/commit/c9c0e4ff39b054af746f3aec75fcbd0a3ef7239d) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - now React Native compatible
## 3.5.0
### Minor Changes
- [#329](https://github.com/thirdweb-dev/js/pull/329) [`5200d5d`](https://github.com/thirdweb-dev/js/commit/5200d5d7e730da58bd4d3e7c222e3c661265f913) Thanks [@adam-maj](https://github.com/adam-maj)! - ### Breaking changes:
1. claim conditions had some changes to support the new drop contracts:
- `maxClaimablePerTransaction` is now named `maxClaimablePerWallet`
- `maxQuantity` is now named `maxClaimable`
2. signature minting now requires a `to` address to be set for security purposees
### Main Changes:
- Support for new optimized Drop contracts
- Support for new claim conditions with overrides
- Don't allow zero address recipient on signature minting
### Patch Changes
- [#362](https://github.com/thirdweb-dev/js/pull/362) [`42a6065`](https://github.com/thirdweb-dev/js/commit/42a606588dfed03c67c57357dd0ee1ad19fad6ea) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SDK] Fix fetching NFTs with numbers as ids
- Updated dependencies [[`aa6d9ed`](https://github.com/thirdweb-dev/js/commit/aa6d9ed75d126d7a0cca9fb8fc389ff94e9d1e14)]:
- @thirdweb-dev/contracts-js@1.2.0
## 3.4.5
### Patch Changes
- [#359](https://github.com/thirdweb-dev/js/pull/359) [`e731c1a`](https://github.com/thirdweb-dev/js/commit/e731c1a7c341e6f2b9cc42c88d5c1b036dcf4a7c) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SDK] Allow fetching claimerProofs from any claim condition
## 3.4.4
## 3.4.3
+4
View File
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-sdk-evm-wallets.cjs.js",
"module": "dist/thirdweb-dev-sdk-evm-wallets.esm.js"
}
+33 -16
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "3.4.4",
"version": "3.6.9",
"description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
"license": "Apache-2.0",
@@ -19,6 +19,10 @@
"module": "./solana/dist/thirdweb-dev-sdk-solana.esm.js",
"default": "./solana/dist/thirdweb-dev-sdk-solana.cjs.js"
},
"./evm/wallets": {
"module": "./evm/wallets/dist/thirdweb-dev-sdk-evm-wallets.esm.js",
"default": "./evm/wallets/dist/thirdweb-dev-sdk-evm-wallets.cjs.js"
},
"./solana/server": {
"module": "./solana/server/dist/thirdweb-dev-sdk-solana-server.esm.js",
"default": "./solana/server/dist/thirdweb-dev-sdk-solana-server.cjs.js"
@@ -28,6 +32,7 @@
"files": [
"dist/",
"evm/",
"wallets/",
"solana/",
"server/"
],
@@ -35,6 +40,7 @@
"entrypoints": [
"index.ts",
"evm/index.ts",
"evm/wallets/index.ts",
"solana/index.ts",
"solana/server/index.ts"
],
@@ -57,7 +63,7 @@
"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",
"node:solana:start": "DEBUG='amman:(info|error|debug)' amman start",
"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'",
"test:solana": "make test-sol",
@@ -65,20 +71,21 @@
"push": "yalc push"
},
"devDependencies": {
"@metaplex-foundation/amman": "0.10.0",
"@metaplex-foundation/amman-client": "0.2.1",
"@aws-sdk/client-secrets-manager": "^3.216.0",
"@metaplex-foundation/amman": "^0.12.0",
"@metaplex-foundation/amman-client": "^0.2.1",
"@microsoft/api-documenter": "^7.19.4",
"@microsoft/api-extractor": "^7.29.2",
"@microsoft/tsdoc": "^0.14.1",
"@nomiclabs/hardhat-ethers": "2.0.5",
"@nomiclabs/hardhat-ethers": "^2.0.5",
"@preconstruct/cli": "^2.2.1",
"@swc-node/register": "^1.5.1",
"@swc/core": "^1.2.177",
"@types/chai": "^4.3.3",
"@types/deep-equal-in-any-order": "^1.0.1",
"@types/mocha": "^9.1.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",
@@ -89,28 +96,38 @@
"eslint-plugin-inclusive-language": "^2.2.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-tsdoc": "^0.2.16",
"ethers": "^5.7.0",
"ethers": "^5.7.2",
"ethers-aws-kms-signer": "^1.3.2",
"hardhat": "^2.9.3",
"mocha": "^10.0.0",
"prettier": "^2.7.1",
"typescript": "^4.7.4"
},
"peerDependencies": {
"ethers": "^5"
"@aws-sdk/client-secrets-manager": "^3.215.0",
"ethers": "^5",
"ethers-aws-kms-signer": "^1.3.2"
},
"peerDependenciesMeta": {
"@aws-sdk/client-secrets-manager": {
"optional": true
},
"ethers-aws-kms-signer": {
"optional": true
}
},
"dependencies": {
"@metaplex-foundation/js": "0.15.0",
"@metaplex-foundation/mpl-token-metadata": "2.2.2",
"@project-serum/anchor": "0.25.0",
"@solana/spl-token": "0.2.0",
"@solana/web3.js": "1.62.0",
"@metaplex-foundation/js": "^0.17.6",
"@metaplex-foundation/mpl-token-metadata": "^2.3.3",
"@project-serum/anchor": "^0.25.0",
"@solana/spl-token": "^0.3.5",
"@solana/web3.js": "^1.62.0",
"@thirdweb-dev/contracts-js": "*",
"@thirdweb-dev/storage": "*",
"bn.js": "^5.2.1",
"bs58": "^5.0.0",
"cbor-x": "^1.4.1",
"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}`;
}
+16 -10
View File
@@ -1,19 +1,25 @@
import { z } from "zod";
/**
* @internal
*/
export const DEFAULT_QUERY_ALL_COUNT = 100;
export const QueryAllParamsSchema = z
.object({
start: z.number().default(0),
count: z.number().default(DEFAULT_QUERY_ALL_COUNT),
})
.default({
start: 0,
count: DEFAULT_QUERY_ALL_COUNT,
});
/**
* Pagination Parameters
* @public
*/
export interface QueryAllParams {
/**
* the index to start from (default: 0)
*/
start?: number;
/**
* how many items to return (default: 100)
*/
count?: number;
}
export type QueryAllParams = Exclude<
z.input<typeof QueryAllParamsSchema>,
undefined
>;
+15 -2
View File
@@ -2,8 +2,14 @@ import BN from "bn.js";
import { BigNumber } from "ethers";
import { z } from "zod";
const isBrowser = () => typeof window !== "undefined";
const FileOrBufferUnionSchema = isBrowser()
/**
* @internal
*/
export const isBrowser = () => typeof window !== "undefined";
/**
* @internal
*/
export const FileOrBufferUnionSchema = isBrowser()
? (z.instanceof(File) as z.ZodType<InstanceType<typeof File>>)
: (z.instanceof(Buffer) as z.ZodTypeAny); // @fixme, this is a hack to make browser happy for now
@@ -96,6 +102,11 @@ export const AmountSchema = z
])
.transform((arg) => (typeof arg === "number" ? arg.toString() : arg));
/**
* @internal
*/
export type Amount = z.input<typeof AmountSchema>;
/**
* @internal
*/
@@ -103,6 +114,8 @@ export const QuantitySchema = z
.union([AmountSchema, z.literal("unlimited")])
.default("unlimited");
export type Quantity = z.output<typeof QuantitySchema>;
export const RawDateSchema = z.date().transform((i) => {
return BigNumber.from(Math.floor(i.getTime() / 1000));
});
+244 -96
View File
@@ -1,6 +1,8 @@
import { Quantity } from "../../core/schema/shared";
import { NATIVE_TOKEN_ADDRESS } from "../constants";
import { ContractWrapper } from "../core/classes/contract-wrapper";
import {
AbstractClaimConditionContractStruct,
ClaimConditionInputArray,
ClaimConditionInputSchema,
ClaimConditionOutputSchema,
@@ -8,7 +10,6 @@ import {
import {
SnapshotEntry,
SnapshotEntryWithProof,
SnapshotInputSchema,
SnapshotSchema,
} from "../schema/contracts/common/snapshots";
import {
@@ -25,9 +26,13 @@ import {
isNativeToken,
normalizePriceValue,
} from "./currency";
import { ShardedMerkleTree } from "./sharded-merkle-tree";
import {
ShardedMerkleTree,
SnapshotFormatVersion,
} from "./sharded-merkle-tree";
import { createSnapshot } from "./snapshots";
import { IDropClaimCondition } from "@thirdweb-dev/contracts-js/dist/declarations/src/DropERC20";
import { IClaimCondition } from "@thirdweb-dev/contracts-js/dist/declarations/src/Drop";
import { IDropClaimCondition_V2 } from "@thirdweb-dev/contracts-js/dist/declarations/src/IDropERC20_V2";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import {
BigNumber,
@@ -45,6 +50,7 @@ import {
* @returns - `overrides` and `proofs` as an object.
*/
export async function prepareClaim(
addressToClaim: string,
quantity: BigNumberish,
activeClaimCondition: ClaimCondition,
merkleMetadataFetcher: () => Promise<Record<string, string>>,
@@ -52,27 +58,57 @@ export async function prepareClaim(
contractWrapper: ContractWrapper<any>,
storage: ThirdwebStorage,
checkERC20Allowance: boolean,
snapshotFormatVersion: SnapshotFormatVersion,
): Promise<ClaimVerification> {
const addressToClaim = await contractWrapper.getSignerAddress();
let maxClaimable = BigNumber.from(0);
let maxClaimable = convertQuantityToBigNumber(
activeClaimCondition.maxClaimablePerWallet,
tokenDecimals,
);
let proofs = [utils.hexZeroPad([0], 32)];
let priceInProof = activeClaimCondition.price; // the price to send to the contract in claim proofs
let currencyAddressInProof = activeClaimCondition.currencyAddress;
try {
if (
!activeClaimCondition.merkleRootHash
.toString()
.startsWith(constants.AddressZero)
) {
const claim = await fetchSnapshotEntryForAddress(
const snapshotEntry = await fetchSnapshotEntryForAddress(
addressToClaim,
activeClaimCondition.merkleRootHash.toString(),
await merkleMetadataFetcher(),
contractWrapper.getProvider(),
storage,
snapshotFormatVersion,
);
if (!claim) {
throw new Error("No claim found for this address");
if (snapshotEntry) {
proofs = snapshotEntry.proof;
// override only if not default values (unlimited for quantity, zero addr for currency)
maxClaimable =
snapshotEntry.maxClaimable === "unlimited"
? ethers.constants.MaxUint256
: ethers.utils.parseUnits(
snapshotEntry.maxClaimable,
tokenDecimals,
);
priceInProof =
snapshotEntry.price === undefined ||
snapshotEntry.price === "unlimited"
? ethers.constants.MaxUint256
: await normalizePriceValue(
contractWrapper.getProvider(),
snapshotEntry.price,
snapshotEntry.currencyAddress || ethers.constants.AddressZero,
);
currencyAddressInProof =
snapshotEntry.currencyAddress || ethers.constants.AddressZero;
} else {
// if no snapshot entry, and it's a v1 format (exclusive allowlist) then address can't claim
if (snapshotFormatVersion === SnapshotFormatVersion.V1) {
throw new Error("No claim found for this address");
}
// but if its snapshot v2 (override list behavior) then address can still claim with default settings
}
proofs = claim.proof;
maxClaimable = ethers.utils.parseUnits(claim.maxClaimable, tokenDecimals);
}
} catch (e) {
// have to handle the valid error case that we *do* want to throw on
@@ -87,18 +123,28 @@ export async function prepareClaim(
}
const overrides = (await contractWrapper.getCallOverrides()) || {};
const price = activeClaimCondition.price;
const currencyAddress = activeClaimCondition.currencyAddress;
if (price.gt(0)) {
// the actual price to check allowance against
// if proof price is unlimited, then we use the price from the claim condition
// this mimics the contract behavior
const pricePerToken =
priceInProof.toString() !== ethers.constants.MaxUint256.toString()
? priceInProof
: activeClaimCondition.price;
// same for currency address
const currencyAddress =
currencyAddressInProof !== ethers.constants.AddressZero
? currencyAddressInProof
: activeClaimCondition.currencyAddress;
if (pricePerToken.gt(0)) {
if (isNativeToken(currencyAddress)) {
overrides["value"] = BigNumber.from(price)
overrides["value"] = BigNumber.from(pricePerToken)
.mul(quantity)
.div(ethers.utils.parseUnits("1", tokenDecimals));
} else if (checkERC20Allowance) {
await approveErc20Allowance(
contractWrapper,
currencyAddress,
price,
pricePerToken,
quantity,
tokenDecimals,
);
@@ -107,9 +153,11 @@ export async function prepareClaim(
return {
overrides,
proofs,
maxQuantityPerTransaction: maxClaimable,
price,
currencyAddress,
maxClaimable,
price: pricePerToken,
currencyAddress: currencyAddress,
priceInProof,
currencyAddressInProof,
};
}
@@ -139,6 +187,8 @@ export async function fetchSnapshot(
return snapshotData.claims.map((claim) => ({
address: claim.address,
maxClaimable: claim.maxClaimable,
price: claim.price,
currencyAddress: claim.currencyAddress,
}));
}
}
@@ -150,7 +200,9 @@ export async function fetchSnapshotEntryForAddress(
address: string,
merkleRoot: string,
merkleMetadata: Record<string, string> | undefined,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
snapshotFormatVersion: SnapshotFormatVersion,
): Promise<SnapshotEntryWithProof | null> {
if (!merkleMetadata) {
return null;
@@ -163,7 +215,11 @@ export async function fetchSnapshotEntryForAddress(
raw,
storage,
);
return await merkleTree.getProof(address);
return await merkleTree.getProof(
address,
provider,
snapshotFormatVersion,
);
}
// legacy non-sharded, just fetch it all and filter out
const snapshotData = SnapshotSchema.parse(raw);
@@ -231,53 +287,20 @@ export async function updateExistingClaimConditions(
}
/**
* Fetches the proof for the current signer for a particular wallet.
*
* @param addressToClaim
* @param merkleRoot - The merkle root of the condition to check.
* @param tokenDecimals
* @param merkleMetadata
* @param storage
* @returns - The proof for the current signer for the specified condition.
*/
export async function getClaimerProofs(
addressToClaim: string,
merkleRoot: string,
tokenDecimals: number,
merkleMetadata: Record<string, string>,
storage: ThirdwebStorage,
): Promise<{ maxClaimable: BigNumber; proof: string[] }> {
const claim = await fetchSnapshotEntryForAddress(
addressToClaim,
merkleRoot,
merkleMetadata,
storage,
);
if (!claim) {
return {
proof: [],
maxClaimable: BigNumber.from(0),
};
}
return {
proof: claim.proof,
maxClaimable: ethers.utils.parseUnits(claim.maxClaimable, tokenDecimals),
};
}
/**
* Create and uploads snapshots + converts claim conditions to contract format
* @internal
* Decorates claim conditions with merkle roots from snapshots if present
* @param claimConditionInputs
* @param tokenDecimals
* @param provider
* @param storage
* @internal
* @param snapshotFormatVersion
*/
export async function processClaimConditionInputs(
async function processSnapshotData(
claimConditionInputs: ClaimConditionInput[],
tokenDecimals: number,
provider: providers.Provider,
provider: ethers.providers.Provider,
storage: ThirdwebStorage,
snapshotFormatVersion: SnapshotFormatVersion,
) {
const snapshotInfos: SnapshotInfo[] = [];
const inputsWithSnapshots = await Promise.all(
@@ -285,9 +308,11 @@ export async function processClaimConditionInputs(
// check snapshots and upload if provided
if (conditionInput.snapshot && conditionInput.snapshot.length > 0) {
const snapshotInfo = await createSnapshot(
SnapshotInputSchema.parse(conditionInput.snapshot),
conditionInput.snapshot,
tokenDecimals,
provider,
storage,
snapshotFormatVersion,
);
snapshotInfos.push(snapshotInfo);
conditionInput.merkleRootHash = snapshotInfo.merkleRoot;
@@ -299,26 +324,54 @@ export async function processClaimConditionInputs(
return conditionInput;
}),
);
return { inputsWithSnapshots, snapshotInfos };
}
function compare(a: BigNumberish, b: BigNumberish) {
const left = BigNumber.from(a);
const right = BigNumber.from(b);
if (left.eq(right)) {
return 0;
} else if (left.gt(right)) {
return 1;
} else {
return -1;
}
}
/**
* Create and uploads snapshots + converts claim conditions to contract format
* @param claimConditionInputs
* @param tokenDecimals
* @param provider
* @param storage
* @param snapshotFormatVersion
* @internal
*/
export async function processClaimConditionInputs(
claimConditionInputs: ClaimConditionInput[],
tokenDecimals: number,
provider: providers.Provider,
storage: ThirdwebStorage,
snapshotFormatVersion: SnapshotFormatVersion,
) {
const { inputsWithSnapshots, snapshotInfos } = await processSnapshotData(
claimConditionInputs,
tokenDecimals,
provider,
storage,
snapshotFormatVersion,
);
const parsedInputs = ClaimConditionInputArray.parse(inputsWithSnapshots);
// Convert processed inputs to the format the contract expects, and sort by timestamp
const sortedConditions: IDropClaimCondition.ClaimConditionStruct[] = (
const sortedConditions: AbstractClaimConditionContractStruct[] = (
await Promise.all(
parsedInputs.map((c) =>
convertToContractModel(c, tokenDecimals, provider),
convertToContractModel(c, tokenDecimals, provider, storage),
),
)
).sort((a, b) => {
const left = BigNumber.from(a.startTimestamp);
const right = BigNumber.from(b.startTimestamp);
if (left.eq(right)) {
return 0;
} else if (left.gt(right)) {
return 1;
} else {
return -1;
}
return compare(a.startTimestamp, b.startTimestamp);
});
return { snapshotInfos, sortedConditions };
}
@@ -328,41 +381,106 @@ export async function processClaimConditionInputs(
* @param c
* @param tokenDecimals
* @param provider
* @param storage
* @internal
*/
async function convertToContractModel(
c: FilledConditionInput,
tokenDecimals: number,
provider: providers.Provider,
): Promise<IDropClaimCondition.ClaimConditionStruct> {
storage: ThirdwebStorage,
): Promise<AbstractClaimConditionContractStruct> {
const currency =
c.currencyAddress === constants.AddressZero
? NATIVE_TOKEN_ADDRESS
: c.currencyAddress;
let maxClaimableSupply;
let quantityLimitPerTransaction;
if (c.maxQuantity === "unlimited") {
maxClaimableSupply = ethers.constants.MaxUint256.toString();
} else {
maxClaimableSupply = ethers.utils.parseUnits(c.maxQuantity, tokenDecimals);
}
if (c.quantityLimitPerTransaction === "unlimited") {
quantityLimitPerTransaction = ethers.constants.MaxUint256.toString();
} else {
quantityLimitPerTransaction = ethers.utils.parseUnits(
c.quantityLimitPerTransaction,
tokenDecimals,
);
const maxClaimableSupply = convertQuantityToBigNumber(
c.maxClaimableSupply,
tokenDecimals,
);
const maxClaimablePerWallet = convertQuantityToBigNumber(
c.maxClaimablePerWallet,
tokenDecimals,
);
let metadataOrUri;
if (c.metadata) {
if (typeof c.metadata === "string") {
metadataOrUri = c.metadata;
} else {
metadataOrUri = await storage.upload(c.metadata);
}
}
return {
startTimestamp: c.startTime,
maxClaimableSupply,
supplyClaimed: 0,
quantityLimitPerTransaction,
waitTimeInSecondsBetweenClaims: c.waitInSeconds,
maxClaimablePerWallet,
pricePerToken: await normalizePriceValue(provider, c.price, currency),
currency,
merkleRoot: c.merkleRootHash,
merkleRoot: c.merkleRootHash.toString(),
waitTimeInSecondsBetweenClaims: c.waitInSeconds || 0,
metadata: metadataOrUri,
};
}
export function abstractContractModelToLegacy(
model: AbstractClaimConditionContractStruct,
): IDropClaimCondition_V2.ClaimConditionStruct {
return {
startTimestamp: model.startTimestamp,
maxClaimableSupply: model.maxClaimableSupply,
supplyClaimed: model.supplyClaimed,
merkleRoot: model.merkleRoot,
pricePerToken: model.pricePerToken,
currency: model.currency,
quantityLimitPerTransaction: model.maxClaimablePerWallet,
waitTimeInSecondsBetweenClaims: model.waitTimeInSecondsBetweenClaims || 0,
};
}
export function abstractContractModelToNew(
model: AbstractClaimConditionContractStruct,
): IClaimCondition.ClaimConditionStruct {
return {
startTimestamp: model.startTimestamp,
maxClaimableSupply: model.maxClaimableSupply,
supplyClaimed: model.supplyClaimed,
merkleRoot: model.merkleRoot,
pricePerToken: model.pricePerToken,
currency: model.currency,
quantityLimitPerWallet: model.maxClaimablePerWallet,
metadata: model.metadata || "",
};
}
export function legacyContractModelToAbstract(
model: IDropClaimCondition_V2.ClaimConditionStruct,
): AbstractClaimConditionContractStruct {
return {
startTimestamp: model.startTimestamp,
maxClaimableSupply: model.maxClaimableSupply,
supplyClaimed: model.supplyClaimed,
merkleRoot: model.merkleRoot.toString(),
pricePerToken: model.pricePerToken,
currency: model.currency,
maxClaimablePerWallet: model.quantityLimitPerTransaction,
waitTimeInSecondsBetweenClaims: model.waitTimeInSecondsBetweenClaims,
};
}
export function newContractModelToAbstract(
model: IClaimCondition.ClaimConditionStruct,
): AbstractClaimConditionContractStruct {
return {
startTimestamp: model.startTimestamp,
maxClaimableSupply: model.maxClaimableSupply,
supplyClaimed: model.supplyClaimed,
merkleRoot: model.merkleRoot.toString(),
pricePerToken: model.pricePerToken,
currency: model.currency,
maxClaimablePerWallet: model.quantityLimitPerWallet,
waitTimeInSecondsBetweenClaims: 0,
metadata: model.metadata,
};
}
@@ -373,10 +491,11 @@ async function convertToContractModel(
* @param provider
* @param merkleMetadata
* @param storage
* @param shouldDownloadSnapshot
* @internal
*/
export async function transformResultToClaimCondition(
pm: IDropClaimCondition.ClaimConditionStructOutput,
pm: AbstractClaimConditionContractStruct,
tokenDecimals: number,
provider: providers.Provider,
merkleMetadata: Record<string, string> | undefined,
@@ -389,8 +508,8 @@ export async function transformResultToClaimCondition(
pm.maxClaimableSupply,
tokenDecimals,
);
const quantityLimitPerTransaction = convertToReadableQuantity(
pm.quantityLimitPerTransaction,
const maxClaimablePerWallet = convertToReadableQuantity(
pm.maxClaimablePerWallet,
tokenDecimals,
);
const availableSupply = convertToReadableQuantity(
@@ -401,13 +520,17 @@ export async function transformResultToClaimCondition(
pm.supplyClaimed,
tokenDecimals,
);
let resolvedMetadata;
if (pm.metadata) {
resolvedMetadata = await storage.downloadJSON(pm.metadata);
}
return ClaimConditionOutputSchema.parse({
startTime: pm.startTimestamp,
maxQuantity: maxClaimableSupply,
maxClaimableSupply,
maxClaimablePerWallet,
currentMintSupply,
availableSupply,
quantityLimitPerTransaction,
waitInSeconds: pm.waitTimeInSecondsBetweenClaims.toString(),
waitInSeconds: pm.waitTimeInSecondsBetweenClaims?.toString(),
price: BigNumber.from(pm.pricePerToken),
currency: pm.currency,
currencyAddress: pm.currency,
@@ -416,10 +539,19 @@ export async function transformResultToClaimCondition(
snapshot: shouldDownloadSnapshot
? await fetchSnapshot(pm.merkleRoot, merkleMetadata, storage)
: undefined,
metadata: resolvedMetadata,
});
}
function convertToReadableQuantity(bn: BigNumber, tokenDecimals: number) {
/**
* @internal
* @param bn
* @param tokenDecimals
*/
export function convertToReadableQuantity(
bn: BigNumberish,
tokenDecimals: number,
) {
if (bn.toString() === ethers.constants.MaxUint256.toString()) {
return "unlimited";
} else {
@@ -427,6 +559,22 @@ function convertToReadableQuantity(bn: BigNumber, tokenDecimals: number) {
}
}
/**
* @internal
* @param quantity
* @param tokenDecimals
*/
export function convertQuantityToBigNumber(
quantity: Quantity,
tokenDecimals: number,
) {
if (quantity === "unlimited") {
return ethers.constants.MaxUint256;
} else {
return ethers.utils.parseUnits(quantity, tokenDecimals);
}
}
export async function calculateClaimCost(
contractWrapper: ContractWrapper<any>,
pricePerToken: Price,
+42 -3
View File
@@ -1,9 +1,9 @@
import { AmountSchema } from "../../core/schema/shared";
import {
getNativeTokenByChainId,
NATIVE_TOKEN_ADDRESS,
} from "../constants/currency";
import { ContractWrapper } from "../core/classes/contract-wrapper";
import { AmountSchema } from "../schema/shared";
import { Amount, Currency, CurrencyValue, Price } from "../types/currency";
import { BaseERC20 } from "../types/eips";
import type { IERC20, IERC20Metadata } from "@thirdweb-dev/contracts-js";
@@ -33,6 +33,14 @@ export function cleanCurrencyAddress(currencyAddress: string): string {
return currencyAddress;
}
/**
*
* @param provider
* @param inputPrice
* @param currencyAddress
* @returns
* @internal
*/
export async function normalizePriceValue(
provider: providers.Provider,
inputPrice: Price,
@@ -42,6 +50,13 @@ export async function normalizePriceValue(
return utils.parseUnits(AmountSchema.parse(inputPrice), metadata.decimals);
}
/**
*
* @param provider
* @param asset
* @returns
* @internal
*/
export async function fetchCurrencyMetadata(
provider: providers.Provider,
asset: string,
@@ -73,6 +88,14 @@ export async function fetchCurrencyMetadata(
}
}
/**
*
* @param providerOrSigner
* @param asset
* @param price
* @returns
* @internal
*/
export async function fetchCurrencyValue(
providerOrSigner: providers.Provider,
asset: string,
@@ -101,7 +124,7 @@ export async function setErc20Allowance(
signer || provider,
currencyAddress,
ERC20Abi,
{},
contractToApprove.options,
);
const owner = await contractToApprove.getSignerAddress();
@@ -128,7 +151,7 @@ export async function approveErc20Allowance(
signer || provider,
currencyAddress,
ERC20Abi,
{},
contractToApprove.options,
);
const owner = await contractToApprove.getSignerAddress();
const spender = contractToApprove.readContract.address;
@@ -169,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);
}
+9 -10
View File
@@ -394,20 +394,16 @@ export async function convertToTWError(
contractInterface: ethers.utils.Interface,
): Promise<TransactionError> {
let raw: string;
if (error.data) {
if (typeof error === "object") {
// metamask errors comes as objects, apply parsing on data object
// TODO test errors from other wallets
raw = JSON.stringify(error.data);
} else if (error instanceof Error) {
// regular ethers.js error
raw = error.message;
raw = JSON.stringify(error);
} else {
// not sure what this is, just throw it back
raw = error.toString();
}
const reason =
error.reason ||
parseMessageParts(/.*?"message[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
parseMessageParts(/.*?"message[^a-zA-Z0-9]*([^"\\]*).*?/, raw) ||
parseMessageParts(/.*?"reason[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
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);
@@ -459,9 +455,12 @@ function parseMessageParts(regex: RegExp, raw: string): string {
* @param message
*/
export function includesErrorMessage(err: any, message: string): boolean {
if (!err) {
return false;
}
return (
(err && err.toString().includes(message)) ||
(err.message && err.message.toString().includes(message)) ||
(err.error && err.error.toString().includes(message))
(err && err.message && err.message.toString().includes(message)) ||
(err && err.error && err.error.toString().includes(message))
);
}

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