Compare commits

...
Author SHA1 Message Date
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
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
2e8d3fd6e7 Version Packages (#358)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-10-28 18:14:35 -07:00
Nacho IacovinoandGitHub cc4613b5fd [React] Add Pack and Multiwrap as NFTContract types (#356) 2022-10-29 01:28:40 +02:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
78566babaa Version Packages (#354)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-10-28 10:29:57 -07:00
Joaquim VergesandGitHub 65fc7ba6ff [SDK] Expose claimCondtions.getClaimerProofs(address) (#357) 2022-10-28 10:25:36 -07:00
Nacho IacovinoandGitHub 1c24c3c3c4 [Multi] Add useUpdateCreator hook, fix CreatorInput schema (#353) 2022-10-26 18:19:32 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
408c5a81fa Version Packages (#347)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-10-26 08:38:25 -07:00
Joaquim VergesandGitHub 352291791e [SDK, React] expose marketplace.auction.executeSale (#352) 2022-10-26 00:19:01 +00:00
Jonas DanielsandGitHub aabbb149e8 [React] - fix wallet connection during hot reload (#351) 2022-10-25 22:48:39 +00:00
Jonas DanielsandGitHub d59450f814 do not release e2e tests (#350) 2022-10-25 20:29:22 +00:00
7d9a4c6abc Update name of useRoyalty, and update (#348)
Co-authored-by: Jonas Daniels <[email protected]>
2022-10-25 19:56:09 +00:00
Jonas DanielsandGitHub 99806e595d [VARIOUS] - exclude sizes of test files etc (#349) 2022-10-25 18:39:30 +00:00
Nacho IacovinoandGitHub 21c21c1adf resolveReleasesFromAddress -> resolveContractUriFromAddress (#344) 2022-10-24 23:43:43 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
4b10719047 Version Packages (#345)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-10-24 16:18:44 -07:00
Joaquim VergesandGitHub 989cf7347c [React, SDK] Small fixes for useOffers and makeOffers (#346) 2022-10-24 23:09:32 +00:00
Joaquim VergesandGitHub 72227b2e16 [SDK, React] Expose new useOffers and useMakeOffer hooks (#343) 2022-10-24 15:28:34 -07:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
ed6c54f20d Version Packages (#336)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-10-21 13:26:24 -07:00
Joaquim VergesandGitHub 26116a6f63 [SDK] Update to new univeral RPC endpoint (#342) 2022-10-21 13:21:11 -07:00
Jonas DanielsandGitHub f11a2719ff [workflow] github hosted runners (#340) 2022-10-20 22:02:58 -07:00
Jonas DanielsandGitHub ef27aad0aa [Various, React] - add initial e2e testing setup (#327) 2022-10-21 04:19:04 +00:00
Nacho IacovinoandGitHub b03a902145 [React] Docs update (#339) 2022-10-20 20:17:01 -07:00
Adam MajmudarandGitHub 340605b507 Clean native token address in changeset (#337) 2022-10-20 23:57:55 +00:00
Adam MajmudarandGitHub 15f8006e1f Export smart contract (#335) 2022-10-20 23:46:02 +00:00
Adam MajmudarandGitHub 811c5a1166 Update code snippets for signature minting (#334) 2022-10-20 23:29:07 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
c41a80d86d Version Packages (#331)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-10-20 15:35:12 -07:00
Joaquim VergesandGitHub ad851f7b4d [SDK] Fix for finding addresses in legacy merkle tree format (#332) 2022-10-20 21:35:52 +00:00
Joaquim VergesandGitHub 6218c88584 [SDK] Fix for deploy byte parameters (#330) 2022-10-20 04:47:55 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
c9b564feaf Version Packages (#323)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-10-19 21:19:06 -07:00
Adam MajmudarandGitHub 87fd6ab14e Update storage download on fail (#324) 2022-10-19 12:44:36 -07:00
Joaquim VergesandGitHub df74340fa5 [SDK] Import cbor-x fully for es builds (#328) 2022-10-19 17:46:54 +00:00
Joaquim VergesandGitHub a57b4f01f3 [SDK] Implement sharded merkle trees for lightweight allowlist checks (#321) 2022-10-19 16:54:09 +00:00
Jonas DanielsandGitHub 126752d7d0 [Various] - clean up extraneous dependencies (#326) 2022-10-18 23:56:04 -07:00
89ff921a7d Fix vite (#315)
Co-authored-by: Jonas Daniels <[email protected]>
Co-authored-by: Joaquim Verges <[email protected]>
2022-10-18 15:23:57 -07:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
9124b3180c Version Packages (#308)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-10-18 15:02:14 -07:00
Adam MajmudarandGitHub f41a443c57 Add update creators and update royalty (#320) 2022-10-18 21:50:47 +00:00
Joaquim VergesandGitHub b7cd744cd0 [SDK] Sign multiple solana claims at once (#322) 2022-10-18 21:35:03 +00:00
bb1b4e6ac3 [React] Add useMinimumNextBid hook (#318)
Co-authored-by: Jonas Daniels <[email protected]>
2022-10-18 11:57:26 -07:00
2f8ec89c4c [SDK, React] Expose total claimed/unclaimed supply for erc721 contracts (#319)
Co-authored-by: Nacho Iacovino <[email protected]>
2022-10-17 18:17:54 -07:00
Joaquim VergesandGitHub 6ae52664e5 [React] Fix passing wrong RPC url to UserWallet when using an external signer (#316) 2022-10-17 22:26:15 +00:00
Adam MajmudarandGitHub 4f867e15ed Fix supply in nft.get() (#317) 2022-10-17 19:17:43 +00:00
cc8f983615 fix typo (#314)
Co-authored-by: Joaquim Verges <[email protected]>
2022-10-16 22:27:40 +00:00
Joaquim VergesandGitHub f45ef62128 [SDK] return fallback metadata when tokenId is not found on nft contract (#313) 2022-10-16 15:15:26 -07:00
9727502eb3 Add useMintNFTSupply hook (#310)
Co-authored-by: Jonas Daniels <[email protected]>
2022-10-14 13:32:43 -07:00
Adam MajmudarandGitHub b6eec6146c [Solana] Add quantity to mint additional supply (#312) 2022-10-14 19:23:07 +00:00
88daa3c5cb [SDK] Check for undefined ABI (#309)
Co-authored-by: Joaquim Verges <[email protected]>
2022-10-14 03:37:40 +00:00
Adam MajmudarandGitHub 53c6507669 Add deploy event listener (#306) 2022-10-13 21:28:24 +00:00
YashandGitHub 782b58d3f6 [SDK] Fix multicall txns in a gasless setup (#307) 2022-10-13 11:57:02 -07:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
e17e41f4d1 Version Packages (#304)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-10-12 15:22:33 -07:00
Joaquim VergesandGitHub 712b11a43e [SDK] Fix not getting real owner of Solana NFTs (#303) 2022-10-12 22:12:53 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
306debb029 Version Packages (#302)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2022-10-12 10:57:32 -07:00
Joaquim VergesandGitHub 86f0ceff46 [React] Remove useAddress hook for now (#301) 2022-10-12 17:54:14 +00:00
343 changed files with 24204 additions and 7116 deletions
+1 -1
View File
@@ -7,7 +7,7 @@
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": [],
"ignore": ["e2e-cra-5", "e2e-next-12", "e2e-vite-3"],
"___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
"updateInternalDependents": "always",
"onlyUpdatePeerDependentsWhenOutOfRange": true
+1 -1
View File
@@ -9,7 +9,7 @@ runs:
with:
node-version: 16
registry-url: "https://registry.npmjs.org"
# cache: "yarn"
cache: "yarn"
- name: Install dependencies
shell: bash
+1 -2
View File
@@ -14,8 +14,7 @@ jobs:
build:
name: Build and Test
# timeout-minutes: 15
# try out buildjet to speed up build and test
runs-on: buildjet-32vcpu-ubuntu-2204
runs-on: ubuntu-latest-32
# To use Remote Caching, uncomment the next lines and follow the steps below.
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
+1 -8
View File
@@ -13,8 +13,7 @@ concurrency:
jobs:
integration-tests:
timeout-minutes: 60
# try out buildjet to speed up build and test
runs-on: buildjet-32vcpu-ubuntu-2204
runs-on: ubuntu-latest-32
steps:
- uses: actions/checkout@v3
@@ -28,9 +27,3 @@ jobs:
run: yarn e2e
env:
NODE_OPTIONS: "--max_old_space_size=4096"
- uses: actions/upload-artifact@v2
if: always()
with:
name: playwright-report
path: packages/react/playwright-report/
retention-days: 30
+1 -2
View File
@@ -40,8 +40,7 @@ jobs:
comment_body: ${{ github.event.comment.body }}
deploy:
# try out buildjet to speed up build and test
runs-on: buildjet-32vcpu-ubuntu-2204
runs-on: ubuntu-latest-32
needs: deploy-check
if: needs.deploy-check.outputs.triggered == 'true'
steps:
+1 -2
View File
@@ -14,8 +14,7 @@ concurrency:
jobs:
release:
name: Release
# try out buildjet to speed up build and test
runs-on: buildjet-32vcpu-ubuntu-2204
runs-on: ubuntu-latest-32
steps:
- name: Checkout branch
uses: actions/checkout@v3
+3 -2
View File
@@ -4,8 +4,7 @@ on: [pull_request]
jobs:
build:
# try out buildjet to speed up build and test
runs-on: buildjet-32vcpu-ubuntu-2204
runs-on: ubuntu-latest-32
steps:
- uses: actions/checkout@v3
@@ -16,3 +15,5 @@ jobs:
repo-token: "${{ secrets.GITHUB_TOKEN }}"
strip-hash: "\\-(\\w{8})(?:\\.esm|\\.cjs)"
minimum-change-threshold: 100
# exclude source maps, node modules and any test related files
exclude: "{**/*.map,**/node_modules/**,**/test/**}"
+6 -1
View File
@@ -12,4 +12,9 @@ server/dist
public/dist
.turbo
./packages/contracts-js/abis
.idea/
.idea/
.yalc/
yalc.lock
build/
playwright-report/
.vscode/
-1
View File
@@ -1,4 +1,3 @@
lib
node_modules
dist
contracts-js
-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.
+5 -9
View File
@@ -8,14 +8,15 @@
"private": true,
"workspaces": {
"packages": [
"packages/*"
"packages/*",
"test/**/*"
]
},
"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",
@@ -27,12 +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"
},
"preconstruct": {
"packages": [
"packages/*"
]
"push": "turbo run push --filter=./packages/*"
},
"packageManager": "[email protected]",
"dependencies": {
+50
View File
@@ -1,5 +1,55 @@
# @thirdweb-dev/auth
## 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.0.23
## 2.0.22
## 2.0.21
### Patch Changes
- [#327](https://github.com/thirdweb-dev/js/pull/327) [`ef27aad`](https://github.com/thirdweb-dev/js/commit/ef27aad0aafc4577e85f44dc77dfbe880bd239b5) Thanks [@jnsdls](https://github.com/jnsdls)! - enable e2e testing
## 2.0.20
## 2.0.19
## 2.0.18
## 2.0.17
## 2.0.16
## 2.0.15
## 2.0.14
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "2.0.15",
"version": "2.0.34",
"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",
}),
);
+161
View File
@@ -1,5 +1,166 @@
# thirdweb
## 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
- Updated dependencies []:
- @thirdweb-dev/sdk@3.4.4
## 0.8.10
### Patch Changes
- Updated dependencies [[`1c24c3c`](https://github.com/thirdweb-dev/js/commit/1c24c3c3c48476a824f817e09e7bf0fbe67c1db5), [`65fc7ba`](https://github.com/thirdweb-dev/js/commit/65fc7ba6fff093a971b53cb0979c39768e090ba1)]:
- @thirdweb-dev/sdk@3.4.3
## 0.8.9
### Patch Changes
- Updated dependencies [[`21c21c1`](https://github.com/thirdweb-dev/js/commit/21c21c1adfd09b60ad563bfd4c308597140de33c), [`3522917`](https://github.com/thirdweb-dev/js/commit/352291791ee900e1500f84f095290497934d2f60)]:
- @thirdweb-dev/sdk@3.4.2
## 0.8.8
### Patch Changes
- Updated dependencies [[`72227b2`](https://github.com/thirdweb-dev/js/commit/72227b2e166a3a68bbb41cf2b389322f5b7547a2)]:
- @thirdweb-dev/sdk@3.4.1
## 0.8.7
### Patch Changes
- [#327](https://github.com/thirdweb-dev/js/pull/327) [`ef27aad`](https://github.com/thirdweb-dev/js/commit/ef27aad0aafc4577e85f44dc77dfbe880bd239b5) Thanks [@jnsdls](https://github.com/jnsdls)! - enable e2e testing
- Updated dependencies [[`340605b`](https://github.com/thirdweb-dev/js/commit/340605b507f384fbd2999b9c16542af3c53e84a9), [`26116a6`](https://github.com/thirdweb-dev/js/commit/26116a6f637ee845f7bd17f20ffe17caf184658e), [`15f8006`](https://github.com/thirdweb-dev/js/commit/15f8006e1fb22333b7ee239b45e7b1b12d6dccc8), [`ef27aad`](https://github.com/thirdweb-dev/js/commit/ef27aad0aafc4577e85f44dc77dfbe880bd239b5)]:
- @thirdweb-dev/sdk@3.4.0
## 0.8.6
### Patch Changes
- Updated dependencies [[`ad851f7`](https://github.com/thirdweb-dev/js/commit/ad851f7b4d6abb5ab9364ef3dec229f913e18ce5), [`6218c88`](https://github.com/thirdweb-dev/js/commit/6218c885842e6b4e44ec38ec92a9211e56c49bf4)]:
- @thirdweb-dev/sdk@3.3.1
## 0.8.5
### Patch Changes
- [#326](https://github.com/thirdweb-dev/js/pull/326) [`126752d`](https://github.com/thirdweb-dev/js/commit/126752d7d02c9a808a63fb9e67a9df6658b5682b) Thanks [@jnsdls](https://github.com/jnsdls)! - remove tons of unused dependencies, use SDK function for extracting ipfs has from bytecode
- Updated dependencies [[`126752d`](https://github.com/thirdweb-dev/js/commit/126752d7d02c9a808a63fb9e67a9df6658b5682b), [`df74340`](https://github.com/thirdweb-dev/js/commit/df74340fa51323304c32419761d6f18628b060fa), [`89ff921`](https://github.com/thirdweb-dev/js/commit/89ff921a7d9f0e42b4e6707c8b56d0aab95c1aa0), [`a57b4f0`](https://github.com/thirdweb-dev/js/commit/a57b4f01f3a49590b897101f2730582e4124a554)]:
- @thirdweb-dev/sdk@3.3.0
## 0.8.4
### Patch Changes
- Updated dependencies [[`4f867e1`](https://github.com/thirdweb-dev/js/commit/4f867e15edbe5757afbf54cab207458711a8986c), [`b6eec61`](https://github.com/thirdweb-dev/js/commit/b6eec6146c23b66a3681bbb48b173b9019254214), [`9727502`](https://github.com/thirdweb-dev/js/commit/9727502eb30ac139382b7c7c8e8fc0967cbfbcf1), [`782b58d`](https://github.com/thirdweb-dev/js/commit/782b58d3f6a3b49ff9b3d837551db5161f96171a), [`f41a443`](https://github.com/thirdweb-dev/js/commit/f41a443c5785240197607b5bf93ff18a1c8e8307), [`f45ef62`](https://github.com/thirdweb-dev/js/commit/f45ef62128cfefe06275a38440c90d45e9f3cef7), [`2f8ec89`](https://github.com/thirdweb-dev/js/commit/2f8ec89c4c83ae577092c840c198e6fcfb114e69), [`b7cd744`](https://github.com/thirdweb-dev/js/commit/b7cd744cd0482a6c3fe5ae0c858f20cd380d4114), [`53c6507`](https://github.com/thirdweb-dev/js/commit/53c65076696a43bd9a7e58a7493d4e65c172900f)]:
- @thirdweb-dev/sdk@3.2.6
## 0.8.3
### Patch Changes
- Updated dependencies [[`712b11a`](https://github.com/thirdweb-dev/js/commit/712b11a43e389ae10b7f09648779a69c05b2c913)]:
- @thirdweb-dev/sdk@3.2.5
## 0.8.2
### Patch Changes
- Updated dependencies []:
- @thirdweb-dev/sdk@3.2.4
## 0.8.1
### Patch Changes
+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/",
);
+4 -11
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.8.1",
"version": "0.9.2",
"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",
@@ -31,24 +31,17 @@
"dependencies": {
"@thirdweb-dev/sdk": "*",
"async-retry": "^1.3.3",
"cbor": "^8.1.0",
"commander": "^9.1.0",
"cpy": "^9.0.1",
"enquirer": "^2.3.6",
"ethers": "^5.7.0",
"form-data": "^4.0.0",
"ethers": "^5.7.2",
"got": "11.8.5",
"inquirer": "^8.2.3",
"ipfs-unixfs": "^6.0.7",
"ipld-dag-pb": "^0.22.3",
"multihashes": "^4.0.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-check": "^1.5.4",
"update-notifier": "^6.0.2",
"validate-npm-package-name": "^4.0.0",
"yaml": "^2.1.1"
+81 -48
View File
@@ -4,7 +4,7 @@ import { processProject } from "../common/processor";
import { cliVersion, pkg } from "../constants/urls";
import { info, logger } from "../core/helpers/logger";
import { twCreate } from "../create/command";
import generateDashboardUrl from "../helpers/generate-dashboard-url";
import { deploy } from "../deploy";
import { upload } from "../storage/command";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import chalk from "chalk";
@@ -40,34 +40,40 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
.version(cliVersion, "-v, --version");
program
.command("create")
.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 (options) => {
await twCreate(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
+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;
@@ -1,7 +1,7 @@
import { extractIPFSHashFromBytecode } from "../helpers/ipfs";
import { logger } from "../helpers/logger";
import { CompileOptions, IBuilder } from "../interfaces/Builder";
import { ContractPayload } from "../interfaces/ContractPayload";
import { extractIPFSHashFromBytecode } from "@thirdweb-dev/sdk/evm";
export abstract class BaseBuilder implements IBuilder {
abstract compile(
+6
View File
@@ -88,6 +88,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 +104,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");
}
}
-66
View File
@@ -1,66 +0,0 @@
import { decodeFirstSync } from "cbor";
import { UnixFS } from "ipfs-unixfs";
import { DAGNode } from "ipld-dag-pb";
import { toB58String } from "multihashes";
/**
* Derives IPFS hash of string
* @param {String} str
* @return {String} IPFS hash (ex: "Qm")
*/
export async function getIPFSHash(str: string) {
const file = new UnixFS({
type: "file",
data: Buffer.from(str),
});
const node = new DAGNode(file.marshal());
const metadataLink = await node.toDAGLink();
return toB58String(metadataLink.Hash.multihash);
}
/**
* Extract the IPFS hash from the given bytecode
* @param bytecode
* @returns
*/
export function extractIPFSHashFromBytecode(
bytecode: string,
): string | undefined {
const numericBytecode = hexToBytes(bytecode);
const cborLength: number =
numericBytecode[numericBytecode.length - 2] * 0x100 +
numericBytecode[numericBytecode.length - 1];
const bytecodeBuffer = Buffer.from(
numericBytecode.slice(numericBytecode.length - 2 - cborLength, -2),
);
const cborData = decodeFirstSync(bytecodeBuffer);
if (cborData["ipfs"]) {
const uri = toB58String(cborData["ipfs"]);
return uri;
}
return undefined;
}
function hexToBytes(hex: string | number) {
hex = hex.toString(16);
if (!hex.startsWith("0x")) {
hex = `0x${hex}`;
}
if (!isHexStrict(hex)) {
throw new Error('Given value "' + hex + '" is not a valid hex string.');
}
hex = hex.replace(/^0x/i, "");
for (var bytes = [], c = 0; c < hex.length; c += 2) {
bytes.push(parseInt(hex.slice(c, c + 2), 16));
}
return bytes;
}
function isHexStrict(hex: string | number) {
return (
(typeof hex === "string" || typeof hex === "number") &&
/^(-)?0x[0-9a-f]*$/i.test(hex.toString())
);
}
@@ -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";
+265 -134
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(options: any) {
if (typeof projectPath === "string") {
projectPath = projectPath.trim();
export async function twCreate(
pType: string,
pPath: string = "",
options: any,
) {
if (typeof pPath === "string") {
projectPath = pPath;
}
if (options.app) {
if (typeof options.contractName === "string") {
contractName = options.contractName;
}
if (pType === "app" || options.app) {
projectType = "app";
}
if (options.contract) {
} 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(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(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(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(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) {
@@ -11,22 +11,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 +46,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 +58,165 @@ 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),
} else {
// Otherwise, create a new contracts project
const projectName = path.basename(root);
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();
console.log("Installing packages. This might take a couple of minutes.");
console.log();
process.chdir(root);
await install(root, null, { packageManager, isOnline });
console.log();
function isErrorLike(err: unknown): err is { message: string } {
return (
typeof err === "object" &&
err !== null &&
typeof (err as { message?: unknown }).message === "string"
);
}
if (tryGitInit(root)) {
console.log("Initialized a git repository.");
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") {
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();
}
+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();
}
@@ -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"
},
+2 -1
View File
@@ -11,7 +11,8 @@ module.exports = {
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-non-null-assertion": "error",
"@typescript-eslint/no-parameter-properties": "error",
"@typescript-eslint/no-unused-vars": "warn",
// making this an error going forward
"@typescript-eslint/no-unused-vars": "error",
// import rules
"import/first": "error",
+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"
+143
View File
@@ -1,5 +1,148 @@
# @thirdweb-dev/react
## 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
- [#356](https://github.com/thirdweb-dev/js/pull/356) [`cc4613b`](https://github.com/thirdweb-dev/js/commit/cc4613b5fd69840f4f9cfd0ac1c4e6743e62fe52) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add Pack and Multiwrap as NFTContract types
## 3.4.3
### Patch Changes
- [#353](https://github.com/thirdweb-dev/js/pull/353) [`1c24c3c`](https://github.com/thirdweb-dev/js/commit/1c24c3c3c48476a824f817e09e7bf0fbe67c1db5) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add useUpdateCreators hook, fix CreatorInput schema
## 3.4.2
### Patch Changes
- [#348](https://github.com/thirdweb-dev/js/pull/348) [`7d9a4c6`](https://github.com/thirdweb-dev/js/commit/7d9a4c6abcad1b4f43e431ce7b0b38db9016ea9a) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - [SOL] - add `useUpdateRoyaltySettings()` hook
[SOL] - change `useRoyalty()` hook -> `useRoyaltySettings()` for consistency
- [#352](https://github.com/thirdweb-dev/js/pull/352) [`3522917`](https://github.com/thirdweb-dev/js/commit/352291791ee900e1500f84f095290497934d2f60) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - expose useExecuteAuctionSale and useAcceptDirectListingOffer
- [#351](https://github.com/thirdweb-dev/js/pull/351) [`aabbb14`](https://github.com/thirdweb-dev/js/commit/aabbb149e81d6824015a4797b2b6c929ca359545) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - fix wallet connection during dev (hot reload)
## 3.4.1
### Patch Changes
- [#343](https://github.com/thirdweb-dev/js/pull/343) [`72227b2`](https://github.com/thirdweb-dev/js/commit/72227b2e166a3a68bbb41cf2b389322f5b7547a2) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose new useOffers and useMakeOffer hooks
## 3.4.0
### Minor Changes
- [#327](https://github.com/thirdweb-dev/js/pull/327) [`ef27aad`](https://github.com/thirdweb-dev/js/commit/ef27aad0aafc4577e85f44dc77dfbe880bd239b5) Thanks [@jnsdls](https://github.com/jnsdls)! - Gnosis Safe and Magic Link connectors are no longer included in the default export. They are now available as named exports instead.
## Gnosis Safe
### Connector
```diff
- import { GnosisSafeConnector } from "@thirdweb-dev/react";
+ import { GnosisSafeConnector } from "@thirdweb-dev/react/evm/connectors/gnosis-safe";
```
### Hook
```diff
- import { useGnosis } from "@thirdweb-dev/react";
+ import { useGnosis } from "@thirdweb-dev/react/evm/connectors/gnosis-safe";
```
## Magic Link
### Connector
```diff
- import { MagicLink } from "@thirdweb-dev/react";
+ import { MagicConnector } from "@thirdweb-dev/react/evm/connectors/magic";
```
### Hook
```diff
- import { useMagic } from "@thirdweb-dev/react";
+ import { useMagic } from "@thirdweb-dev/react/evm/connectors/magic";
```
### Patch Changes
- [#339](https://github.com/thirdweb-dev/js/pull/339) [`b03a902`](https://github.com/thirdweb-dev/js/commit/b03a9021451b79f802f682f66e5ae8e9355d7e6f) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix docs for some functions
## 3.3.1
## 3.3.0
## 3.2.6
### Patch Changes
- [#316](https://github.com/thirdweb-dev/js/pull/316) [`6ae5266`](https://github.com/thirdweb-dev/js/commit/6ae52664e5865564cd4fc2e00e3120675b9e0ca3) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix SIWE when using an external signer
- [#310](https://github.com/thirdweb-dev/js/pull/310) [`9727502`](https://github.com/thirdweb-dev/js/commit/9727502eb30ac139382b7c7c8e8fc0967cbfbcf1) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - [SOL] - add useMintNFTSupply hook in react and accomodate inputs for it in SDK
- [#319](https://github.com/thirdweb-dev/js/pull/319) [`2f8ec89`](https://github.com/thirdweb-dev/js/commit/2f8ec89c4c83ae577092c840c198e6fcfb114e69) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose total claimed and unclaimed supply for erc721 drop contracts
- [#318](https://github.com/thirdweb-dev/js/pull/318) [`bb1b4e6`](https://github.com/thirdweb-dev/js/commit/bb1b4e6ac39d98cc68b8e31e659cd68be3a5b967) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add useMinimumNextBid hook and change invariant for other marketplace hooks
## 3.2.5
## 3.2.4
### Patch Changes
- [#301](https://github.com/thirdweb-dev/js/pull/301) [`86f0cef`](https://github.com/thirdweb-dev/js/commit/86f0ceff46f72df8ebd81f843e3c66a245f23992) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Remove useAddress hook for now
## 3.2.3
### Patch Changes
+2 -2
View File
@@ -26,11 +26,11 @@ The `useContractCall` hook to call a smart contract function has been renamed to
### Prebuilt Contract Hooks
Hooks to connect to prebuilt contracts such as `useNFTDrop` and `useMarketplace` are now deprecated in favour of using the generic `useContract` hook:
Hooks to connect to prebuilt contracts such as `useNFTDrop` and `useMarketplace` are now deprecated in favour of using the generic `useContract` hook followed by the contract type:
```diff
- const contract = useNFTDrop("0x...")
+ const { contract } = useContract("0x...")
+ const { contract } = useContract("0x...", "nft-drop")
```
You can currently still continue to use the prebuilt hooks, however they provide a warning in the console informing you of their deprecation. We will likely remove these hooks in a future version of the SDK.
+1 -1
View File
@@ -191,7 +191,7 @@ export default function Home() {
<div>
{nfts.map((nft) => (
<ThirdwebNftMedia
key={nft.tokenId}
key={nft.metadata.id}
metadata={nft.metadata}
height={200}
/>
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-react-evm-connectors-gnosis-safe.cjs.js",
"module": "dist/thirdweb-dev-react-evm-connectors-gnosis-safe.esm.js"
}
@@ -0,0 +1,4 @@
{
"main": "dist/thirdweb-dev-react-evm-connectors-magic.cjs.js",
"module": "dist/thirdweb-dev-react-evm-connectors-magic.esm.js"
}
+21 -19
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "3.2.3",
"version": "3.6.4",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -20,6 +20,14 @@
"module": "./solana/dist/thirdweb-dev-react-solana.esm.js",
"default": "./solana/dist/thirdweb-dev-react-solana.cjs.js"
},
"./evm/connectors/magic": {
"module": "./evm/connectors/magic/dist/thirdweb-dev-react-evm-connectors-magic.esm.js",
"default": "./evm/connectors/magic/dist/thirdweb-dev-react-evm-connectors-magic.cjs.js"
},
"./evm/connectors/gnosis-safe": {
"module": "./evm/connectors/gnosis-safe/dist/thirdweb-dev-react-evm-connectors-gnosis-safe.esm.js",
"default": "./evm/connectors/gnosis-safe/dist/thirdweb-dev-react-evm-connectors-gnosis-safe.cjs.js"
},
"./package.json": "./package.json"
},
"files": [
@@ -31,7 +39,8 @@
"entrypoints": [
"index.ts",
"solana/index.ts",
"evm/index.ts"
"evm/index.ts",
"evm/connectors/**.ts"
],
"___experimentalFlags_WILL_CHANGE_IN_PATCH": {
"exports": true
@@ -49,13 +58,11 @@
"generate-docs:solana": "api-extractor run --local --config ./config/api-extractor-solana.json && api-documenter markdown -i ./temp -o ./docs/solana && rm -rf ./temp-solana && mv ./temp ./temp-solana",
"generate-snippets": "node ./scripts/generate-snippets-evm.mjs && node ./scripts/generate-snippets-solana.mjs && node ./scripts/generate-feature-snippets-evm.mjs",
"build": "tsc && preconstruct build",
"e2e": "yarn test-ct",
"test-ct": "playwright test -c playwright-ct.config.ts",
"push": "yalc push"
},
"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",
@@ -63,15 +70,12 @@
"@microsoft/api-documenter": "^7.19.4",
"@microsoft/api-extractor": "^7.29.2",
"@microsoft/tsdoc": "^0.14.1",
"@playwright/experimental-ct-react": "1.25.1",
"@playwright/test": "1.25.1",
"@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.63.0",
"@solana/web3.js": "^1.62.0",
"@thirdweb-dev/sdk": "*",
"@thirdweb-dev/solana": "*",
"@types/color": "^3.0.3",
"@types/mime": "^3.0.1",
"@types/react": "^18.0.5",
@@ -84,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",
@@ -93,13 +97,14 @@
"dependencies": {
"@emotion/react": "^11.10.0",
"@emotion/styled": "^11.10.0",
"@gnosis.pm/safe-core-sdk": "2.1.0",
"@gnosis.pm/safe-ethers-adapters": "0.1.0-alpha.9",
"@gnosis.pm/safe-ethers-lib": "1.1.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",
"@solana/wallet-adapter-phantom": "^0.9.17",
"@tanstack/react-query": "^4.0.10",
"@zag-js/menu": "0.1.14",
"@zag-js/react": "0.1.16",
"@zag-js/menu": "^0.1.16",
"@zag-js/react": "^0.1.18",
"buffer": "^6.0.3",
"color": "^4.2.3",
"copy-to-clipboard": "^3.3.2",
@@ -114,7 +119,7 @@
"@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.63.0",
"@solana/web3.js": "^1.62.0",
"@thirdweb-dev/sdk": "*",
"ethers": ">=5.5.1",
"react": ">=18.0.0",
@@ -136,9 +141,6 @@
},
"@solana/web3.js": {
"optional": true
},
"@thirdweb-dev/solana": {
"optional": true
}
}
}
-57
View File
@@ -1,57 +0,0 @@
import type { PlaywrightTestConfig } from "@playwright/experimental-ct-react";
import { devices } from "@playwright/experimental-ct-react";
/**
* See https://playwright.dev/docs/test-configuration.
*/
const config: PlaywrightTestConfig = {
testDir: "./",
/* The base directory, relative to the config file, for snapshot files created with toMatchSnapshot and toHaveScreenshot. */
snapshotDir: "./__snapshots__",
/* Maximum time one test can run for. */
timeout: 10 * 1000,
/* Run tests in files in parallel */
fullyParallel: true,
/* Fail the build on CI if you accidentally left test.only in the source code. */
forbidOnly: !!process.env.CI,
/* Retry on CI only */
retries: process.env.CI ? 2 : 0,
/* Opt out of parallel tests on CI. */
// workers: process.env.CI ? 1 : undefined,
// we can use parallel tests because we have more cores now
workers: undefined,
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
reporter: "html",
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
use: {
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
trace: "on-first-retry",
/* Port to use for Playwright component endpoint. */
ctPort: 3100,
},
/* Configure projects for major browsers */
projects: [
{
name: "chromium",
use: {
...devices["Desktop Chrome"],
},
},
{
name: "firefox",
use: {
...devices["Desktop Firefox"],
},
},
{
name: "webkit",
use: {
...devices["Desktop Safari"],
},
},
],
};
export default config;
-4
View File
@@ -1,4 +0,0 @@
// Import styles, initialize component theme here.
// import '../src/common.css';
export {};
@@ -1,4 +1,4 @@
import { RequiredParam } from "../types/shared";
import { RequiredParam } from "./required-param";
import type { QueryKey } from "@tanstack/react-query";
import type { ValidContractInstance } from "@thirdweb-dev/sdk";
import type {
@@ -0,0 +1,15 @@
import invariant from "tiny-invariant";
/**
* Makes a parameter required to be passed, but still allowes it to be null or undefined.
*
* @beta
*/
export type RequiredParam<T> = T | null | undefined;
export function requiredParamInvariant<TValue>(
condition: RequiredParam<TValue>,
message?: string,
): asserts condition {
invariant(condition !== null || condition !== undefined, message);
}
-6
View File
@@ -1,6 +0,0 @@
/**
* Makes a parameter required to be passed, but still allowes it to be null or undefined.
*
* @beta
*/
export type RequiredParam<T> = T | null | undefined;
@@ -1,15 +0,0 @@
import { ConnectWallet } from ".";
import { ThirdwebProvider } from "../../providers/full";
import { test, expect } from "@playwright/experimental-ct-react";
test.use({ viewport: { width: 500, height: 500 } });
test("should render the connect wallet button", async ({ mount }) => {
const component = await mount(
<ThirdwebProvider desiredChainId={1}>
<ConnectWallet />
</ThirdwebProvider>,
);
await expect(component).toContainText("Connect Wallet");
});
@@ -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}>
@@ -144,7 +144,7 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = ({
},
connect,
] = useConnect();
const disconnect = useDisconnect({ reconnectAfterGnosis: false });
const disconnect = useDisconnect({ reconnectPrevious: false });
const supportedConnectors = connectors.filter((c) =>
SUPPORTED_CONNECTORS.includes(c.id as typeof SUPPORTED_CONNECTORS[number]),
@@ -13,12 +13,14 @@ export interface ThirdwebNftMediaProps extends SharedMediaProps {
}
/**
* This component can be used to render NFTs from the thirdweb SDK.
* Props: {@link ThirdwebNftMediaProps}
*
* @example
* ```jsx
* import { ThirdwebNftMedia, useNFTCollection, useNFT } from "@thirdweb-dev/react";
* import { ThirdwebNftMedia, useContract, useNFT } from "@thirdweb-dev/react";
* export default function NFTCollectionRender() {
* const contract = useNFTCollection(<your-contract-address>);
* const { contract } = useContract(<your-contract-address>);
* const { data: nft, isLoading } = useNFT(contract, 0);
*
* return (
@@ -32,11 +34,6 @@ export interface ThirdwebNftMediaProps extends SharedMediaProps {
* );
* }
* ```
*
* Use this to get the primary sales recipient of your {@link SmartContract}
* @param contract - an instance of a {@link SmartContract}
* @returns the wallet address of the primary sales recipient
* @beta
*/
export const ThirdwebNftMedia = React.forwardRef<
HTMLMediaElement,
@@ -1,16 +0,0 @@
import { Web3Button } from ".";
import { ThirdwebProvider } from "../../providers/full";
import { test, expect } from "@playwright/experimental-ct-react";
test.use({ viewport: { width: 500, height: 500 } });
test("should render the connect wallet button", async ({ mount }) => {
const component = await mount(
<ThirdwebProvider desiredChainId={1}>
<Web3Button contractAddress="0x123" action={() => undefined}>
Do the thing
</Web3Button>
</ThirdwebProvider>,
);
await expect(component).toContainText("Connect Wallet");
});
@@ -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;
}
`;
@@ -1,14 +1,29 @@
import { ChainId } from "@thirdweb-dev/sdk";
import { useConnect } from "../hooks/wagmi-required/useConnect";
import { Signer, ethers, utils } from "ethers";
import invariant from "tiny-invariant";
import { Chain, Connector, ConnectorData, normalizeChainId } from "wagmi";
import {
Chain,
Connector,
ConnectorData,
normalizeChainId,
useContext as useWagmiContext,
} from "wagmi";
// exerpt from https://docs.gnosis-safe.io/backend/available-services
const CHAIN_ID_TO_GNOSIS_SERVER_URL = {
[ChainId.Mainnet]: "https://safe-transaction.mainnet.gnosis.io",
[ChainId.Avalanche]: "https://safe-transaction.avalanche.gnosis.io",
[ChainId.Polygon]: "https://safe-transaction.polygon.gnosis.io",
[ChainId.Goerli]: "https://safe-transaction.goerli.gnosis.io",
};
// mainnet
1: "https://safe-transaction-mainnet.safe.global",
// avalanche
43114: "https://safe-transaction-avalanche.safe.global",
// polygon
137: "https://safe-transaction-polygon.safe.global",
// goerli
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;
@@ -18,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";
@@ -50,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;
@@ -81,7 +103,10 @@ export class GnosisSafeConnector extends Connector {
import("@gnosis.pm/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,
@@ -163,3 +188,67 @@ export class GnosisSafeConnector extends Connector {
this.config = config;
}
}
/**
* Hook for connecting to a Gnosis Safe. This enables multisig wallets to connect to your application and sing transactions.
*
* ```javascript
* import { useGnosis } from "@thirdweb-dev/react"
* ```
*
*
* @example
* ```javascript
* import { useGnosis } from "@thirdweb-dev/react"
*
* const App = () => {
* const connectWithGnosis = useGnosis()
*
* return (
* <button onClick={() => connectWithGnosis({ safeAddress: "0x...", safeChainId: 1 })}>
* Connect Gnosis Safe
* </button>
* )
* }
* ```
*
* @public
*/
export function useGnosis() {
const wagmiContext = useWagmiContext();
invariant(
wagmiContext,
`useGnosis() can only be used inside <ThirdwebProvider />. If you are using <ThirdwebSDKProvider /> you will have to use your own wallet-connection logic.`,
);
const [connectors, connect] = useConnect();
if (connectors.loading) {
return () => Promise.reject("Gnosis connector not ready to be used, yet");
}
const connector = connectors.data.connectors.find((c) => c.id === "gnosis");
invariant(
connector,
"Gnosis connector not found, please make sure it is provided to your <ThirdwebProvider />",
);
return async (config: GnosisConnectorArguments) => {
const previousConnector = connectors.data.connector;
const previousConnectorChain = await previousConnector?.getChainId();
invariant(
!!previousConnector,
"Cannot connect to Gnosis Safe without first being connected to a personal wallet.",
);
invariant(
previousConnectorChain === config.safeChainId,
"Gnosis safe chain id must match personal wallet chain id.",
);
invariant(
utils.isAddress(config.safeAddress),
"Gnosis safe address must be a valid address.",
);
(connector as GnosisSafeConnector).setConfiguration(
previousConnector,
config,
);
return connect(connector);
};
}
+93 -1
View File
@@ -1,3 +1,4 @@
import { useConnect } from "../hooks/wagmi-required/useConnect";
import { providers, utils } from "ethers";
import type {
LoginWithMagicLinkConfiguration,
@@ -5,7 +6,12 @@ import type {
MagicSDKAdditionalConfiguration,
} from "magic-sdk";
import invariant from "tiny-invariant";
import { Chain, Connector, normalizeChainId } from "wagmi";
import {
Chain,
Connector,
normalizeChainId,
useContext as useWagmiContext,
} from "wagmi";
export interface MagicConnectorArguments
extends MagicSDKAdditionalConfiguration {
@@ -186,3 +192,89 @@ export class MagicConnector extends Connector {
}
}
}
/**
* Hook for connecting to an email wallet using magic link.
* This enables users without their own wallets to connect to your application and sign transactions securely using their email.
*
* ```javascript
* import { useMagic } from "@thirdweb-dev/react"
* ```
*
*
* @example
* Before using this hook, you first need to set up the magic configuration in your `ThirdwebProvider`, including your magic API key.
*
* ```javascript
* // Add the magic configuration object to your wallet connectors
* const connectors = [
* "metamask",
* "walletConnect",
* "walletLink",
* {
* name: "magic",
* options: {
* apiKey: "your-magic-api-key",
* }
* }
* ]
*
* // Add the above to the walletConnectors prop of your <ThirdwebProvider />
* const Provider = ({ children }) => (
* return (
* <ThirdwebProvider
* walletConnectors={connectors}
* // Specify remaining parameters
* ...
* >
* {children}
* </ThirdwebProvider>
* )
* }
* ```
*
* In order to use the hook to connect users with magic link, you just need to provide the users email to the connect function.
*
* You can setup the hook with the following configuration:
* ```javascript
* import { useMagic } from "@thirdweb-dev/react"
* import { useState } from "react"
*
* const LoginWithMagicLink = () => {
* const connectWithMagic = useMagic()
* const [email, setEmail] = useState()
*
* return (
* <div>
* <input value={email} onChange={(e) => setEmail(e.target.value)} />
* <button onClick={() => connectWithMagic({ email })}>Login</button>
* </div>
* )
* }
* ```
*
* @public
*/
export function useMagic() {
const wagmiContext = useWagmiContext();
invariant(
wagmiContext,
`useMagic() can only be used inside <ThirdwebProvider />. If you are using <ThirdwebSDKProvider /> you will have to use your own wallet-connection logic.`,
);
const [connectors, connect] = useConnect();
if (connectors.loading) {
return () => Promise.reject("Magic connector not ready to be used, yet");
}
const connector = connectors.data.connectors.find((c) => c.id === "magic");
invariant(
connector,
"Magic connector not found, please make sure it is provided to your <ThirdwebProvider />",
);
return (configuration: LoginWithMagicLinkConfiguration) => {
(connector as MagicConnector).setConfiguration(configuration);
return connect(connector);
};
}
+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,
@@ -3,7 +3,7 @@ import {
SupportedChainId,
defaultSupportedChains,
} from "../constants/chain";
import { ChainId } from "@thirdweb-dev/sdk";
import { DEFAULT_RPC_URLS } from "@thirdweb-dev/sdk";
import React, { PropsWithChildren, createContext, useContext } from "react";
interface ThirdwebConfigContext {
@@ -11,17 +11,8 @@ interface ThirdwebConfigContext {
supportedChains: Chain[];
}
export const defaultChainRpc: Record<SupportedChainId | number, string> = {
[ChainId.Mainnet]: "mainnet",
[ChainId.Goerli]: "goerli",
[ChainId.Polygon]: "polygon",
[ChainId.Mumbai]: "mumbai",
[ChainId.Fantom]: "fantom",
[ChainId.Avalanche]: "avalanche",
};
const ThirdwebConfigContext = createContext<ThirdwebConfigContext>({
rpcUrlMap: defaultChainRpc,
rpcUrlMap: DEFAULT_RPC_URLS,
supportedChains: defaultSupportedChains,
});
@@ -33,7 +33,17 @@ export const ThirdwebConnectedWalletProvider: React.FC<
const { rpcUrlMap } = useThirdwebConfigContext();
const [contextValue, setContextValue] =
useState<ThirdwebConnectedWalletContext>(INITIAL_CONTEXT_VALUE);
useState<ThirdwebConnectedWalletContext>({
...INITIAL_CONTEXT_VALUE,
signer: signer ? signer : undefined,
});
useEffect(() => {
setContextValue((val) => ({
...val,
signer: signer ? signer : undefined,
}));
}, [signer]);
useEffect(() => {
let s = signer;
@@ -1,5 +1,8 @@
import { RequiredParam } from "../../../core/types/shared";
import { useSDKChainId } from "../../providers/base";
import {
RequiredParam,
requiredParamInvariant,
} from "../../../core/query-utils/required-param";
import { useSDK, useSDKChainId } from "../../providers/base";
import { getErcs, DropContract, WalletAddress } from "../../types";
import {
cacheKeys,
@@ -7,8 +10,16 @@ import {
} from "../../utils/cache-keys";
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { ClaimCondition, ClaimConditionInput } from "@thirdweb-dev/sdk";
import { BigNumberish } from "ethers";
import {
ClaimCondition,
ClaimConditionFetchOptions,
ClaimConditionInput,
SnapshotEntryWithProof,
fetchCurrencyValue,
convertToReadableQuantity,
fetchCurrencyMetadata,
} from "@thirdweb-dev/sdk";
import { BigNumberish, constants, utils } from "ethers";
import invariant from "tiny-invariant";
/**
@@ -38,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
@@ -53,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
@@ -62,25 +73,30 @@ export type SetClaimConditionsParams = {
export function useActiveClaimCondition(
contract: RequiredParam<DropContract>,
tokenId?: BigNumberish,
options?: ClaimConditionFetchOptions,
) {
const contractAddress = contract?.getAddress();
const { erc1155, erc721, erc20 } = getErcs(contract);
return useQueryWithNetwork(
cacheKeys.extensions.claimConditions.getActive(contractAddress, tokenId),
cacheKeys.extensions.claimConditions.getActive(
contractAddress,
tokenId,
options,
),
() => {
if (erc1155) {
invariant(
tokenId !== undefined,
requiredParamInvariant(
tokenId,
"tokenId is required for ERC1155 claim conditions",
);
return erc1155.claimConditions.getActive(tokenId);
return erc1155.claimConditions.getActive(tokenId, options);
}
if (erc721) {
return erc721.claimConditions.getActive();
return erc721.claimConditions.getActive(options);
}
if (erc20) {
return erc20.claimConditions.getActive();
return erc20.claimConditions.getActive(options);
}
throw new Error("Contract must be ERC721, ERC1155 or ERC20");
},
@@ -94,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
@@ -109,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
@@ -118,22 +207,30 @@ export function useActiveClaimCondition(
export function useClaimConditions(
contract: RequiredParam<DropContract>,
tokenId?: BigNumberish,
options?: ClaimConditionFetchOptions,
) {
const contractAddress = contract?.getAddress();
const { erc1155, erc721, erc20 } = getErcs(contract);
return useQueryWithNetwork(
cacheKeys.extensions.claimConditions.getAll(contractAddress, tokenId),
cacheKeys.extensions.claimConditions.getAll(
contractAddress,
tokenId,
options,
),
() => {
if (erc1155) {
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
return erc1155.claimConditions.getAll(tokenId);
requiredParamInvariant(
tokenId,
"tokenId is required for ERC1155 claim conditions",
);
return erc1155.claimConditions.getAll(tokenId, options);
}
if (erc721) {
return erc721.claimConditions.getAll();
return erc721.claimConditions.getAll(options);
}
if (erc20) {
return erc20.claimConditions.getAll();
return erc20.claimConditions.getAll(options);
}
throw new Error("Contract must be ERC721, ERC1155 or ERC20");
},
@@ -184,7 +281,7 @@ export function useClaimIneligibilityReasons(
),
() => {
if (erc1155) {
invariant(
requiredParamInvariant(
tokenId,
"tokenId is required for ERC1155 claim ineligibility reasons",
);
@@ -222,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 **/
/** **********************/
@@ -270,11 +497,14 @@ export function useSetClaimConditions(
return useMutation(
async (data: SetClaimConditionsParams) => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
const { phases, reset = false } = data;
invariant(phases, 'No "phases" provided');
if (erc1155) {
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
requiredParamInvariant(
tokenId,
"tokenId is required for ERC1155 claim conditions",
);
return erc1155.claimConditions.set(tokenId, phases, reset);
}
if (erc721) {
@@ -341,35 +571,42 @@ export function useResetClaimConditions(
return useMutation(
async () => {
const cleanConditions = (conditions: ClaimCondition[]) => {
const cleanConditions = async (conditions: ClaimCondition[]) => {
return conditions.map((c) => ({
...c,
price: c.currencyMetadata.displayValue,
maxQuantity: c.maxQuantity.toString(),
quantityLimitPerTransaction: c.quantityLimitPerTransaction.toString(),
}));
};
if (erc1155) {
invariant(tokenId, "tokenId is required for ERC1155 claim conditions");
const claimConditions = await erc1155.claimConditions.getAll(tokenId);
requiredParamInvariant(
tokenId,
"tokenId is required for ERC1155 claim conditions",
);
const claimConditions = await erc1155.claimConditions.getAll(tokenId, {
withAllowList: true,
});
return erc1155.claimConditions.set(
tokenId,
cleanConditions(claimConditions || []),
await cleanConditions(claimConditions || []),
true,
);
}
if (erc721) {
const claimConditions = await erc721.claimConditions.getAll();
const claimConditions = await erc721.claimConditions.getAll({
withAllowList: true,
});
return await erc721.claimConditions.set(
cleanConditions(claimConditions || []),
await cleanConditions(claimConditions || []),
true,
);
}
if (erc20) {
const claimConditions = await erc20.claimConditions.getAll();
const claimConditions = await erc20.claimConditions.getAll({
withAllowList: true,
});
return await erc20.claimConditions.set(
cleanConditions(claimConditions || []),
await cleanConditions(claimConditions || []),
true,
);
}
@@ -1,4 +1,7 @@
import { RequiredParam } from "../../../core/types/shared";
import {
RequiredParam,
requiredParamInvariant,
} from "../../../core/query-utils/required-param";
import { useSDKChainId } from "../../providers/base";
import { WalletAddress } from "../../types";
import {
@@ -35,7 +38,7 @@ export function usePrimarySaleRecipient(
return useQueryWithNetwork(
cacheKeys.extensions.sales.getRecipient(contractAddress),
() => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(
"sales" in contract && contract.sales,
"Contract does not support primarySale",
@@ -86,7 +89,7 @@ export function useUpdatePrimarySaleRecipient(
const activeChainId = useSDKChainId();
return useMutation(
(newRecipient: WalletAddress) => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(
"sales" in contract && contract.sales,
"Contract does not support primarySale",
@@ -128,7 +131,7 @@ export function useRoyaltySettings(
return useQueryWithNetwork(
cacheKeys.extensions.royalties.getDefaultRoyaltyInfo(contractAddress),
() => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(
"royalties" in contract && contract.royalties,
"Contract does not support royalties",
@@ -182,7 +185,7 @@ export function useUpdateRoyaltySettings(
seller_fee_basis_points?: number;
fee_recipient?: WalletAddress;
}) => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(
"royalties" in contract && contract.royalties,
"Contract does not support royalties",
@@ -224,7 +227,7 @@ export function usePlatformFees(
return useQueryWithNetwork(
cacheKeys.extensions.platformFees.get(contractAddress),
() => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(
"platformFees" in contract && contract.platformFees,
"Contract does not support platformFees",
@@ -277,7 +280,7 @@ export function useUpdatePlatformFees(
platform_fee_basis_points?: number;
fee_recipient?: WalletAddress;
}) => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(
"platformFees" in contract && contract.platformFees,
"Contract does not support platformFees",
@@ -317,7 +320,7 @@ export function useMetadata(contract: RequiredParam<ValidContractInstance>) {
return useQueryWithNetwork(
cacheKeys.extensions.metadata.get(contractAddress),
() => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(
"metadata" in contract && contract.metadata,
"Contract does not support metadata",
@@ -366,7 +369,7 @@ export function useUpdateMetadata(
const activeChainId = useSDKChainId();
return useMutation(
(updatePayload: CustomContractMetadata) => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(
"metadata" in contract && contract.metadata,
"Contract does not support metadata",
+14 -11
View File
@@ -1,5 +1,8 @@
import { neverPersist } from "../../../core/query-utils/query-key";
import { RequiredParam } from "../../../core/types/shared";
import {
RequiredParam,
requiredParamInvariant,
} from "../../../core/query-utils/required-param";
import { useSDK, useSDKChainId } from "../../providers/base";
import { ContractAddress } from "../../types";
import {
@@ -20,7 +23,7 @@ import {
ContractEvent,
ContractForPrebuiltContractType,
ContractType,
EventQueryFilter,
EventQueryOptions,
PrebuiltContractType,
SUPPORTED_CHAIN_ID,
ThirdwebSDK,
@@ -216,7 +219,7 @@ export function useContract(
{ wallet, walletChainId, sdkTimestamp },
]),
async () => {
invariant(contractAddress, "contract address is required");
requiredParamInvariant(contractAddress, "contract address is required");
invariant(sdk, "SDK not initialized");
invariant(activeChainId, "active chain id is required");
@@ -290,7 +293,7 @@ export function useContractMetadata<TContract extends ValidContractInstance>(
>(
cacheKeys.contract.metadata(contract?.getAddress()),
async () => {
invariant(contract, "contract is required");
requiredParamInvariant(contract, "contract is required");
return await contract.metadata.get();
},
{
@@ -311,7 +314,7 @@ export function useContractMetadataUpdate(
return useMutation(
async (metadata: CommonContractSchemaInput) => {
invariant(contract, "contract must be defined");
requiredParamInvariant(contract, "contract must be defined");
return contract.metadata.update(metadata);
},
@@ -343,7 +346,7 @@ export function useContractMetadataUpdate(
export function useContractEvents(
contract: RequiredParam<ValidContractInstance>,
eventName?: string,
options: { queryFilter?: EventQueryFilter; subscribe?: boolean } = {
options: { queryFilter?: EventQueryOptions; subscribe?: boolean } = {
subscribe: true,
},
) {
@@ -406,7 +409,7 @@ export function useContractEvents(
return useQuery(
cacheKey,
() => {
invariant(contract, "contract must be defined");
requiredParamInvariant(contract, "contract must be defined");
if (eventName) {
return contract.events.getEvents(eventName, options.queryFilter);
}
@@ -447,8 +450,8 @@ export function useContractRead(
return useQueryWithNetwork(
cacheKeys.contract.call(contractAddress, functionName, args),
() => {
invariant(contract, "contract must be defined");
invariant(functionName, "function name must be provided");
requiredParamInvariant(contract, "contract must be defined");
requiredParamInvariant(functionName, "function name must be provided");
return contract.call(functionName, ...args);
},
{
@@ -485,8 +488,8 @@ export function useContractWrite(
return useMutation(
async (callParams?: unknown[] | [...unknown[], CallOverrides]) => {
invariant(contract, "contract must be defined");
invariant(functionName, "function name must be provided");
requiredParamInvariant(contract, "contract must be defined");
requiredParamInvariant(functionName, "function name must be provided");
if (!callParams?.length) {
return contract.call(functionName);
}
+25 -23
View File
@@ -1,4 +1,7 @@
import { RequiredParam } from "../../../core/types/shared";
import {
RequiredParam,
requiredParamInvariant,
} from "../../../core/query-utils/required-param";
import { useSDKChainId } from "../../providers/base";
import {
ClaimNFTParams,
@@ -51,7 +54,7 @@ export function useUnclaimedNFTs(
return useQueryWithNetwork(
cacheKeys.contract.nft.drop.getAllUnclaimed(contractAddress, queryParams),
() => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
// TODO make this work for custom contracts (needs ABI change)
invariant(
contract.getAllUnclaimed,
@@ -94,18 +97,18 @@ export function useClaimedNFTs(
*/
export function useUnclaimedNFTSupply(contract: RequiredParam<DropContract>) {
const contractAddress = contract?.getAddress();
const { erc721 } = getErcs(contract);
return useQueryWithNetwork(
cacheKeys.contract.nft.drop.totalUnclaimedSupply(contractAddress),
() => {
invariant(contract, "No Contract instance provided");
// TODO make this work for custom contracts (needs ABI change)
invariant(
"totalUnclaimedSupply" in contract && contract.totalUnclaimedSupply,
"Contract instance does not support fetching unclaimed supply",
);
return contract.totalUnclaimedSupply();
requiredParamInvariant(contract, "No Contract instance provided");
if (erc721) {
invariant(erc721, "No ERC721 Contract instance provided");
return erc721.totalUnclaimedSupply();
}
invariant(false, "Contract is not an instance of ERC721");
},
{ enabled: !!contract },
{ enabled: !!erc721 },
);
}
@@ -118,18 +121,17 @@ export function useUnclaimedNFTSupply(contract: RequiredParam<DropContract>) {
*/
export function useClaimedNFTSupply(contract: RequiredParam<DropContract>) {
const contractAddress = contract?.getAddress();
const { erc721 } = getErcs(contract);
return useQueryWithNetwork(
cacheKeys.contract.nft.drop.totalClaimedSupply(contractAddress),
() => {
invariant(contract, "No Contract instance provided");
// TODO make this work for custom contracts (needs ABI change)
invariant(
"totalClaimedSupply" in contract && contract.totalClaimedSupply,
"Contract instance does not support fetching unclaimed supply",
);
return contract.totalClaimedSupply();
requiredParamInvariant(contract, "No Contract instance provided");
if (erc721) {
return erc721.totalClaimedSupply();
}
invariant(false, "Contract is not an instance of ERC721");
},
{ enabled: !!contract },
{ enabled: !!erc721 },
);
}
@@ -206,10 +208,10 @@ export function useClaimNFT<TContract extends DropContract>(
return useMutation(
async (data: ClaimNFTParams) => {
invariant(contract, "contract is undefined");
requiredParamInvariant(contract, "contract is undefined");
if (erc1155) {
invariant(!!data.tokenId, "tokenId not provided");
requiredParamInvariant(data.tokenId, "tokenId not provided");
if (!data.to) {
return (await erc1155.claim(
data.tokenId,
@@ -270,7 +272,7 @@ export function useLazyMint<TContract extends DropContract>(
return useMutation(
async (data: { metadatas: NFTMetadataInput[] }) => {
invariant(contract, "contract is undefined");
requiredParamInvariant(contract, "contract is undefined");
let options;
if (onProgress) {
options = {
@@ -316,7 +318,7 @@ export function useDelayedRevealLazyMint<TContract extends RevealableContract>(
return useMutation(
async (data: DelayedRevealLazyMintInput) => {
invariant(contract, "contract is undefined");
requiredParamInvariant(contract, "contract is undefined");
let options;
if (onProgress) {
options = {
@@ -370,7 +372,7 @@ export function useRevealLazyMint<TContract extends RevealableContract>(
return useMutation(
async (data: RevealLazyMintInput) => {
invariant(contract, "contract is undefined");
requiredParamInvariant(contract, "contract is undefined");
const { erc721, erc1155 } = getErcs(contract);
if (erc721) {
return await erc721.revealer.reveal(data.batchId, data.password);
+266 -20
View File
@@ -1,12 +1,22 @@
import { RequiredParam } from "../../../core/types/shared";
import {
RequiredParam,
requiredParamInvariant,
} from "../../../core/query-utils/required-param";
import { useSDKChainId } from "../../providers/base";
import { BuyNowParams, MakeBidParams } from "../../types";
import {
AcceptDirectOffer,
BuyNowParams,
ExecuteAuctionSale,
MakeBidParams,
MakeOfferParams,
} from "../../types";
import {
cacheKeys,
invalidateContractAndBalances,
} from "../../utils/cache-keys";
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
import { useAddress } from "../wallet";
import { useContractEvents } from "./contracts";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import type {
AuctionListing,
@@ -17,7 +27,7 @@ import type {
} from "@thirdweb-dev/sdk";
import { ListingType } from "@thirdweb-dev/sdk";
import { Marketplace } from "@thirdweb-dev/sdk/dist/declarations/src/evm/contracts/prebuilt-implementations/marketplace";
import { BigNumber, BigNumberish } from "ethers";
import { BigNumberish } from "ethers";
import invariant from "tiny-invariant";
/** **********************/
@@ -45,8 +55,9 @@ export function useListing(
return useQueryWithNetwork(
cacheKeys.contract.marketplace.getListing(contractAddress, listingId),
() => {
invariant(contract, "No Contract instance provided");
return contract.getListing(BigNumber.from(listingId || 0));
requiredParamInvariant(contract, "No Contract instance provided");
requiredParamInvariant(listingId, "No listing id provided");
return contract.getListing(listingId);
},
{
enabled: !!contract,
@@ -76,7 +87,7 @@ export function useListings(
return useQueryWithNetwork(
cacheKeys.contract.marketplace.getAllListings(contractAddress, filter),
() => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
return contract.getAllListings(filter);
},
{
@@ -103,7 +114,7 @@ export function useListingsCount(contract: RequiredParam<Marketplace>) {
return useQueryWithNetwork(
cacheKeys.contract.marketplace.getTotalCount(contractAddress),
() => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
return contract.getTotalCount();
},
{
@@ -133,7 +144,7 @@ export function useActiveListings(
return useQueryWithNetwork(
cacheKeys.contract.marketplace.getActiveListings(contractAddress, filter),
() => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
return contract.getActiveListings(filter);
},
@@ -168,8 +179,9 @@ export function useWinningBid(
listingId,
),
() => {
invariant(contract, "No Contract instance provided");
return contract.auction.getWinningBid(BigNumber.from(listingId || 0));
requiredParamInvariant(contract, "No Contract instance provided");
requiredParamInvariant(listingId, "No listing id provided");
return contract.auction.getWinningBid(listingId);
},
{
enabled: !!contract && listingId !== undefined,
@@ -201,12 +213,11 @@ export function useAuctionWinner(
listingId,
),
async () => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
requiredParamInvariant(listingId, "No listing id provided");
let winner: string | undefined;
try {
winner = await contract.auction.getWinner(
BigNumber.from(listingId || 0),
);
winner = await contract.auction.getWinner(listingId);
} catch (err) {
if (!(err as Error)?.message?.includes("Could not find auction")) {
throw err;
@@ -238,7 +249,7 @@ export function useBidBuffer(contract: RequiredParam<Marketplace>) {
return useQueryWithNetwork(
cacheKeys.contract.marketplace.getBidBufferBps(contractAddress),
() => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
return contract.getBidBufferBps();
},
{
@@ -247,6 +258,40 @@ export function useBidBuffer(contract: RequiredParam<Marketplace>) {
);
}
/**
* Use this to get the minimum next bid for the auction listing from your marketplace contract.
*
* @example
* ```javascript
* const { data: minimumNextBid, isLoading, error } = useMinimumNextBid(<YourMarketplaceContractInstance>, <listingId>);
* ```
*
* @param contract - an instance of a marketplace contract
* @param listingId - the listing id to check
* @returns a response object that includes the minimum next bid for the auction listing
* @beta
*/
export function useMinimumNextBid(
contract: RequiredParam<Marketplace>,
listingId: RequiredParam<BigNumberish>,
) {
const contractAddress = contract?.getAddress();
return useQueryWithNetwork(
cacheKeys.contract.marketplace.auction.getWinner(
contractAddress,
listingId,
),
async () => {
requiredParamInvariant(contract, "No Contract instance provided");
requiredParamInvariant(listingId, "No listing id provided");
return await contract.auction.getMinimumNextBid(listingId);
},
{
enabled: !!contract && listingId !== undefined,
},
);
}
/** **********************/
/** WRITE HOOKS **/
/** **********************/
@@ -290,8 +335,9 @@ export function useCreateDirectListing(contract: RequiredParam<Marketplace>) {
return useMutation(
async (data: NewDirectListing) => {
invariant(walletAddress, "no wallet connected, cannot create listing");
requiredParamInvariant(contract, "No Contract instance provided");
invariant(
contract?.direct?.createListing,
contract.direct.createListing,
"contract does not support direct.createListing",
);
return await contract.direct.createListing(data);
@@ -346,8 +392,9 @@ export function useCreateAuctionListing(contract: RequiredParam<Marketplace>) {
return useMutation(
async (data: NewAuctionListing) => {
invariant(walletAddress, "no wallet connected, cannot create listing");
requiredParamInvariant(contract, "No Contract instance provided");
invariant(
contract?.direct?.createListing,
contract.direct.createListing,
"contract does not support auction.createListing",
);
return await contract.auction.createListing(data);
@@ -456,8 +503,9 @@ export function useMakeBid(contract: RequiredParam<Marketplace>) {
return useMutation(
async (data: MakeBidParams) => {
invariant(walletAddress, "no wallet connected, cannot make bid");
requiredParamInvariant(contract, "No Contract instance provided");
invariant(
contract?.auction?.makeBid,
contract.auction.makeBid,
"contract does not support auction.makeBid",
);
return await contract.auction.makeBid(data.listingId, data.bid);
@@ -473,6 +521,203 @@ export function useMakeBid(contract: RequiredParam<Marketplace>) {
);
}
/**
* Use this to make an offer on direct or auction listing from your marketplace contract.
*
* @example
* ```jsx
* const Component = () => {
* const {
* mutate: makeOffer,
* isLoading,
* error,
* } = useMakeOffer(">>YourMarketplaceContractInstance<<");
*
* if (error) {
* console.error("failed to make a bid", error);
* }
*
* return (
* <button
* disabled={isLoading}
* onClick={() => makeOffer({ listingId: 1, pricePerToken: 0.5, quantity: 1 })}
* >
* Bid!
* </button>
* );
* };
* ```
*
* @param contract - an instance of a Marketplace contract
* @returns a mutation object that can be used to make a bid on an auction listing
* @beta
*/
export function useMakeOffer(contract: RequiredParam<Marketplace>) {
const activeChainId = useSDKChainId();
const contractAddress = contract?.getAddress();
const queryClient = useQueryClient();
const walletAddress = useAddress();
return useMutation(
async (data: MakeOfferParams) => {
invariant(walletAddress, "no wallet connected, cannot make bid");
requiredParamInvariant(contract, "No Contract instance provided");
return await contract.makeOffer(
data.listingId,
data.pricePerToken,
data.quantity,
);
},
{
onSettled: () =>
invalidateContractAndBalances(
queryClient,
contractAddress,
activeChainId,
),
},
);
}
/**
* Accept an offer on a direct listing from an offeror, will accept the latest offer by the given offeror.
*
* @example
* ```jsx
* const Component = () => {
* const {
* mutate: acceptOffer,
* isLoading,
* error,
* } = useAcceptDirectListingOffer(">>YourMarketplaceContractInstance<<");
*
* if (error) {
* console.error("failed to accept offer", error);
* }
*
* return (
* <button
* disabled={isLoading}
* onClick={() => acceptOffer({ listingId: 1, addressOfOfferor: "0x..." })}
* >
* Accept offer
* </button>
* );
* };
* ```
*
* @param contract - an instance of a Marketplace contract
* @returns a mutation object that can be used to accept an offer on a direct listing
* @beta
*/
export function useAcceptDirectListingOffer(
contract: RequiredParam<Marketplace>,
) {
const activeChainId = useSDKChainId();
const contractAddress = contract?.getAddress();
const queryClient = useQueryClient();
const walletAddress = useAddress();
return useMutation(
async (data: AcceptDirectOffer) => {
invariant(walletAddress, "no wallet connected, cannot make bid");
requiredParamInvariant(contract?.direct, "No Direct instance provided");
return await contract.direct.acceptOffer(
data.listingId,
data.addressOfOfferor,
);
},
{
onSettled: () =>
invalidateContractAndBalances(
queryClient,
contractAddress,
activeChainId,
),
},
);
}
/**
* Execute an auction sale. Can only be executed once the auction has ended and the auction has a winning bid.
*
* @example
* ```jsx
* const Component = () => {
* const {
* mutate: executeAuctionSale,
* isLoading,
* error,
* } = useExecuteAuctionSale(">>YourMarketplaceContractInstance<<");
*
* if (error) {
* console.error("failed to execute sale", error);
* }
*
* return (
* <button
* disabled={isLoading}
* onClick={() => executeAuctionSale({ listingId: 1 })}
* >
* Execute sale
* </button>
* );
* };
* ```
*
* @param contract - an instance of a Marketplace contract
* @returns a mutation object that can be used to accept an offer on a direct listing
* @beta
*/
export function useExecuteAuctionSale(contract: RequiredParam<Marketplace>) {
const activeChainId = useSDKChainId();
const contractAddress = contract?.getAddress();
const queryClient = useQueryClient();
const walletAddress = useAddress();
return useMutation(
async (data: ExecuteAuctionSale) => {
invariant(walletAddress, "no wallet connected, cannot make bid");
requiredParamInvariant(
contract?.auction,
"No Auction marketplace instance provided",
);
return await contract.auction.executeSale(data.listingId);
},
{
onSettled: () =>
invalidateContractAndBalances(
queryClient,
contractAddress,
activeChainId,
),
},
);
}
/**
* Get all the offers for a listing
*
* @remarks Fetch all the offers for a specified direct or auction listing.
* @example
* ```javascript
* const { data: offers, isLoading, error } = useOffers(<YourMarketplaceContractInstance>, <listingId>);
* ```
*
* @param contract - an instance of a Marketplace contract
* @param listingId - the id of the listing to fetch offers for
* @beta
*/
export function useOffers(
contract: RequiredParam<Marketplace>,
listingId: RequiredParam<BigNumberish>,
) {
const result = useContractEvents(contract, "NewOffer");
return {
...result,
data: result.data
?.filter((ev) => ev.data.listingId.eq(listingId))
?.map((ev) => ev.data),
};
}
/**
* Use this to buy out an auction listing from your marketplace contract.
*
@@ -512,9 +757,10 @@ export function useBuyNow(contract: RequiredParam<Marketplace>) {
return useMutation(
async (data: BuyNowParams) => {
invariant(walletAddress, "no wallet connected, cannot make bid");
requiredParamInvariant(contract, "No Contract instance provided");
if (data.type === ListingType.Direct) {
invariant(
contract?.direct.buyoutListing,
contract.direct.buyoutListing,
"contract does not support direct.buyoutListing",
);
@@ -525,7 +771,7 @@ export function useBuyNow(contract: RequiredParam<Marketplace>) {
);
}
invariant(
contract?.auction?.buyoutListing,
contract.auction.buyoutListing,
"contract does not support auction.buyoutListing",
);
return await contract.auction.buyoutListing(data.id);
+21 -17
View File
@@ -1,4 +1,7 @@
import { RequiredParam } from "../../../core/types/shared";
import {
requiredParamInvariant,
RequiredParam,
} from "../../../core/query-utils/required-param";
import { useSDKChainId } from "../../providers/base";
import {
AirdropNFTParams,
@@ -50,7 +53,7 @@ export function useNFT<TContract extends NFTContract>(
return useQueryWithNetwork<NFT>(
cacheKeys.contract.nft.get(contractAddress, tokenId),
async () => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
if (erc1155) {
invariant(erc1155.get, "Contract instance does not support get");
@@ -93,7 +96,7 @@ export function useNFTs<TContract extends NFTContract>(
return useQueryWithNetwork<NFT[]>(
cacheKeys.contract.nft.query.all(contractAddress, queryParams),
async () => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
if (erc721) {
invariant(erc721.getAll, "Contract instance does not support getAll");
@@ -134,7 +137,7 @@ export function useTotalCount<TContract extends NFTContract>(
return useQueryWithNetwork<BigNumber>(
cacheKeys.contract.nft.query.totalCount(contractAddress),
async () => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
if (erc1155) {
invariant(
@@ -182,14 +185,14 @@ export function useTotalCirculatingSupply(
return useQueryWithNetwork<BigNumber>(
cacheKeys.contract.nft.query.totalCirculatingSupply(contractAddress),
async () => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
if (erc1155) {
invariant(
erc1155.totalCirculatingSupply,
"Contract instance does not support totalCirculatingSupply",
);
invariant(tokenId, "No tokenId provided");
requiredParamInvariant(tokenId, "No tokenId provided");
return await erc1155.totalCirculatingSupply(tokenId);
}
if (erc721) {
@@ -232,7 +235,7 @@ export function useOwnedNFTs<TContract extends NFTContract>(
return useQueryWithNetwork<NFT[]>(
cacheKeys.contract.nft.query.owned.all(contractAddress, ownerWalletAddress),
async () => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
invariant(ownerWalletAddress, "No wallet address provided");
if (erc721) {
return await erc721.getOwned(ownerWalletAddress);
@@ -277,11 +280,11 @@ export function useNFTBalance(
tokenId,
),
() => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
invariant(ownerWalletAddress, "No owner wallet address provided");
if (erc1155) {
invariant(tokenId, "No tokenId provided");
requiredParamInvariant(tokenId, "No tokenId provided");
invariant(
erc1155.balanceOf,
"Contract instance does not support balanceOf",
@@ -375,7 +378,7 @@ export function useMintNFT<TContract extends NFTContract>(
return useMutation(
async (data: MintNFTParams) => {
invariant(data.to, 'No "to" address provided');
invariant(contract, "contract is undefined");
requiredParamInvariant(contract, "contract is undefined");
if (erc1155) {
invariant("supply" in data, "supply not provided");
const { to, metadata, supply } = data;
@@ -444,9 +447,9 @@ export function useMintNFTSupply(contract: Erc1155) {
return useMutation(
async (data: MintNFTSupplyParams) => {
invariant(data.to, 'No "to" address provided');
invariant(contract, "contract is undefined");
requiredParamInvariant(contract, "contract is undefined");
invariant("tokenId" in data, "tokenId not provided");
requiredParamInvariant(data.tokenId, "tokenId not provided");
invariant("additionalSupply" in data, "additionalSupply not provided");
const { to, tokenId, additionalSupply } = data;
return await contract.mintAdditionalSupplyTo(
@@ -512,7 +515,7 @@ export function useTransferNFT<TContract extends NFTContract>(
invariant("to" in data, "to not provided");
if (erc1155) {
invariant(erc1155.transfer, "contract does not support transfer");
invariant("tokenId" in data, "tokenId not provided");
requiredParamInvariant(data.tokenId, "tokenId not provided");
invariant("amount" in data, "amount not provided");
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
return erc1155.transfer(data.to, data.tokenId, data.amount!);
@@ -539,7 +542,7 @@ export function useTransferNFT<TContract extends NFTContract>(
* @example
* ```jsx
* const Component = () => {
* const editionDrop = useEditionDrop(<ContractAddress>);
* const editionDrop = useContract(<ContractAddress>, "edition-drop");
* const {
* mutate: airdropNFT,
* isLoading,
@@ -602,7 +605,8 @@ export function useAirdropNFT(contract: Erc1155) {
return useMutation(
({ tokenId, addresses }: AirdropNFTParams) => {
invariant(contract?.airdrop, "contract does not support airdrop");
requiredParamInvariant(contract, "contract is undefined");
invariant(contract.airdrop, "contract does not support airdrop");
return contract.airdrop(tokenId, addresses);
},
@@ -688,8 +692,8 @@ export function useBurnNFT<TContract extends NFTContract>(
return useMutation(
async (data: BurnNFTParams) => {
invariant(data.tokenId, "No tokenId provided");
invariant(contract, "contract is undefined");
requiredParamInvariant(data.tokenId, "No tokenId provided");
requiredParamInvariant(contract, "contract is undefined");
if (erc1155) {
invariant("amount" in data, "amount not provided");
const { tokenId, amount } = data;
+9 -6
View File
@@ -1,4 +1,7 @@
import { RequiredParam } from "../../../core/types/shared";
import {
requiredParamInvariant,
RequiredParam,
} from "../../../core/query-utils/required-param";
import { useSDKChainId } from "../../providers/base";
import { WalletAddress } from "../../types";
import {
@@ -61,7 +64,7 @@ export function useAllRoleMembers<TContract extends ContractWithRoles>(
return useQueryWithNetwork<Awaited<GetAllReturnType<TContract>>>(
cacheKeys.extensions.roles.getAll(contractAddress),
() => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(contract.roles, "Contract does not support roles");
// have to cast to any because of role bs, type is defined in the useQueryWithNetwork definition above
return contract.roles.getAll() as any;
@@ -94,7 +97,7 @@ export function useRoleMembers<TContract extends ContractWithRoles>(
return useQueryWithNetwork(
cacheKeys.extensions.roles.get(contractAddress, role),
() => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(contract.roles, "Contract does not support roles");
return contract.roles.get(role);
},
@@ -192,7 +195,7 @@ export function useSetAllRoleMembers<TContract extends ContractWithRoles>(
async (rolesWithAddresses: {
[role in RolesForContract<TContract>]: string[];
}) => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(contract.roles, "Contract does not support roles");
await contract.roles.setAll(rolesWithAddresses);
},
@@ -253,7 +256,7 @@ export function useGrantRole<TContract extends ContractWithRoles>(
role: RolesForContract<TContract>;
address: WalletAddress;
}) => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(contract.roles, "Contract does not support roles");
await contract.roles.grant(params.role as any, params.address);
},
@@ -311,7 +314,7 @@ export function useRevokeRole<TContract extends ContractWithRoles>(
role: RolesForContract<TContract>;
address: WalletAddress;
}) => {
invariant(contract, "No contract provided");
requiredParamInvariant(contract, "No contract provided");
invariant(contract.roles, "Contract does not support roles");
await contract.roles.revoke(params.role as any, params.address);
},
+14 -13
View File
@@ -1,4 +1,7 @@
import { RequiredParam } from "../../../core/types/shared";
import {
requiredParamInvariant,
RequiredParam,
} from "../../../core/query-utils/required-param";
import { useSDKChainId } from "../../providers/base";
import {
ClaimTokenParams,
@@ -39,7 +42,7 @@ export function useTokenSupply(contract: RequiredParam<TokenContract>) {
return useQueryWithNetwork(
cacheKeys.contract.token.totalSupply(contractAddress),
() => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
const erc20 = getErc20(contract);
if (erc20) {
return erc20.totalSupply();
@@ -75,7 +78,7 @@ export function useTokenBalance(
return useQueryWithNetwork(
cacheKeys.contract.token.balanceOf(contractAddress, walletAddress),
async () => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
invariant(walletAddress, "No address provided");
if (erc20) {
return await erc20.balanceOf(walletAddress);
@@ -109,7 +112,7 @@ export function useTokenDecimals(contract: RequiredParam<TokenContract>) {
return useQueryWithNetwork(
cacheKeys.contract.token.decimals(contractAddress),
async () => {
invariant(contract, "No Contract instance provided");
requiredParamInvariant(contract, "No Contract instance provided");
if (erc20) {
return (await erc20.get()).decimals;
@@ -168,7 +171,7 @@ export function useMintToken(contract: RequiredParam<TokenContract>) {
return useMutation(
(data: TokenParams) => {
const { to, amount } = data;
invariant(contract, "contract is undefined");
requiredParamInvariant(contract, "contract is undefined");
if (erc20) {
return erc20.mintTo(to, amount);
}
@@ -229,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");
},
@@ -350,7 +351,7 @@ export function useTransferBatchToken(contract: RequiredParam<TokenContract>) {
(data: TokenParams[]) => {
if (erc20) {
invariant(
erc20?.transferBatch,
erc20.transferBatch,
"contract does not support transferBatch",
);
const convertedData = data.map((token) => ({
@@ -415,9 +416,9 @@ export function useBurnToken(contract: RequiredParam<TokenContract>) {
return useMutation(
(data: TokenBurnParams) => {
const { amount } = data;
invariant(contract, "contract is undefined");
requiredParamInvariant(contract, "contract is undefined");
if (erc20) {
invariant(erc20?.burn, "contract does not support burn");
invariant(erc20.burn, "contract does not support burn");
return erc20.burn(amount);
}
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;
},
{
@@ -1,72 +0,0 @@
import {
GnosisConnectorArguments,
GnosisSafeConnector,
} from "../../connectors/gnosis-safe";
import { useConnect } from "../wagmi-required/useConnect";
import { utils } from "ethers";
import invariant from "tiny-invariant";
import { useContext as useWagmiContext } from "wagmi";
/**
* Hook for connecting to a Gnosis Safe. This enables multisig wallets to connect to your application and sing transactions.
*
* ```javascript
* import { useGnosis } from "@thirdweb-dev/react"
* ```
*
*
* @example
* ```javascript
* import { useGnosis } from "@thirdweb-dev/react"
*
* const App = () => {
* const connectWithGnosis = useGnosis()
*
* return (
* <button onClick={() => connectWithGnosis({ safeAddress: "0x...", safeChainId: 1 })}>
* Connect Gnosis Safe
* </button>
* )
* }
* ```
*
* @public
*/
export function useGnosis() {
const wagmiContext = useWagmiContext();
invariant(
wagmiContext,
`useGnosis() can only be used inside <ThirdwebProvider />. If you are using <ThirdwebSDKProvider /> you will have to use your own wallet-connection logic.`,
);
const [connectors, connect] = useConnect();
if (connectors.loading) {
return () => Promise.reject("Gnosis connector not ready to be used, yet");
}
const connector = connectors.data.connectors.find((c) => c.id === "gnosis");
invariant(
connector,
"Gnosis connector not found, please make sure it is provided to your <ThirdwebProvider />",
);
return async (config: GnosisConnectorArguments) => {
const previousConnector = connectors.data.connector;
const previousConnectorChain = await previousConnector?.getChainId();
invariant(
!!previousConnector,
"Cannot connect to Gnosis Safe without first being connected to a personal wallet.",
);
invariant(
previousConnectorChain === config.safeChainId,
"Gnosis safe chain id must match personal wallet chain id.",
);
invariant(
utils.isAddress(config.safeAddress),
"Gnosis safe address must be a valid address.",
);
(connector as GnosisSafeConnector).setConfiguration(
previousConnector,
config,
);
return connect(connector);
};
}
@@ -1,91 +0,0 @@
import { MagicConnector } from "../../connectors/magic";
import { useConnect } from "../wagmi-required/useConnect";
import { LoginWithMagicLinkConfiguration } from "magic-sdk";
import invariant from "tiny-invariant";
import { useContext as useWagmiContext } from "wagmi";
/**
* Hook for connecting to an email wallet using magic link.
* This enables users without their own wallets to connect to your application and sign transactions securely using their email.
*
* ```javascript
* import { useMagic } from "@thirdweb-dev/react"
* ```
*
*
* @example
* Before using this hook, you first need to set up the magic configuration in your `ThirdwebProvider`, including your magic API key.
*
* ```javascript
* // Add the magic configuration object to your wallet connectors
* const connectors = [
* "metamask",
* "walletConnect",
* "walletLink",
* {
* name: "magic",
* options: {
* apiKey: "your-magic-api-key",
* }
* }
* ]
*
* // Add the above to the walletConnectors prop of your <ThirdwebProvider />
* const Provider = ({ children }) => (
* return (
* <ThirdwebProvider
* walletConnectors={connectors}
* // Specify remaining parameters
* ...
* >
* {children}
* </ThirdwebProvider>
* )
* }
* ```
*
* In order to use the hook to connect users with magic link, you just need to provide the users email to the connect function.
*
* You can setup the hook with the following configuration:
* ```javascript
* import { useMagic } from "@thirdweb-dev/react"
* import { useState } from "react"
*
* const LoginWithMagicLink = () => {
* const connectWithMagic = useMagic()
* const [email, setEmail] = useState()
*
* return (
* <div>
* <input value={email} onChange={(e) => setEmail(e.target.value)} />
* <button onClick={() => connectWithMagic({ email })}>Login</button>
* </div>
* )
* }
* ```
*
* @public
*/
export function useMagic() {
const wagmiContext = useWagmiContext();
invariant(
wagmiContext,
`useMagic() can only be used inside <ThirdwebProvider />. If you are using <ThirdwebSDKProvider /> you will have to use your own wallet-connection logic.`,
);
const [connectors, connect] = useConnect();
if (connectors.loading) {
return () => Promise.reject("Magic connector not ready to be used, yet");
}
const connector = connectors.data.connectors.find((c) => c.id === "magic");
invariant(
connector,
"Magic connector not found, please make sure it is provided to your <ThirdwebProvider />",
);
return (configuration: LoginWithMagicLinkConfiguration) => {
(connector as MagicConnector).setConfiguration(configuration);
return connect(connector);
};
}
@@ -1,10 +1,10 @@
import { useConnect } from "../wagmi-required/useConnect";
import { Buffer } from "buffer";
import invariant from "tiny-invariant";
import { useContext as useWagmiContext } from "wagmi";
if (!globalThis.Buffer) {
globalThis.Buffer = require("buffer/").Buffer;
}
globalThis.Buffer = Buffer;
/**
* Hook for connecting to a mobile wallet with Wallet Connect
*
@@ -1,10 +1,10 @@
import { useConnect } from "../wagmi-required/useConnect";
import { Buffer } from "buffer";
import invariant from "tiny-invariant";
import { useContext as useWagmiContext } from "wagmi";
if (!globalThis.Buffer) {
globalThis.Buffer = require("buffer/").Buffer;
}
globalThis.Buffer = Buffer;
/**
* Hook for connecting to a Coinbase wallet.
*
@@ -1,4 +1,4 @@
import { RequiredParam } from "../../../core/types/shared";
import { RequiredParam } from "../../../core/query-utils/required-param";
import { showDeprecationWarning } from "../../utils/deprecation-warning";
import { useContract } from "../async/contracts";
@@ -28,8 +28,8 @@ import { useContract } from "../async/contracts";
* @deprecated
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
* ```diff
* - const edition = await sdk.useEdition("0x1234...");
* + const edition = await sdk.useContract("0x1234...", "edition").contract;
* - const edition = useEdition("0x1234...");
* + const edition = useContract("0x1234...", "edition").contract;
* ```
*/
export function useEdition(contractAddress: RequiredParam<string>) {
@@ -1,4 +1,4 @@
import { RequiredParam } from "../../../core/types/shared";
import { RequiredParam } from "../../../core/query-utils/required-param";
import { showDeprecationWarning } from "../../utils/deprecation-warning";
import { useContract } from "../async/contracts";
@@ -27,8 +27,8 @@ import { useContract } from "../async/contracts";
* @deprecated
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
* ```diff
* - const editionDrop = await sdk.useEditionDrop("0x1234...");
* + const editionDrop = await sdk.useContract("0x1234...", "edition-drop").contract;
* - const editionDrop = useEditionDrop("0x1234...");
* + const editionDrop = useContract("0x1234...", "edition-drop").contract;
* ```
*/
export function useEditionDrop(contractAddress: RequiredParam<string>) {
@@ -1,4 +1,4 @@
import { RequiredParam } from "../../../core/types/shared";
import { RequiredParam } from "../../../core/query-utils/required-param";
import { showDeprecationWarning } from "../../utils/deprecation-warning";
import { useContract } from "../async/contracts";
@@ -28,8 +28,8 @@ import { useContract } from "../async/contracts";
* @deprecated
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
* ```diff
* - const marketplace = await sdk.useMarketplace("0x1234...");
* + const marketplace = await sdk.useContract("0x1234...", "marketplace").contract;
* - const marketplace = useMarketplace("0x1234...");
* + const marketplace = useContract("0x1234...", "marketplace").contract;
* ```
*/
export function useMarketplace(contractAddress: RequiredParam<string>) {
@@ -1,4 +1,4 @@
import { RequiredParam } from "../../../core/types/shared";
import { RequiredParam } from "../../../core/query-utils/required-param";
import { showDeprecationWarning } from "../../utils/deprecation-warning";
import { useContract } from "../async/contracts";
@@ -27,8 +27,8 @@ import { useContract } from "../async/contracts";
* @deprecated
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
* ```diff
* - const multiwrap = await sdk.useMultiwrap("0x1234...");
* + const multiwrap = await sdk.useContract("0x1234...", "multiwrap").contract;
* - const multiwrap = useMultiwrap("0x1234...");
* + const multiwrap = useContract("0x1234...", "multiwrap").contract;
* ```
*/
export function useMultiwrap(contractAddress: RequiredParam<string>) {
@@ -1,4 +1,4 @@
import { RequiredParam } from "../../../core/types/shared";
import { RequiredParam } from "../../../core/query-utils/required-param";
import { showDeprecationWarning } from "../../utils/deprecation-warning";
import { useContract } from "../async/contracts";
@@ -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
*
@@ -28,8 +28,8 @@ import { useContract } from "../async/contracts";
* @deprecated
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
* ```diff
* - const nftCollection = await sdk.useNFTCollection("0x1234...");
* + const nftCollection = await sdk.useContract("0x1234...", "nft-collection").contract;
* - const nftCollection = useNFTCollection("0x1234...");
* + const nftCollection = useContract("0x1234...", "nft-collection").contract;
* ```
*/
export function useNFTCollection(contractAddress: RequiredParam<string>) {
@@ -1,4 +1,4 @@
import { RequiredParam } from "../../../core/types/shared";
import { RequiredParam } from "../../../core/query-utils/required-param";
import { showDeprecationWarning } from "../../utils/deprecation-warning";
import { useContract } from "../async/contracts";
@@ -27,8 +27,8 @@ import { useContract } from "../async/contracts";
* @deprecated
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
* ```diff
* - const nftDrop = await sdk.useNFTDrop("0x1234...");
* + const nftDrop = await sdk.useContract("0x1234...", "nft-drop").contract;
* - const nftDrop = useNFTDrop("0x1234...");
* + const nftDrop = useContract("0x1234...", "nft-drop").contract;
* ```
*/
export function useNFTDrop(contractAddress: RequiredParam<string>) {
@@ -1,4 +1,4 @@
import { RequiredParam } from "../../../core/types/shared";
import { RequiredParam } from "../../../core/query-utils/required-param";
import { showDeprecationWarning } from "../../utils/deprecation-warning";
import { useContract } from "../async/contracts";
@@ -28,8 +28,8 @@ import { useContract } from "../async/contracts";
* @deprecated
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
* ```diff
* - const pack = await sdk.usePack("0x1234...");
* + const pack = await sdk.useContract("0x1234...", "pack").contract;
* - const pack = usePack("0x1234...");
* + const pack = useContract("0x1234...", "pack").contract;
* ```
*/
export function usePack(contractAddress: RequiredParam<string>) {
@@ -1,4 +1,4 @@
import { RequiredParam } from "../../../core/types/shared";
import { RequiredParam } from "../../../core/query-utils/required-param";
import { showDeprecationWarning } from "../../utils/deprecation-warning";
import { useContract } from "../async/contracts";
@@ -27,8 +27,8 @@ import { useContract } from "../async/contracts";
* @deprecated
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
* ```diff
* - const signatureDrop = await sdk.useSignatureDrop("0x1234...");
* + const signatureDrop = await sdk.useContract("0x1234...", "signature-drop").contract;
* - const signatureDrop = useSignatureDrop("0x1234...");
* + const signatureDrop = useContract("0x1234...", "signature-drop").contract;
* ```
*/
export function useSignatureDrop(contractAddress?: RequiredParam<string>) {
@@ -1,4 +1,4 @@
import { RequiredParam } from "../../../core/types/shared";
import { RequiredParam } from "../../../core/query-utils/required-param";
import { showDeprecationWarning } from "../../utils/deprecation-warning";
import { useContract } from "../async/contracts";
@@ -28,8 +28,8 @@ import { useContract } from "../async/contracts";
* @deprecated
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
* ```diff
* - const split = await sdk.useSplit("0x1234...");
* + const split = await sdk.useContract("0x1234...", "split").contract;
* - const split = useSplit("0x1234...");
* + const split = useContract("0x1234...", "split").contract;
* ```
*/
export function useSplit(contractAddress: RequiredParam<string>) {
@@ -1,4 +1,4 @@
import { RequiredParam } from "../../../core/types/shared";
import { RequiredParam } from "../../../core/query-utils/required-param";
import { showDeprecationWarning } from "../../utils/deprecation-warning";
import { useContract } from "../async/contracts";
@@ -28,8 +28,8 @@ import { useContract } from "../async/contracts";
* @deprecated
* This hook is deprecated and will be removed in a future major version. You should use {@link useContract} instead.
* ```diff
* - const token = await sdk.useToken("0x1234...");
* + const token = await sdk.useContract("0x1234...", "token").contract;
* - const token = useToken("0x1234...");
* + const token = useContract("0x1234...", "token").contract;
* ```
*/
export function useToken(contractAddress: RequiredParam<string>) {

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