Compare commits

...
Author SHA1 Message Date
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
c9b0131acd Version Packages (#1478)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-08-10 15:51:09 -07:00
Joaquim VergesandGitHub 34b315993c [Wallets] use RPCs with no client id when adding to external wallets (#1477) 2023-08-10 22:33:47 +00:00
iketwandGitHub 14d9a71c92 [RN] Deprecates magicWallet in favor of magicLink for consistency (#1479) 2023-08-10 21:22:49 +00:00
YashandGitHub 7f5311222b [SDK] Enable dynamic contract deployment with any evm (#1468) 2023-08-10 19:32:51 +00:00
github-actions[bot]GitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
b4847dd134 Version Packages (#1464)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-08-09 16:00:33 -07:00
Danny FridayandGitHub cf82c3b58c Improve error logging when authentication fails (#1475) 2023-08-09 21:37:09 +00:00
Adam MajmudarandGitHub a17326634e [Chains] Add back scroll-alpha-testnet (#1474) 2023-08-09 19:24:04 +00:00
70c4a119d6 Add sdk information in headers for various services (#1472)
Co-authored-by: Manan Tank <[email protected]>
2023-08-09 19:22:46 +00:00
Joaquim VergesandGitHub f0443bd989 [SDK] Expose erc721.claimConditions.getSupplyClaimedByWallet() (#1471) 2023-08-09 19:05:11 +00:00
Jonas DanielsandGitHub 73462ef108 [multi] only evaluate auth token if it is a valid string (#1473) 2023-08-09 18:07:26 +00:00
Jonas DanielsandGitHub 27c225a512 feat(urls): add clientId parameter to getGatewayUrlForCid (#1470) 2023-08-09 03:20:53 +00:00
Jonas DanielsandGitHub cb1c9937fa refactor(urls): Simplify authentication strategy handling (#1469) 2023-08-08 21:07:27 +00:00
Kien NgoandGitHub 588b210601 [react, react-native]Add option to hide the "Request Testnet Funds" button (#1458) 2023-08-08 08:38:37 -07:00
Phillip HoandGitHub 7e483ec97f [service-utils] Silence publishUsageEvents() output (#1466) 2023-08-08 00:20:09 +00:00
Joaquim VergesandGitHub c902901cff [All] Added PR template (#1465) 2023-08-07 23:57:31 +00:00
Phillip HoandGitHub 205018f6e1 [service-utils] Add userOpHash field (#1463) 2023-08-07 23:41:43 +00:00
FirekeeperandGitHub 269e68c0a1 Firekeeper/xai and large chainids (#1461) 2023-08-07 23:14:23 +00:00
Jonas DanielsandGitHub 2888efc065 build: Add TW_SECRET_KEY to test and e2e environments (#1462) 2023-08-07 21:14:00 +00:00
91 changed files with 1655 additions and 2846 deletions
+13
View File
@@ -0,0 +1,13 @@
## Problem solved
Short description of the bug fixed or feature added
## Changes made
- [ ] Public API changes: list the public API changes made if any
- [ ] Internal API changes: explain the internal logic changes
## How to test
- [ ] Automated tests: link to unit test file
- [ ] Manual tests: step by step instructions on how to test
+1 -1
View File
@@ -31,7 +31,7 @@
"hotlink-revert": "node ./scripts/hotlink/hotlink-revert.mjs",
"explain:major": "node ./scripts/changeset-explain-major.mjs"
},
"packageManager": "pnpm@8.1.0",
"packageManager": "pnpm@8.6.12",
"dependencies": {
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.2",
+14
View File
@@ -1,5 +1,19 @@
# @thirdweb-dev/auth
## 3.2.30
### Patch Changes
- Updated dependencies [[`34b31599`](https://github.com/thirdweb-dev/js/commit/34b315993c0abaccb9640a5d5804c2c93af569c2)]:
- @thirdweb-dev/wallets@1.1.13
## 3.2.29
### Patch Changes
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed)]:
- @thirdweb-dev/wallets@1.1.12
## 3.2.28
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/auth",
"version": "3.2.28",
"version": "3.2.30",
"main": "dist/thirdweb-dev-auth.cjs.js",
"module": "dist/thirdweb-dev-auth.esm.js",
"browser": {
+12
View File
@@ -1,5 +1,17 @@
# @thirdweb-dev/chains
## 0.1.43
### Patch Changes
- [#1469](https://github.com/thirdweb-dev/js/pull/1469) [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308) Thanks [@jnsdls](https://github.com/jnsdls)! - update chains
- [#1474](https://github.com/thirdweb-dev/js/pull/1474) [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9) Thanks [@adam-maj](https://github.com/adam-maj)! - Add back scroll-alpha-testnet
- [#1458](https://github.com/thirdweb-dev/js/pull/1458) [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Update chains
- [#1461](https://github.com/thirdweb-dev/js/pull/1461) [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30) Thanks [@0xFirekeeper](https://github.com/0xFirekeeper)! - add xai-goerli chain and support BigInteger from Unity
## 0.1.42
### Patch Changes
+2 -2
View File
@@ -3,7 +3,7 @@ export default {
"name": "Ultron Testnet",
"chain": "Ultron",
"icon": {
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
"width": 512,
"height": 512,
"format": "png"
@@ -27,7 +27,7 @@ export default {
"name": "Ultron Testnet Explorer",
"url": "https://explorer.ultron-dev.io",
"icon": {
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
"width": 512,
"height": 512,
"format": "png"
+2 -2
View File
@@ -3,7 +3,7 @@ export default {
"name": "Ultron Mainnet",
"chain": "Ultron",
"icon": {
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
"width": 512,
"height": 512,
"format": "png"
@@ -27,7 +27,7 @@ export default {
"name": "Ultron Explorer",
"url": "https://ulxscan.com",
"icon": {
"url": "ipfs://QmS4W4kY7XYBA4f52vuuytXh3YaTcNBXF14V9tEY6SNqhz",
"url": "ipfs://QmPC6odFVyAQrXJQaZJVFpEQfRNbzZ5BjDZ7KBKmXPaYDw",
"width": 512,
"height": 512,
"format": "png"
+7 -7
View File
@@ -1,10 +1,10 @@
import type { Chain } from "../src/types";
export default {
"name": "Credit Smartchain Mainnet",
"name": "Credit Smart Chain",
"chain": "CREDIT",
"rpc": [
"https://credit-smartchain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://mainnet-rpc.cscscan.io"
"https://credit-smart-chain.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.creditsmartchain.com"
],
"faucets": [],
"nativeCurrency": {
@@ -23,7 +23,7 @@ export default {
"infoURL": "https://creditsmartchain.com",
"shortName": "Credit",
"chainId": 13308,
"networkId": 1,
"networkId": 13308,
"icon": {
"url": "ipfs://bafkreifbso3gd4wu5wxl27xyurxctmuae2jyuy37guqtzx23nga6ba4ag4",
"width": 1000,
@@ -32,8 +32,8 @@ export default {
},
"explorers": [
{
"name": "CSC Scan",
"url": "https://explorer.cscscan.io",
"name": "Creditscan",
"url": "https://scan.creditsmartchain.com",
"icon": {
"url": "ipfs://bafkreifbso3gd4wu5wxl27xyurxctmuae2jyuy37guqtzx23nga6ba4ag4",
"width": 1000,
@@ -44,5 +44,5 @@ export default {
}
],
"testnet": false,
"slug": "credit-smartchain"
"slug": "credit-smart-chain"
} as const satisfies Chain;
+24
View File
@@ -0,0 +1,24 @@
import type { Chain } from "../src/types";
export default {
"name": "Humanode Testnet 5 Israfel",
"chain": "Humanode Testnet 5",
"rpc": [
"https://humanode-testnet-5-israfel.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://explorer-rpc-http.testnet5.stages.humanode.io"
],
"faucets": [
"https://t.me/HumanodeTestnet5FaucetBot"
],
"nativeCurrency": {
"name": "HMND",
"symbol": "HMND",
"decimals": 18
},
"infoURL": "https://humanode.io",
"shortName": "hmnd-t5",
"chainId": 14853,
"networkId": 14853,
"explorers": [],
"testnet": true,
"slug": "humanode-testnet-5-israfel"
} as const satisfies Chain;
+6 -6
View File
@@ -3,9 +3,9 @@ export default {
"name": "Lightlink Phoenix Mainnet",
"chain": "Lightlink Phoenix Mainnet",
"icon": {
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
"width": 600,
"height": 600,
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
"width": 200,
"height": 200,
"format": "png"
},
"rpc": [
@@ -33,9 +33,9 @@ export default {
"name": "phoenix",
"url": "https://phoenix.lightlink.io",
"icon": {
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
"width": 600,
"height": 600,
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
"width": 200,
"height": 200,
"format": "png"
},
"standard": "EIP3091"
+6 -6
View File
@@ -3,9 +3,9 @@ export default {
"name": "Lightlink Pegasus Testnet",
"chain": "Lightlink Pegasus Testnet",
"icon": {
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
"width": 600,
"height": 600,
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
"width": 200,
"height": 200,
"format": "png"
},
"rpc": [
@@ -35,9 +35,9 @@ export default {
"name": "pegasus",
"url": "https://pegasus.lightlink.io",
"icon": {
"url": "ipfs://QmNRUoMgx16hurD3au3ou5A9rmTLYmre8WiGmQEPFmP2Vo",
"width": 600,
"height": 600,
"url": "ipfs://QmXMDj6iAFn2ducQcUU1M87PMMdT2jfyL3Tp3Lz5uUD5Lv",
"width": 200,
"height": 200,
"format": "png"
},
"standard": "EIP3091"
+1 -1
View File
@@ -4,7 +4,7 @@ export default {
"chain": "REAP",
"rpc": [
"https://reapchain-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://test-rpc.reapchain.org"
"https://test-eth.reapchain.org"
],
"faucets": [
"http://faucet.reapchain.com"
+27
View File
@@ -0,0 +1,27 @@
import type { Chain } from "../src/types";
export default {
"name": "Xai Goerli Orbit",
"chain": "Xai Goerli Orbit Testnet",
"shortName": "xai-goerli",
"chainId": 47279324479,
"testnet": true,
"nativeCurrency": {
"name": "Xai Goerli Ether",
"symbol": "ETH",
"decimals": 18
},
"rpc": [
"https://xai-goerli-orbit.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet.xai-chain.net/rpc"
],
"explorers": [
{
"name": "Xai Goerli Testnet Explorer",
"url": "https://testnet-explorer.xai-chain.net",
"standard": "EIP3091"
}
],
"faucets": [],
"infoURL": "https://xai.games/",
"slug": "xai-goerli-orbit"
} as const satisfies Chain;
+17 -4
View File
@@ -2,8 +2,11 @@ import type { Chain } from "../src/types";
export default {
"name": "Scroll Sepolia Testnet",
"chain": "ETH",
"status": "incubating",
"rpc": [],
"status": "active",
"rpc": [
"https://scroll-sepolia-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://sepolia-rpc.scroll.io/"
],
"faucets": [],
"nativeCurrency": {
"name": "Ether",
@@ -14,11 +17,21 @@ export default {
"shortName": "scr-sepolia",
"chainId": 534351,
"networkId": 534351,
"explorers": [],
"explorers": [
{
"name": "Scroll Sepolia Testnet Block Explorer",
"url": "https://sepolia-blockscout.scroll.io",
"standard": "EIP3091"
}
],
"parent": {
"type": "L2",
"chain": "eip155-11155111",
"bridges": []
"bridges": [
{
"url": "https://scroll.io/bridge"
}
]
},
"testnet": true,
"slug": "scroll-sepolia-testnet"
+16 -3
View File
@@ -3,7 +3,10 @@ export default {
"name": "Scroll",
"chain": "ETH",
"status": "incubating",
"rpc": [],
"rpc": [
"https://scroll.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://rpc.scroll.io"
],
"faucets": [],
"nativeCurrency": {
"name": "Ether",
@@ -14,11 +17,21 @@ export default {
"shortName": "scr",
"chainId": 534352,
"networkId": 534352,
"explorers": [],
"explorers": [
{
"name": "Scroll Mainnet Block Explorer",
"url": "https://blockscout.scroll.io",
"standard": "EIP3091"
}
],
"parent": {
"type": "L2",
"chain": "eip155-1",
"bridges": []
"bridges": [
{
"url": "https://scroll.io/bridge"
}
]
},
"testnet": false,
"slug": "scroll"
+2 -7
View File
@@ -2,7 +2,7 @@ import type { Chain } from "../src/types";
export default {
"name": "Scroll Alpha Testnet",
"chain": "ETH",
"status": "active",
"status": "deprecated",
"rpc": [
"https://scroll-alpha-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://alpha-rpc.scroll.io/l2"
@@ -20,12 +20,7 @@ export default {
"explorers": [
{
"name": "Scroll Alpha Testnet Block Explorer",
"url": "https://blockscout.scroll.io",
"standard": "EIP3091"
},
{
"name": "Scroll Alpha Testnet Block Explorer",
"url": "https://scrollscan.co",
"url": "https://alpha-blockscout.scroll.io",
"standard": "EIP3091"
}
],
+6 -2
View File
@@ -9,7 +9,11 @@ export default {
"https://evm-dataseed3.meerscan.io",
"https://evm-dataseed.meerscan.com",
"https://evm-dataseed1.meerscan.com",
"https://evm-dataseed2.meerscan.com"
"https://evm-dataseed2.meerscan.com",
"https://qng.rpc.qitmeer.io",
"https://mainnet.meerlabs.com",
"https://rpc.dimai.ai",
"https://rpc.woowow.io"
],
"faucets": [],
"nativeCurrency": {
@@ -37,7 +41,7 @@ export default {
"height": 512,
"format": "png"
},
"url": "https://evm.meerscan.com",
"url": "https://qng.meerscan.io",
"standard": "none"
}
],
+10 -3
View File
@@ -2,8 +2,15 @@ import type { Chain } from "../src/types";
export default {
"name": "Qitmeer Network Testnet",
"chain": "MEER",
"rpc": [],
"faucets": [],
"rpc": [
"https://qitmeer-network-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://testnet-qng.rpc.qitmeer.io",
"https://testnet.meerlabs.com",
"https://meer.testnet.meerfans.club"
],
"faucets": [
"https://faucet.qitmeer.io"
],
"nativeCurrency": {
"name": "Qitmeer Testnet",
"symbol": "MEER-T",
@@ -28,7 +35,7 @@ export default {
"height": 512,
"format": "png"
},
"url": "https://testnet.qng.meerscan.io",
"url": "https://qng-testnet.meerscan.io",
"standard": "none"
}
],
+5 -1
View File
@@ -2,7 +2,11 @@ import type { Chain } from "../src/types";
export default {
"name": "IMPERIUM TESTNET",
"chain": "tIMP",
"rpc": [],
"rpc": [
"https://imperium-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://data-aws-testnet.imperiumchain.com",
"https://data-aws2-testnet.imperiumchain.com"
],
"faucets": [
"https://faucet.imperiumchain.com/"
],
+5 -1
View File
@@ -2,7 +2,11 @@ import type { Chain } from "../src/types";
export default {
"name": "IMPERIUM MAINNET",
"chain": "IMP",
"rpc": [],
"rpc": [
"https://imperium.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
"https://data-aws-mainnet.imperiumchain.com",
"https://data-aws2-mainnet.imperiumchain.com"
],
"faucets": [
"https://faucet.imperiumchain.com/"
],
@@ -0,0 +1,26 @@
// @ts-check
/** @typedef { import("../../src/types").Chain } Chain */
/** @type {Omit<Chain, "slug">} */
export default {
name: "Xai Goerli Orbit",
chain: "Xai Goerli Orbit Testnet",
shortName: "xai-goerli",
chainId: 47279324479,
testnet: true,
nativeCurrency: {
name: "Xai Goerli Ether",
symbol: "ETH",
decimals: 18,
},
rpc: ["https://testnet.xai-chain.net/rpc"],
explorers: [
{
name: "Xai Goerli Testnet Explorer",
url: "https://testnet-explorer.xai-chain.net",
standard: "EIP3091",
},
],
faucets: [],
infoURL: "https://xai.games/",
};
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/chains",
"version": "0.1.42",
"version": "0.1.43",
"main": "dist/thirdweb-dev-chains.cjs.js",
"module": "dist/thirdweb-dev-chains.esm.js",
"browser": {
+2 -1
View File
@@ -105,7 +105,8 @@ for (const file of additionalChainsFiles) {
}
chains = chains
.filter((c) => c.status !== "deprecated")
// Keep scroll-alpha-testnet for now even though its deprecated
.filter((c) => c.status !== "deprecated" || c.chainId === 534353)
.map((chain) => {
if (overrides[chain.chainId]) {
chain = merge(chain, overrides[chain.chainId], {
File diff suppressed because one or more lines are too long
+16
View File
@@ -1,5 +1,21 @@
# thirdweb
## 0.11.13
### Patch Changes
- Updated dependencies [[`7f531122`](https://github.com/thirdweb-dev/js/commit/7f5311222b14da04877df056baae36409dff4696)]:
- @thirdweb-dev/sdk@3.10.49
## 0.11.12
### Patch Changes
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`27c225a5`](https://github.com/thirdweb-dev/js/commit/27c225a51221417592b5940887abd1ccb8b67e47), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
- @thirdweb-dev/storage@1.2.5
- @thirdweb-dev/sdk@3.10.48
- @thirdweb-dev/chains@0.1.43
## 0.11.11
### Patch Changes
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "thirdweb",
"main": "dist/cli/index.js",
"version": "0.11.11",
"version": "0.11.13",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
+20
View File
@@ -1,5 +1,25 @@
# @thirdweb-dev/react-core
## 3.14.30
### Patch Changes
- Updated dependencies [[`34b31599`](https://github.com/thirdweb-dev/js/commit/34b315993c0abaccb9640a5d5804c2c93af569c2), [`7f531122`](https://github.com/thirdweb-dev/js/commit/7f5311222b14da04877df056baae36409dff4696)]:
- @thirdweb-dev/wallets@1.1.13
- @thirdweb-dev/sdk@3.10.49
- @thirdweb-dev/auth@3.2.30
## 3.14.29
### Patch Changes
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`27c225a5`](https://github.com/thirdweb-dev/js/commit/27c225a51221417592b5940887abd1ccb8b67e47), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
- @thirdweb-dev/storage@1.2.5
- @thirdweb-dev/wallets@1.1.12
- @thirdweb-dev/sdk@3.10.48
- @thirdweb-dev/chains@0.1.43
- @thirdweb-dev/auth@3.2.29
## 3.14.28
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-core",
"version": "3.14.28",
"version": "3.14.30",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -1,5 +1,9 @@
# @thirdweb-dev/react-native-compat
## 0.2.49
## 0.2.48
## 0.2.47
## 0.2.46
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@thirdweb-dev/react-native-compat",
"description": "Shims for Thirdweb in React Native Projects",
"version": "0.2.47",
"version": "0.2.49",
"author": "thirdweb eng <[email protected]>",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
"license": "Apache-2.0",
+30
View File
@@ -1,5 +1,35 @@
# @thirdweb-dev/react-native
## 0.2.49
### Patch Changes
- [#1479](https://github.com/thirdweb-dev/js/pull/1479) [`14d9a71c`](https://github.com/thirdweb-dev/js/commit/14d9a71c928019907618cc8694af0bc631e94b68) Thanks [@iketw](https://github.com/iketw)! - Deprecates magicWallet in favor of magicLink for consistency with our React package
- [#1477](https://github.com/thirdweb-dev/js/pull/1477) [`34b31599`](https://github.com/thirdweb-dev/js/commit/34b315993c0abaccb9640a5d5804c2c93af569c2) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Pass unauth'd RPCs to wallets when adding new chains
- Updated dependencies [[`34b31599`](https://github.com/thirdweb-dev/js/commit/34b315993c0abaccb9640a5d5804c2c93af569c2), [`7f531122`](https://github.com/thirdweb-dev/js/commit/7f5311222b14da04877df056baae36409dff4696)]:
- @thirdweb-dev/wallets@1.1.13
- @thirdweb-dev/sdk@3.10.49
- @thirdweb-dev/react-core@3.14.30
## 0.2.48
### Patch Changes
- [#1458](https://github.com/thirdweb-dev/js/pull/1458) [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Add `hideTestnetFaucet` to hide the "Request Testnet funds" button in ConnectWallet details dropdown in `@thirdweb-dev/react-native` and `@thirdweb-dev/react`.
```ts
<ConnectWallet hideTestnetFaucet={true} />
```
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`27c225a5`](https://github.com/thirdweb-dev/js/commit/27c225a51221417592b5940887abd1ccb8b67e47), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 0.2.47
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react-native",
"version": "0.2.47",
"version": "0.2.49",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -19,6 +19,13 @@ export type ConnectWalletProps = {
* render custom rows in the Connect Wallet Details modal
*/
extraRows?: ConnectWalletDetailsProps["extraRows"];
/**
* Hide option to request testnet funds for testnets in dropdown
*
* @default false
*/
hideTestnetFaucet?: boolean;
} & ConnectWalletButtonProps;
export const ConnectWallet = ({
@@ -27,6 +34,7 @@ export const ConnectWallet = ({
buttonTitle,
modalTitle,
extraRows,
hideTestnetFaucet,
}: ConnectWalletProps) => {
const fadeAnim = useRef(new Animated.Value(0)).current;
const address = useAddress();
@@ -47,6 +55,7 @@ export const ConnectWallet = ({
address={address}
detailsButton={detailsButton}
extraRows={extraRows}
hideTestnetFaucet={hideTestnetFaucet}
/>
) : (
<ConnectWalletButton
@@ -32,11 +32,13 @@ export const ConnectWalletDetailsModal = ({
onClosePress,
extraRows,
address,
hideTestnetFaucet,
}: {
isVisible: boolean;
onClosePress: () => void;
extraRows?: React.FC;
address?: string;
hideTestnetFaucet?: boolean;
}) => {
const theme = useAppTheme();
const [isExportModalVisible, setIsExportModalVisible] = useState(false);
@@ -198,7 +200,7 @@ export const ConnectWalletDetailsModal = ({
<Text variant="bodySmallSecondary">Current Network</Text>
</View>
<NetworkButton chain={chain} enableSwitchModal={true} />
{chain?.testnet && chain?.faucets?.length ? (
{!hideTestnetFaucet && chain?.testnet && chain?.faucets?.length ? (
<IconTextButton
mt="xs"
text="Request Testnet Funds"
@@ -14,12 +14,14 @@ export type ConnectWalletDetailsProps = {
address?: string;
detailsButton?: React.FC<{ onPress: () => void }>;
extraRows?: React.FC;
hideTestnetFaucet?: boolean;
};
export const WalletDetailsButton = ({
address,
detailsButton,
extraRows,
hideTestnetFaucet,
}: ConnectWalletDetailsProps) => {
const activeWallet = useWallet();
const chain = useChain();
@@ -46,6 +48,7 @@ export const WalletDetailsButton = ({
onClosePress={onPress}
extraRows={extraRows}
address={address}
hideTestnetFaucet={hideTestnetFaucet}
/>
{detailsButton ? (
detailsButton({ onPress })
@@ -3,7 +3,12 @@ import Modal, { ModalProps } from "react-native-modal";
// Populate with the data...
export function TWModal(props: Partial<ModalProps>) {
return (
<Modal {...props} useNativeDriver hideModalContentWhileAnimating={true}>
<Modal
{...props}
avoidKeyboard
useNativeDriver
hideModalContentWhileAnimating={true}
>
{props.children}
</Modal>
);
+4 -2
View File
@@ -15,8 +15,10 @@ export { TrustWallet, trustWallet } from "./wallets/wallets/trust-wallet";
export { smartWallet } from "./wallets/wallets/smart-wallet";
export { localWallet } from "./wallets/wallets/local-wallet";
export { LocalWallet } from "./wallets/wallets/LocalWallet";
export { magicWallet } from "./wallets/wallets/magic-wallet";
export { MagicWallet } from "./wallets/wallets/MagicWallet";
export { magicWallet } from "./wallets/wallets/magic-link";
export { MagicWallet } from "./wallets/wallets/MagicLink";
export { MagicLink } from "./wallets/wallets/MagicLink";
export { magicLink } from "./wallets/wallets/magic-link";
export * from "./wallets/wallets/WalletConnectV2";
export type { WCMeta } from "./wallets/types/wc";
@@ -7,47 +7,47 @@ import {
useState,
} from "react";
import { useWalletConnectListener } from "../wallets/hooks/useWalletConnectListener";
import { MagicWallet } from "../wallets/wallets/MagicWallet";
import { MagicLink } from "../wallets/wallets/MagicLink";
import { useWalletContext } from "@thirdweb-dev/react-core";
type DappContextType = {
smartWallet?: SmartWallet;
setSmartWallet?: (value?: SmartWallet) => void;
magicWallet?: MagicWallet;
setMagicWallet?: (value?: MagicWallet) => void;
magicLink?: MagicLink;
setMagicLink?: (value?: MagicLink) => void;
};
const DappContext = createContext<DappContextType>({});
export const DappContextProvider = (props: React.PropsWithChildren) => {
const [smartWallet, setSmartWallet] = useState<SmartWallet | undefined>();
const [magicWallet, setMagicWallet] = useState<MagicWallet | undefined>();
const [magicLink, setMagicLink] = useState<MagicLink | undefined>();
const createdWalletInstance = useWalletContext().createdWalletInstance;
useEffect(() => {
if (createdWalletInstance?.walletId === walletIds.magicLink) {
setMagicWallet(createdWalletInstance as MagicWallet);
setMagicLink(createdWalletInstance as MagicLink);
}
}, [createdWalletInstance, setMagicWallet]);
}, [createdWalletInstance, setMagicLink]);
useWalletConnectListener();
const magicSDK = useCallback(() => {
if (magicWallet) {
const magic = magicWallet.getMagicSDK();
if (magicLink) {
const magic = magicLink.getMagicSDK();
return <magic.Relayer />;
}
return null;
}, [magicWallet]);
}, [magicLink]);
return (
<DappContext.Provider
value={{
smartWallet,
setSmartWallet,
magicWallet: magicWallet,
setMagicWallet: setMagicWallet,
magicLink: magicLink,
setMagicLink: setMagicLink,
}}
>
{props.children}
@@ -66,11 +66,11 @@ export const useSmartWallet = () => {
return [context.smartWallet, context.setSmartWallet] as const;
};
export const useMagicWallet = () => {
export const useMagicLink = () => {
const context = useContext(DappContext);
return {
magicWallet: context.magicWallet,
setMagicWallet: context.setMagicWallet,
magicLink: context.magicLink,
setMagicLink: context.setMagicLink,
} as const;
};
@@ -1,3 +1,4 @@
import { Chain, getValidChainRPCs } from "@thirdweb-dev/chains";
import { WCMeta } from "../wallets/types/wc";
/**
@@ -20,3 +21,19 @@ export function formatWalletConnectDisplayUri(
}wc?uri=${encodedUri}`
: `${uri}`;
}
export function getValidPublicRPCUrl(chain: Chain) {
return getValidChainRPCs(chain).map((rpc) => {
try {
const url = new URL(rpc);
// remove client id from url
if (url.hostname.endsWith(".thirdweb.com")) {
url.pathname = "";
url.search = "";
}
return url.toString();
} catch (e) {
return rpc;
}
});
}
@@ -4,7 +4,6 @@ import type {
WalletMobileSDKProviderOptions,
} from "@coinbase/wallet-mobile-sdk/build/WalletMobileSDKEVMProvider";
import type { ConfigurationParams } from "@coinbase/wallet-mobile-sdk/src/CoinbaseWalletSDK.types";
import { getValidChainRPCs } from "@thirdweb-dev/chains";
import {
UserRejectedRequestError,
ChainNotConfiguredError,
@@ -18,6 +17,7 @@ import {
} from "@thirdweb-dev/wallets";
import type { Address } from "abitype";
import { providers, utils } from "ethers";
import { getValidPublicRPCUrl } from "evm/utils/uri";
export type CoinbaseWalletConnectorOptions = WalletMobileSDKProviderOptions &
ConfigurationParams & {
@@ -227,7 +227,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
chainId: id,
chainName: chain.name,
nativeCurrency: chain.nativeCurrency,
rpcUrls: [getValidChainRPCs(chain)],
rpcUrls: getValidPublicRPCUrl(chain), // no client id on purpose here
blockExplorerUrls: this.getBlockExplorerUrls(chain),
},
],
@@ -6,7 +6,7 @@ import {
import type { MagicConnector as MagicConnectorType } from "../connectors/magic/magic-connector";
import { MagicConnector } from "../connectors/magic/magic-connector";
export class MagicWallet extends AbstractClientWallet<
export class MagicLink extends AbstractClientWallet<
MagicLinkOptions,
MagicConnectorOptions
> {
@@ -68,3 +68,10 @@ export class MagicWallet extends AbstractClientWallet<
return super.disconnect();
}
}
/**
* @deprecated Use `MagicLink` instead
*
* Renamed for consistency with our React package
*/
export class MagicWallet extends MagicLink {}
@@ -10,22 +10,22 @@ import {
useWalletContext,
} from "@thirdweb-dev/react-core";
import { MagicLinkOptions } from "../connectors/magic/types";
import { MagicWallet } from "./MagicWallet";
import { MagicLink } from "./MagicLink";
import { useEffect, useRef } from "react";
import Box from "../../components/base/Box";
import { TextInput } from "../../components/base/TextInput";
import Text from "../../components/base/Text";
import { ActivityIndicator } from "react-native";
import { useMagicWallet } from "../../providers/context-provider";
import { useMagicLink } from "../../providers/context-provider";
export const magicWallet = (
export const magicLink = (
magicLinkOptions: MagicLinkOptions,
): WalletConfig<MagicWallet> => {
): WalletConfig<MagicLink> => {
return {
id: walletIds.magicLink,
meta: MagicWallet.meta,
meta: MagicLink.meta,
create: (options: WalletOptions) => {
return new MagicWallet({
return new MagicLink({
...options,
...magicLinkOptions,
chainId: options.chain.chainId,
@@ -42,7 +42,7 @@ export const magicWallet = (
/**
* UI for selecting wallet - this UI is rendered in the wallet selection screen
*/
selectUI: (props: SelectUIProps<MagicWallet>) => {
selectUI: (props: SelectUIProps<MagicLink>) => {
return (
<Box flex={1}>
<TextInput
@@ -71,23 +71,23 @@ export const magicWallet = (
};
const MagicConnectionUI: React.FC<
ConnectUIProps<MagicWallet> & { magicLinkOptions: MagicLinkOptions }
ConnectUIProps<MagicLink> & { magicLinkOptions: MagicLinkOptions }
> = ({ selectionData, walletConfig, close, magicLinkOptions }) => {
const createWalletInstance = useCreateWalletInstance();
const setConnectedWallet = useSetConnectedWallet();
const chainToConnect = useWalletContext().chainToConnect;
const setConnectionStatus = useSetConnectionStatus();
const { magicWallet: ctxMagicWallet, setMagicWallet } = useMagicWallet();
const { magicLink: ctxMagicLink, setMagicLink } = useMagicLink();
useEffect(() => {
const inst = createWalletInstance(walletConfig);
setMagicWallet?.(inst);
}, [createWalletInstance, setMagicWallet, walletConfig]);
setMagicLink?.(inst);
}, [createWalletInstance, setMagicLink, walletConfig]);
const connectPrompted = useRef(false);
useEffect(() => {
if (connectPrompted.current || !ctxMagicWallet) {
if (connectPrompted.current || !ctxMagicLink) {
return;
}
connectPrompted.current = true;
@@ -105,10 +105,10 @@ const MagicConnectionUI: React.FC<
: { phoneNumber: selectionData }),
};
close();
await ctxMagicWallet.connect(connectParams);
await ctxMagicWallet.getMagicSDK().user.getMetadata();
await ctxMagicLink.connect(connectParams);
await ctxMagicLink.getMagicSDK().user.getMetadata();
setConnectedWallet(ctxMagicWallet, connectParams);
setConnectedWallet(ctxMagicLink, connectParams);
setConnectionStatus("connected");
} catch (e) {
setConnectionStatus("disconnected");
@@ -119,7 +119,7 @@ const MagicConnectionUI: React.FC<
selectionData,
walletConfig,
close,
ctxMagicWallet,
ctxMagicLink,
setConnectedWallet,
setConnectionStatus,
chainToConnect?.chainId,
@@ -129,6 +129,14 @@ const MagicConnectionUI: React.FC<
return (
<Box minHeight={500}>
<ActivityIndicator size="small" />
<TextInput placeholder="Enter the OTP sent to your email / phone number" />
</Box>
);
};
/**
* @deprecated Use `magicLink()` instead
*
* Renamed for consistency with our React package
*/
export const magicWallet = magicLink;
+25
View File
@@ -1,5 +1,30 @@
# @thirdweb-dev/react
## 3.14.30
### Patch Changes
- Updated dependencies [[`34b31599`](https://github.com/thirdweb-dev/js/commit/34b315993c0abaccb9640a5d5804c2c93af569c2), [`7f531122`](https://github.com/thirdweb-dev/js/commit/7f5311222b14da04877df056baae36409dff4696)]:
- @thirdweb-dev/wallets@1.1.13
- @thirdweb-dev/sdk@3.10.49
- @thirdweb-dev/react-core@3.14.30
## 3.14.29
### Patch Changes
- [#1458](https://github.com/thirdweb-dev/js/pull/1458) [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76) Thanks [@kien-ngo](https://github.com/kien-ngo)! - Add `hideTestnetFaucet` to hide the "Request Testnet funds" button in ConnectWallet details dropdown in `@thirdweb-dev/react-native` and `@thirdweb-dev/react`.
```ts
<ConnectWallet hideTestnetFaucet={true} />
```
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
- @thirdweb-dev/[email protected]
## 3.14.28
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/react",
"version": "3.14.28",
"version": "3.14.30",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
"author": "thirdweb eng <[email protected]>",
"license": "Apache-2.0",
@@ -47,6 +47,13 @@ type ConnectWalletProps = {
};
style?: React.CSSProperties;
networkSelector?: Omit<NetworkSelectorProps, "theme" | "onClose" | "chains">;
/**
* Hide option to request testnet funds for testnets in dropdown
*
* @default false
*/
hideTestnetFaucet?: boolean;
};
const TW_CONNECT_WALLET = "tw-connect-wallet";
@@ -163,6 +170,7 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = (props) => {
theme={theme}
style={props.style}
detailsBtn={props.detailsBtn}
hideTestnetFaucet={props.hideTestnetFaucet}
onDisconnect={() => {
if (authConfig?.authUrl) {
logout();
@@ -65,6 +65,7 @@ export const ConnectedWalletDetails: React.FC<{
networkSelector?: Omit<NetworkSelectorProps, "theme" | "onClose" | "chains">;
className?: string;
detailsBtn?: () => JSX.Element;
hideTestnetFaucet?: boolean;
}> = (props) => {
const disconnect = useDisconnect();
const chains = useSupportedChains();
@@ -322,32 +323,33 @@ export const ConnectedWalletDetails: React.FC<{
)}
{/* Request Testnet funds */}
{((chain?.faucets && chain.faucets.length > 0) ||
chain?.chainId === Localhost.chainId) && (
<MenuLink
href={chain?.faucets ? chain.faucets[0] : "#"}
target="_blank"
as="a"
onClick={async (e) => {
if (chain.chainId === Localhost.chainId) {
e.preventDefault();
setOpen(false);
await sdk?.wallet.requestFunds(10);
await balanceQuery.refetch();
}
}}
style={{
textDecoration: "none",
color: "inherit",
fontSize: fontSize.sm,
}}
>
<SecondaryIconContainer>
<FundsIcon size={iconSize.sm} />
</SecondaryIconContainer>
Request Testnet Funds
</MenuLink>
)}
{!props.hideTestnetFaucet &&
((chain?.faucets && chain.faucets.length > 0) ||
chain?.chainId === Localhost.chainId) && (
<MenuLink
href={chain?.faucets ? chain.faucets[0] : "#"}
target="_blank"
as="a"
onClick={async (e) => {
if (chain.chainId === Localhost.chainId) {
e.preventDefault();
setOpen(false);
await sdk?.wallet.requestFunds(10);
await balanceQuery.refetch();
}
}}
style={{
textDecoration: "none",
color: "inherit",
fontSize: fontSize.sm,
}}
>
<SecondaryIconContainer>
<FundsIcon size={iconSize.sm} />
</SecondaryIconContainer>
Request Testnet Funds
</MenuLink>
)}
{/* Export Wallet */}
{activeWallet?.walletId === walletIds.localWallet && (
+22
View File
@@ -1,5 +1,27 @@
# @thirdweb-dev/sdk
## 3.10.49
### Patch Changes
- [#1468](https://github.com/thirdweb-dev/js/pull/1468) [`7f531122`](https://github.com/thirdweb-dev/js/commit/7f5311222b14da04877df056baae36409dff4696) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Enable dynamic contract deployment with any evm
## 3.10.48
### Patch Changes
- [#1473](https://github.com/thirdweb-dev/js/pull/1473) [`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4) Thanks [@jnsdls](https://github.com/jnsdls)! - do not pass empty auth tokens
- [#1472](https://github.com/thirdweb-dev/js/pull/1472) [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add sdk information to service request headers
- [#1471](https://github.com/thirdweb-dev/js/pull/1471) [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose erc721.claimConditions.getSupplyClaimedByWallet()
- [#1469](https://github.com/thirdweb-dev/js/pull/1469) [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308) Thanks [@jnsdls](https://github.com/jnsdls)! - fix secret key auth strategy for RPC
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`27c225a5`](https://github.com/thirdweb-dev/js/commit/27c225a51221417592b5940887abd1ccb8b67e47), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
- @thirdweb-dev/storage@1.2.5
- @thirdweb-dev/chains@0.1.43
## 3.10.47
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/sdk",
"version": "3.10.47",
"version": "3.10.49",
"description": "The main thirdweb SDK.",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
"license": "Apache-2.0",
@@ -9,8 +9,13 @@ import { fetchAndCacheDeployMetadata } from "./fetchAndCacheDeployMetadata";
import { getCreate2FactoryAddress } from "./getCreate2FactoryAddress";
import { caches } from "./caches";
import { computeDeploymentInfo } from "./computeDeploymentInfo";
import { generatePluginFunctions } from "../plugin/generatePluginFunctions";
import {
generateExtensionFunctions,
generatePluginFunctions,
} from "../plugin/generatePluginFunctions";
import { getMetadataForPlugins } from "../plugin/getMetadataForPlugins";
import { getMetadataForExtensions } from "../plugin/getMetadataForExtensions";
import { Extension } from "../../types/extensions";
/**
*
* Returns txn data for keyless deploys as well as signer deploys.
@@ -42,6 +47,10 @@ export async function getDeploymentInfo(
storage,
);
const pluginMetadata = await getMetadataForPlugins(metadataUri, storage);
const extensionMetadata = await getMetadataForExtensions(
metadataUri,
storage,
);
// if pluginMetadata is not empty, then it's a plugin-pattern router contract
if (pluginMetadata.length > 0) {
@@ -87,6 +96,42 @@ export async function getDeploymentInfo(
};
finalDeploymentInfo.push(...pluginDeploymentInfo, pluginMapTransaction);
} else if (extensionMetadata.length > 0) {
// get deployment info for all extensions
const extensionDeploymentInfo = await Promise.all(
extensionMetadata.map(async (metadata) => {
const info = await computeDeploymentInfo(
"extension",
provider,
storage,
create2FactoryAddress,
{ metadata: metadata },
);
return info;
}),
);
// create constructor param input for BaseRouter
const routerInput: Extension[] = [];
extensionMetadata.forEach((metadata, index) => {
const extensionFunctions = generateExtensionFunctions(metadata.abi);
routerInput.push({
metadata: {
name: metadata.name,
metadataURI: "",
implementation:
extensionDeploymentInfo[index].transaction.predictedAddress,
},
functions: extensionFunctions,
});
});
// routerInput as constructor param for BaseRouter
customParams["_extensions"] = {
value: routerInput,
};
finalDeploymentInfo.push(...extensionDeploymentInfo);
}
const implementationDeployInfo = await computeDeploymentInfo(
@@ -1,13 +1,18 @@
import { Abi } from "../../schema/contracts/custom";
import { utils } from "ethers";
import { Plugin } from "../../types/plugins";
import { ExtensionFunction } from "../../types/extensions";
function getFunctionSignature(fnInputs: any): string {
return (
"(" +
fnInputs
.map((i: any) => {
return i.type === "tuple" ? getFunctionSignature(i.components) : i.type;
return i.type === "tuple"
? getFunctionSignature(i.components)
: i.type === "tuple[]"
? getFunctionSignature(i.components) + `[]`
: i.type;
})
.join(",") +
")"
@@ -34,3 +39,25 @@ export function generatePluginFunctions(
}
return pluginFunctions;
}
export function generateExtensionFunctions(
extensionAbi: any,
): ExtensionFunction[] {
const extensionInterface = new utils.Interface(extensionAbi);
const extensionFunctions: ExtensionFunction[] = [];
// TODO - filter out common functions like _msgSender(), contractType(), etc.
for (const fnFragment of Object.values(extensionInterface.functions)) {
const fn = extensionInterface.getFunction(
extensionInterface.getSighash(fnFragment),
);
if (fn.name.startsWith("_")) {
continue;
}
extensionFunctions.push({
functionSelector: extensionInterface.getSighash(fn),
functionSignature: fn.name + getFunctionSignature(fn.inputs),
});
}
return extensionFunctions;
}
@@ -0,0 +1,74 @@
import { getAllExtensionsAbi } from "../../constants/thirdweb-features";
import { ContractWrapper } from "../../core/classes/contract-wrapper";
import {
AbiSchema,
PreDeployMetadataFetched,
} from "../../schema/contracts/custom";
import { isFeatureEnabled } from "../feature-detection/isFeatureEnabled";
import { ThirdwebStorage } from "@thirdweb-dev/storage";
import { getChainProvider } from "../../constants/urls";
import { fetchAndCachePublishedContractURI } from "../any-evm-utils/fetchAndCachePublishedContractURI";
import { fetchAndCacheDeployMetadata } from "../any-evm-utils/fetchAndCacheDeployMetadata";
import { Extension } from "../../types/extensions";
export async function getMetadataForExtensions(
publishedMetadataUri: string,
storage: ThirdwebStorage,
): Promise<PreDeployMetadataFetched[]> {
let extensionMetadata: PreDeployMetadataFetched[] = [];
const { compilerMetadata, extendedMetadata } =
await fetchAndCacheDeployMetadata(publishedMetadataUri, storage);
// check if contract is extension-pattern
const isExtensionRouter: boolean = isFeatureEnabled(
AbiSchema.parse(compilerMetadata.abi),
"ExtensionRouter",
);
if (isExtensionRouter) {
if (
extendedMetadata &&
extendedMetadata.factoryDeploymentData?.implementationAddresses
) {
const implementationsAddresses = Object.entries(
extendedMetadata.factoryDeploymentData.implementationAddresses,
);
try {
const entry = implementationsAddresses.find(
([, implementation]) => implementation !== "",
);
const [network, implementation] = entry ? entry : [];
if (network && implementation) {
const provider = getChainProvider(parseInt(network), {});
const contract = new ContractWrapper(
provider,
implementation,
getAllExtensionsAbi,
{},
storage,
);
const extensions = await contract.call("getAllExtensions");
const extensionNames: string[] = Array.from(
new Set(extensions.map((item: Extension) => item.metadata.name)),
);
const extensionUris = await Promise.all(
extensionNames.map((name) => {
return fetchAndCachePublishedContractURI(name);
}),
);
extensionMetadata = (
await Promise.all(
extensionUris.map(async (uri) => {
return fetchAndCacheDeployMetadata(uri, storage);
}),
)
).map((fetchedMetadata) => fetchedMetadata.compilerMetadata);
}
} catch {}
}
}
return extensionMetadata;
}
+67 -14
View File
@@ -8,6 +8,8 @@ import { getValidChainRPCs } from "@thirdweb-dev/chains";
import type { Chain } from "@thirdweb-dev/chains";
import { providers } from "ethers";
import type { Signer } from "ethers";
import pkg from "../../../package.json";
import { isBrowser } from "@thirdweb-dev/storage";
/**
* @internal
@@ -159,26 +161,76 @@ export function getProviderFromRpcUrl(
) {
try {
const headers: HeadersInit = {};
// will be used to make sure we don't cache providers with different auth strategies
let authStrategy = "none";
if (isTwUrl(rpcUrl)) {
if (sdkOptions?.clientId) {
headers["x-client-id"] = sdkOptions?.clientId;
// bundleId may already be injected
if (!rpcUrl.includes("bundleId")) {
rpcUrl =
rpcUrl +
(typeof globalThis !== "undefined" && "APP_BUNDLE_ID" in globalThis
? `?bundleId=${(globalThis as any).APP_BUNDLE_ID as string}`
: "");
// if we have a secret key passed in the SDK options we want to always use that
if (sdkOptions?.secretKey) {
// compute the clientId from the secret key
// should only be used on Node.js in a backend/script context
if (typeof window !== "undefined") {
throw new Error("Cannot use secretKey in browser context");
}
} else if (sdkOptions?.secretKey) {
headers["x-secret-key"] = sdkOptions?.secretKey;
// this is on purpose because we're using the crypto module only in node
// try to trick webpack :)
const pto = "pto";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const crypto = require("cry" + pto);
const hashedSecretKey = crypto
.createHash("sha256")
.update(sdkOptions.secretKey)
.digest("hex");
const derivedClientId = hashedSecretKey.slice(0, 32);
const utilizedRpcUrl = new URL(rpcUrl);
// always set the clientId on the path to the derived client id
utilizedRpcUrl.pathname = derivedClientId;
// set the headers
headers["x-client-id"] = derivedClientId;
headers["x-secret-key"] = sdkOptions.secretKey;
// set the final rpc url
rpcUrl = utilizedRpcUrl.toString();
authStrategy = "secretKey";
}
// if we have a tw auth token on global context add it to the headers
if (typeof globalThis !== "undefined" && "TW_AUTH_TOKEN" in globalThis) {
// if we do NOT have a secret key but we have a client id we want to use that
else if (sdkOptions?.clientId) {
const utilizedRpcUrl = new URL(rpcUrl);
// always set the clientId on the path to the client id
utilizedRpcUrl.pathname = sdkOptions.clientId;
// set the headers
headers["x-client-id"] = sdkOptions.clientId;
// set the final rpc url
rpcUrl = utilizedRpcUrl.toString();
authStrategy = "clientId";
}
// if we *also* have a tw auth token on global context add it to the headers (in addition to anything else)
if (
typeof globalThis !== "undefined" &&
"TW_AUTH_TOKEN" in globalThis &&
typeof (globalThis as any).TW_AUTH_TOKEN === "string"
) {
headers["authorization"] = `Bearer ${
(globalThis as any).TW_AUTH_TOKEN as string
}`;
authStrategy = "twAuthToken";
}
const bundleId =
typeof globalThis !== "undefined" && "APP_BUNDLE_ID" in globalThis
? ((globalThis as any).APP_BUNDLE_ID as string)
: undefined;
if (!rpcUrl.includes("bundleId")) {
rpcUrl = rpcUrl + (bundleId ? `?bundleId=${bundleId}` : "");
}
headers["x-sdk-version"] = pkg.version;
headers["x-sdk-name"] = pkg.name;
headers["x-sdk-platform"] = bundleId
? "react-native"
: isBrowser()
? "browser"
: "node";
}
const match = rpcUrl.match(/^(ws|http)s?:/i);
// Try the JSON batch provider if available
@@ -187,7 +239,7 @@ export function getProviderFromRpcUrl(
case "http":
case "https":
// Create a unique cache key for these params
const seralizedOpts = `${rpcUrl}-${chainId || -1}`;
const seralizedOpts = `${rpcUrl}-${chainId || -1}-${authStrategy}`;
// Check if we have a provider in our cache already
const existingProvider = RPC_PROVIDER_MAP.get(seralizedOpts);
@@ -217,6 +269,7 @@ export function getProviderFromRpcUrl(
case "ws":
case "wss":
// Use the WebSocketProvider for ws:// URLs
// TODO: handle auth for WS at some point
return new providers.WebSocketProvider(rpcUrl, chainId);
}
}
@@ -366,7 +366,25 @@ export class DropClaimConditions<
"Merkle proof verification failed:",
"reason" in e ? e.reason : e,
);
reasons.push(ClaimEligibility.AddressNotAllowed);
const reason = (e as any).reason;
switch (reason) {
case "!Qty":
reasons.push(ClaimEligibility.OverMaxClaimablePerWallet);
break;
case "!PriceOrCurrency":
reasons.push(ClaimEligibility.WrongPriceOrCurrency);
break;
case "!MaxSupply":
reasons.push(ClaimEligibility.NotEnoughSupply);
break;
case "cant claim yet":
reasons.push(ClaimEligibility.ClaimPhaseNotStarted);
break;
default: {
reasons.push(ClaimEligibility.AddressNotAllowed);
break;
}
}
return reasons;
}
}
@@ -376,38 +394,35 @@ export class DropClaimConditions<
this.isNewSinglePhaseDrop(this.contractWrapper) ||
this.isNewMultiphaseDrop(this.contractWrapper)
) {
const claimerProofs = await this.getClaimerProofs(resolvedAddress);
let claimedSupply = BigNumber.from(0);
let maxClaimable = convertQuantityToBigNumber(
claimCondition.maxClaimablePerWallet,
decimals,
);
if (this.isNewSinglePhaseDrop(this.contractWrapper)) {
claimedSupply =
await this.contractWrapper.readContract.getSupplyClaimedByWallet(
resolvedAddress,
);
try {
claimedSupply = await this.getSupplyClaimedByWallet(resolvedAddress);
} catch (e) {
// no-op
}
if (this.isNewMultiphaseDrop(this.contractWrapper)) {
const activeClaimConditionId =
await this.contractWrapper.readContract.getActiveClaimConditionId();
claimedSupply =
await this.contractWrapper.readContract.getSupplyClaimedByWallet(
activeClaimConditionId,
resolvedAddress,
);
}
if (claimerProofs) {
if (allowListEntry) {
maxClaimable = convertQuantityToBigNumber(
claimerProofs.maxClaimable,
allowListEntry.maxClaimable,
decimals,
);
}
if (
maxClaimable.gt(0) &&
maxClaimable.lt(claimedSupply.add(quantityWithDecimals))
) {
reasons.push(ClaimEligibility.OverMaxClaimablePerWallet);
return reasons;
}
// if there is no allowlist, or if there is an allowlist and the address is not in it
// if maxClaimable is 0, we consider it as the address is not allowed
if (!hasAllowList || (hasAllowList && !allowListEntry)) {
if (maxClaimable.lte(claimedSupply) || maxClaimable.eq(0)) {
reasons.push(ClaimEligibility.AddressNotAllowed);
@@ -508,6 +523,34 @@ export class DropClaimConditions<
}
}
/**
* Get the total supply claimed by a specific wallet
* @param walletAddress the wallet address to check
* @returns the total supply claimed
*/
public async getSupplyClaimedByWallet(
walletAddress: AddressOrEns,
): Promise<BigNumber> {
const resolvedAddress = await resolveAddress(walletAddress);
if (this.isNewSinglePhaseDrop(this.contractWrapper)) {
return await this.contractWrapper.readContract.getSupplyClaimedByWallet(
resolvedAddress,
);
}
if (this.isNewMultiphaseDrop(this.contractWrapper)) {
const activeClaimConditionId =
await this.contractWrapper.readContract.getActiveClaimConditionId();
return await this.contractWrapper.readContract.getSupplyClaimedByWallet(
activeClaimConditionId,
resolvedAddress,
);
}
throw new Error(
"This contract does not support the getSupplyClaimedByWallet function",
);
}
/** ***************************************
* WRITE FUNCTIONS
*****************************************/
@@ -50,6 +50,7 @@ import { processClaimConditionInputs } from "../../common/claim-conditions/proce
import { transformResultToClaimCondition } from "../../common/claim-conditions/transformResultToClaimCondition";
import { updateExistingClaimConditions } from "../../common/claim-conditions/updateExistingClaimConditions";
import { fetchSnapshotEntryForAddress } from "../../common/claim-conditions/fetchSnapshotEntryForAddress";
import { convertQuantityToBigNumber } from "../../common/claim-conditions/convertQuantityToBigNumber";
/**
* Manages claim conditions for Edition Drop contracts
@@ -371,7 +372,25 @@ export class DropErc1155ClaimConditions<
"Merkle proof verification failed:",
"reason" in e ? e.reason : e,
);
reasons.push(ClaimEligibility.AddressNotAllowed);
const reason = (e as any).reason;
switch (reason) {
case "!Qty":
reasons.push(ClaimEligibility.OverMaxClaimablePerWallet);
break;
case "!PriceOrCurrency":
reasons.push(ClaimEligibility.WrongPriceOrCurrency);
break;
case "!MaxSupply":
reasons.push(ClaimEligibility.NotEnoughSupply);
break;
case "cant claim yet":
reasons.push(ClaimEligibility.ClaimPhaseNotStarted);
break;
default: {
reasons.push(ClaimEligibility.AddressNotAllowed);
break;
}
}
return reasons;
}
}
@@ -381,8 +400,37 @@ export class DropErc1155ClaimConditions<
this.isNewSinglePhaseDrop(this.contractWrapper) ||
this.isNewMultiphaseDrop(this.contractWrapper)
) {
let claimedSupply = BigNumber.from(0);
let maxClaimable = convertQuantityToBigNumber(
claimCondition.maxClaimablePerWallet,
0,
);
try {
claimedSupply = await this.getSupplyClaimedByWallet(
tokenId,
resolvedAddress,
);
} catch (e) {
// no-op
}
if (allowListEntry) {
maxClaimable = convertQuantityToBigNumber(
allowListEntry.maxClaimable,
0,
);
}
if (maxClaimable.gt(0) && maxClaimable.lt(claimedSupply.add(quantity))) {
reasons.push(ClaimEligibility.OverMaxClaimablePerWallet);
return reasons;
}
// if there is no allowlist, or if there is an allowlist and the address is not in it
// if maxClaimable is 0, we consider it as the address is not allowed
if (!hasAllowList || (hasAllowList && !allowListEntry)) {
if (claimCondition.maxClaimablePerWallet === "0") {
if (maxClaimable.lte(claimedSupply) || maxClaimable.eq(0)) {
reasons.push(ClaimEligibility.AddressNotAllowed);
return reasons;
}
@@ -483,6 +531,39 @@ export class DropErc1155ClaimConditions<
}
}
/**
* Get the total supply claimed by a specific wallet
* @param walletAddress the wallet address to check
* @returns the total supply claimed
*/
public async getSupplyClaimedByWallet(
tokenId: BigNumberish,
walletAddress: AddressOrEns,
): Promise<BigNumber> {
const resolvedAddress = await resolveAddress(walletAddress);
if (this.isNewSinglePhaseDrop(this.contractWrapper)) {
return await this.contractWrapper.readContract.getSupplyClaimedByWallet(
tokenId,
resolvedAddress,
);
}
if (this.isNewMultiphaseDrop(this.contractWrapper)) {
const activeClaimConditionId =
await this.contractWrapper.readContract.getActiveClaimConditionId(
tokenId,
);
return await this.contractWrapper.readContract.getSupplyClaimedByWallet(
tokenId,
activeClaimConditionId,
resolvedAddress,
);
}
throw new Error(
"This contract does not support the getSupplyClaimedByWallet function",
);
}
/** ***************************************
* WRITE FUNCTIONS
*****************************************/
@@ -5,8 +5,14 @@ export enum ClaimEligibility {
WaitBeforeNextClaimTransaction = "Not enough time since last claim transaction. Please wait.",
ClaimPhaseNotStarted = "Claim phase has not started yet.",
AlreadyClaimed = "You have already claimed the token.",
WrongPriceOrCurrency = "Incorrect price or currency.",
OverMaxClaimablePerWallet = "Cannot claim more than maximum allowed quantity.",
NotEnoughTokens = "There are not enough tokens in the wallet to pay for the claim.",
NoActiveClaimPhase = "There is no active claim phase at the moment. Please check back in later.",
@@ -0,0 +1,31 @@
import { BytesLikeSchema } from "../../../../core/schema/shared";
import { AddressOrEnsSchema } from "../../shared/AddressOrEnsSchema";
import { z } from "zod";
/**
* @internal
*/
export const ExtensionMetadataInput = /* @__PURE__ */ (() =>
z.object({
name: z.string(),
metadataURI: z.string(),
implementation: AddressOrEnsSchema,
}))();
/**
* @internal
*/
export const ExtensionFunctionInput = /* @__PURE__ */ (() =>
z.object({
functionSelector: BytesLikeSchema,
functionSignature: z.string(),
}))();
/**
* @internal
*/
export const ExtensionInput = /* @__PURE__ */ (() =>
z.object({
metadata: ExtensionMetadataInput,
functions: z.array(ExtensionFunctionInput),
}))();
@@ -31,6 +31,7 @@ export type DeployedContractType =
| "implementation"
| "create2Factory"
| "plugin"
| "extension"
| "custom";
export type DeploymentTransaction = {
+24
View File
@@ -0,0 +1,24 @@
import {
ExtensionFunctionInput,
ExtensionInput,
ExtensionMetadataInput,
} from "../schema/contracts/common/extensions";
import { z } from "zod";
/**
* Input model to pass an extension's metadata -- name, metadataURI, implementation address
* @public
*/
export type ExtensionMetadata = z.input<typeof ExtensionMetadataInput>;
/**
* Input model to pass a list function-selectors
* @public
*/
export type ExtensionFunction = z.input<typeof ExtensionFunctionInput>;
/**
* Input model to pass a list of extension-addresses + function-selectors
* @public
*/
export type Extension = z.input<typeof ExtensionInput>;
@@ -326,6 +326,121 @@ describe("Edition Drop Contract (V4)", async () => {
expect(balance).to.deep.equal(BigNumber.from(2));
});
it("should check eligibility reasons max claims per wallet with allowlist", async () => {
await bdContract.createBatch([
{ name: "name", description: "description" },
]);
await bdContract.claimConditions.set(0, [{}]);
let c = await bdContract.claimConditions.getSupplyClaimedByWallet(
0,
w1.address,
);
expect(c.toNumber()).to.eq(0);
await sdk.updateSignerOrProvider(w1);
await bdContract.claim(0, 2);
c = await bdContract.claimConditions.getSupplyClaimedByWallet(
0,
w1.address,
);
expect(c.toNumber()).to.eq(2);
});
it("should check eligibility reasons max claims per wallet with allowlist", async () => {
await bdContract.createBatch([
{ name: "name", description: "description" },
]);
await bdContract.claimConditions.set(0, [
{
maxClaimablePerWallet: 0,
snapshot: [
{ address: w1.address, maxClaimable: 2 },
{ address: w2.address, maxClaimable: 1 },
],
},
]);
let r = await bdContract.claimConditions.getClaimIneligibilityReasons(
0,
2,
await w1.getAddress(),
);
expect(r.length).to.eq(0);
r = await bdContract.claimConditions.getClaimIneligibilityReasons(
0,
10,
await w1.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.OverMaxClaimablePerWallet);
r = await bdContract.claimConditions.getClaimIneligibilityReasons(
0,
10,
await w3.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.AddressNotAllowed);
await sdk.updateSignerOrProvider(w1);
await bdContract.claim(0, 2);
r = await bdContract.claimConditions.getClaimIneligibilityReasons(
0,
1,
await w1.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.OverMaxClaimablePerWallet);
r = await bdContract.claimConditions.getClaimIneligibilityReasons(
0,
2,
await w2.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.OverMaxClaimablePerWallet);
r = await bdContract.claimConditions.getClaimIneligibilityReasons(
0,
2,
await w3.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.AddressNotAllowed);
});
it("should check eligibility reasons max claims per wallet", async () => {
await bdContract.createBatch([
{ name: "name", description: "description" },
]);
await bdContract.claimConditions.set(0, [
{
maxClaimablePerWallet: 1,
},
]);
let r = await bdContract.claimConditions.getClaimIneligibilityReasons(
0,
1,
await w1.getAddress(),
);
expect(r.length).to.eq(0);
r = await bdContract.claimConditions.getClaimIneligibilityReasons(
0,
2,
await w1.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.OverMaxClaimablePerWallet);
await sdk.updateSignerOrProvider(w1);
await bdContract.claim(0, 1);
r = await bdContract.claimConditions.getClaimIneligibilityReasons(
0,
1,
await w1.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.OverMaxClaimablePerWallet);
});
it("should return addresses of all the claimers", async () => {
await bdContract.createBatch([
{
+111
View File
@@ -594,6 +594,117 @@ describe("NFT Drop Contract (v4)", async () => {
}
});
it("should check eligibility reasons max claims per wallet with allowlist", async () => {
await dropContract.createBatch([
{ name: "name", description: "description" },
{ name: "name2", description: "description" },
{ name: "name3", description: "description" },
{ name: "name4", description: "description" },
]);
await dropContract.claimConditions.set([{}]);
let c = await dropContract.claimConditions.getSupplyClaimedByWallet(
w1.address,
);
expect(c.toNumber()).to.eq(0);
await sdk.updateSignerOrProvider(w1);
await dropContract.claim(2);
c = await dropContract.claimConditions.getSupplyClaimedByWallet(w1.address);
expect(c.toNumber()).to.eq(2);
});
it("should check eligibility reasons max claims per wallet with allowlist", async () => {
await dropContract.createBatch([
{ name: "name", description: "description" },
{ name: "name2", description: "description" },
{ name: "name3", description: "description" },
{ name: "name4", description: "description" },
]);
await dropContract.claimConditions.set([
{
maxClaimablePerWallet: 0,
snapshot: [
{ address: w1.address, maxClaimable: 2 },
{ address: w2.address, maxClaimable: 1 },
],
},
]);
let r = await dropContract.claimConditions.getClaimIneligibilityReasons(
2,
await w1.getAddress(),
);
expect(r.length).to.eq(0);
r = await dropContract.claimConditions.getClaimIneligibilityReasons(
10,
await w1.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.OverMaxClaimablePerWallet);
r = await dropContract.claimConditions.getClaimIneligibilityReasons(
10,
await w3.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.AddressNotAllowed);
await sdk.updateSignerOrProvider(w1);
await dropContract.claim(2);
r = await dropContract.claimConditions.getClaimIneligibilityReasons(
1,
await w1.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.OverMaxClaimablePerWallet);
r = await dropContract.claimConditions.getClaimIneligibilityReasons(
2,
await w2.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.OverMaxClaimablePerWallet);
r = await dropContract.claimConditions.getClaimIneligibilityReasons(
2,
await w3.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.AddressNotAllowed);
});
it("should check eligibility reasons max claims per wallet", async () => {
await dropContract.createBatch([
{ name: "name", description: "description" },
{ name: "name2", description: "description" },
{ name: "name3", description: "description" },
{ name: "name4", description: "description" },
]);
await dropContract.claimConditions.set([
{
maxClaimablePerWallet: 1,
},
]);
let r = await dropContract.claimConditions.getClaimIneligibilityReasons(
1,
await w1.getAddress(),
);
expect(r.length).to.eq(0);
r = await dropContract.claimConditions.getClaimIneligibilityReasons(
2,
await w1.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.OverMaxClaimablePerWallet);
await sdk.updateSignerOrProvider(w1);
await dropContract.claim(1);
r = await dropContract.claimConditions.getClaimIneligibilityReasons(
1,
await w1.getAddress(),
);
expect(r[0]).to.eq(ClaimEligibility.OverMaxClaimablePerWallet);
});
it("should return the newly claimed token", async () => {
await dropContract.claimConditions.set([{}]);
await dropContract.createBatch([
+12
View File
@@ -1,5 +1,17 @@
# @thirdweb-dev/service-utils
## 0.4.2
### Patch Changes
- [#1463](https://github.com/thirdweb-dev/js/pull/1463) [`205018f6`](https://github.com/thirdweb-dev/js/commit/205018f6e191d2a2fb89f1bee276d0ea89643f30) Thanks [@arcoraven](https://github.com/arcoraven)! - Add userOpHash
- [#1473](https://github.com/thirdweb-dev/js/pull/1473) [`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4) Thanks [@jnsdls](https://github.com/jnsdls)! - handle possible empty auth tokens
- [#1475](https://github.com/thirdweb-dev/js/pull/1475) [`cf82c3b5`](https://github.com/thirdweb-dev/js/commit/cf82c3b58c92714d006f3880ec84a84893da861b) Thanks [@nessup](https://github.com/nessup)! - Improve error logging when authentication fails
- [#1466](https://github.com/thirdweb-dev/js/pull/1466) [`7e483ec9`](https://github.com/thirdweb-dev/js/commit/7e483ec97f576067d0220518b86d00794da94b4d) Thanks [@arcoraven](https://github.com/arcoraven)! - Silence output for publishUsageEvents()
## 0.4.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/service-utils",
"version": "0.4.1",
"version": "0.4.2",
"main": "dist/thirdweb-dev-service-utils.cjs.js",
"module": "dist/thirdweb-dev-service-utils.esm.js",
"exports": {
@@ -138,7 +138,7 @@ export async function extractAuthorizationData(
const authHeader = headers.get("authorization");
if (authHeader) {
const [type, token] = authHeader.split(" ");
if (type.toLowerCase() === "bearer") {
if (type.toLowerCase() === "bearer" && !!token) {
jwt = token;
}
}
@@ -186,6 +186,7 @@ export async function logHttpRequest({
statusMessage?: Error | string;
}) {
const authorizationData = await extractAuthorizationData({ req, clientId });
const headers = req.headers;
console.log(
JSON.stringify({
@@ -197,6 +198,9 @@ export async function logHttpRequest({
clientId: authorizationData.clientId,
isAuthed: !!isAuthed ?? null,
status: res.status,
sdkName: headers.get("x-sdk-name") ?? "unknown",
sdkVersion: headers.get("x-sdk-version") ?? "unknown",
platform: headers.get("x-sdk-platform") ?? "unknown",
}),
);
console.log(`statusMessage=${statusMessage ?? res.statusText}`);
+11 -7
View File
@@ -38,6 +38,7 @@ const usageEventSchema = z.object({
transactionHash: z.string().optional(),
gasLimit: z.number().nonnegative().optional(),
gasPricePerUnit: z.string().optional(),
userOpHash: z.string().optional(),
});
export type UsageEvent = z.infer<typeof usageEventSchema>;
@@ -63,7 +64,7 @@ export async function publishUsageEvents(
secretAccessKey: string;
region?: string;
},
): Promise<string> {
): Promise<void> {
const {
queueUrl,
accessKeyId,
@@ -71,17 +72,21 @@ export async function publishUsageEvents(
region = "us-west-2",
} = config;
const entries = usageEvents.map((event) => ({
Id: crypto.randomUUID(),
MessageBody: JSON.stringify(event),
}));
const entries = usageEvents.map((event) => {
// Enforce schema of usage event.
const parsed = usageEventSchema.parse(event);
return {
Id: crypto.randomUUID(),
MessageBody: JSON.stringify(parsed),
};
});
const aws = getAws({
accessKeyId,
secretAccessKey,
region,
});
const res = await aws.fetch(`https://sqs.${region}.amazonaws.com`, {
await aws.fetch(`https://sqs.${region}.amazonaws.com`, {
headers: {
"X-Amz-Target": "AmazonSQS.SendMessageBatch",
"X-Amz-Date": new Date().toISOString(),
@@ -92,5 +97,4 @@ export async function publishUsageEvents(
Entries: entries,
}),
});
return await res.text();
}
+12 -8
View File
@@ -61,12 +61,13 @@ export async function fetchKeyMetadataFromApi(
"content-type": "application/json",
},
});
if (!response.ok) {
throw new Error(
`Error fetching key metadata from API: ${response.statusText}`,
);
let json: ApiResponse
try {
json = await response.json();
} catch (e) {
throw new Error(`Error fetching key metadata from API: ${response.status} - ${response.statusText} - ${await response.text()}`);
}
return (await response.json()) as ApiResponse;
return json;
}
export async function fetchAccountFromApi(
@@ -83,8 +84,11 @@ export async function fetchAccountFromApi(
authorization: `Bearer ${jwt}`,
},
});
if (!response.ok) {
throw new Error(`Error fetching account from API: ${response.statusText}`);
let json: ApiAccountResponse
try {
json = await response.json();
} catch (e) {
throw new Error(`Error fetching account from API: ${response.status} - ${response.statusText} - ${await response.text()}`);
}
return (await response.json()) as ApiAccountResponse;
return json;
}
@@ -115,7 +115,7 @@ export async function authorize(
authorized: false,
status: 500,
errorMessage: "Failed to get account information.",
errorCode: "FAILED_TO_ACCOUNT",
errorCode: "FAILED_TO_LOAD_ACCOUNT",
};
}
}
+5 -1
View File
@@ -125,7 +125,7 @@ export function extractAuthorizationData(
const authorizationHeader = getHeader(headers, "authorization");
if (authorizationHeader) {
const [type, token] = authorizationHeader.split(" ");
if (type.toLowerCase() === "bearer") {
if (type.toLowerCase() === "bearer" && !!token) {
jwt = token;
}
}
@@ -164,6 +164,7 @@ export function logHttpRequest({
statusMessage?: Error | string;
}) {
const authorizationData = extractAuthorizationData({ req, clientId });
const headers = req.headers;
const _statusMessage = statusMessage ?? res.statusMessage;
console.log(
@@ -177,6 +178,9 @@ export function logHttpRequest({
isAuthed: !!isAuthed ?? null,
status: res.statusCode,
statusMessage: _statusMessage,
sdkName: headers["x-sdk-name"] ?? "unknown",
sdkVersion: headers["x-sdk-version"] ?? "unknown",
platform: headers["x-sdk-platform"] ?? "unknown",
}),
);
console.log(`statusMessage=${_statusMessage}`);
+10
View File
@@ -1,5 +1,15 @@
# @thirdweb-dev/storage
## 1.2.5
### Patch Changes
- [#1473](https://github.com/thirdweb-dev/js/pull/1473) [`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4) Thanks [@jnsdls](https://github.com/jnsdls)! - do not pass empty auth tokens
- [#1470](https://github.com/thirdweb-dev/js/pull/1470) [`27c225a5`](https://github.com/thirdweb-dev/js/commit/27c225a51221417592b5940887abd1ccb8b67e47) Thanks [@jnsdls](https://github.com/jnsdls)! - fix storage secretKey and clientId handling
- [#1472](https://github.com/thirdweb-dev/js/pull/1472) [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add sdk information to service request headers
## 1.2.4
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/storage",
"version": "1.2.4",
"version": "1.2.5",
"main": "dist/thirdweb-dev-storage.cjs.js",
"module": "dist/thirdweb-dev-storage.esm.js",
"browser": {
+22 -2
View File
@@ -3,6 +3,7 @@ import CIDTool from "cid-tool";
import { getProcessEnv } from "./process";
const TW_HOSTNAME_SUFFIX = ".ipfscdn.io";
const TW_STAGINGHOSTNAME_SUFFIX = ".thirdwebstorage-staging.com";
const TW_GATEWAY_URLS = [
`https://{clientId}${TW_HOSTNAME_SUFFIX}/ipfs/{cid}/{path}`,
];
@@ -13,7 +14,13 @@ const TW_GATEWAY_URLS = [
* @returns
*/
export function isTwGatewayUrl(url: string): boolean {
return new URL(url).hostname.endsWith(TW_HOSTNAME_SUFFIX);
const hostname = new URL(url).hostname;
const isProd = hostname.endsWith(TW_HOSTNAME_SUFFIX);
if (isProd) {
return true;
}
// fall back to also handle staging urls
return hostname.endsWith(TW_STAGINGHOSTNAME_SUFFIX);
}
const PUBLIC_GATEWAY_URLS = [
@@ -66,7 +73,11 @@ export function parseGatewayUrls(
/**
* @internal
*/
export function getGatewayUrlForCid(gatewayUrl: string, cid: string): string {
export function getGatewayUrlForCid(
gatewayUrl: string,
cid: string,
clientId?: string,
): string {
const parts = cid.split("/");
const hash = convertCidToV1(parts[0]);
const filePath = parts.slice(1).join("/");
@@ -86,6 +97,15 @@ export function getGatewayUrlForCid(gatewayUrl: string, cid: string): string {
else {
url += `${hash}/${filePath}`;
}
// if the URL contains the {clientId} token, replace it with the client ID
if (gatewayUrl.includes("{clientId}")) {
if (!clientId) {
throw new Error(
"Cannot use {clientId} in gateway URL without providing a client ID",
);
}
url = url.replace("{clientId}", clientId);
}
return url;
}
+11 -4
View File
@@ -148,6 +148,7 @@ export function replaceSchemeWithGatewayUrl(
uri: string,
gatewayUrls: GatewayUrls,
index = 0,
clientId?: string,
): string | undefined {
const scheme = Object.keys(gatewayUrls).find((s) => uri.startsWith(s));
const schemeGatewayUrls = scheme ? gatewayUrls[scheme] : [];
@@ -161,7 +162,7 @@ export function replaceSchemeWithGatewayUrl(
}
const path = uri.replace(scheme, "");
return getGatewayUrlForCid(schemeGatewayUrls[index], path);
return getGatewayUrlForCid(schemeGatewayUrls[index], path, clientId);
}
/**
@@ -206,9 +207,15 @@ export function replaceObjectGatewayUrlsWithSchemes<TData = unknown>(
export function replaceObjectSchemesWithGatewayUrls<TData = unknown>(
data: TData,
gatewayUrls: GatewayUrls,
clientId?: string,
): TData {
if (typeof data === "string") {
return replaceSchemeWithGatewayUrl(data, gatewayUrls) as any as TData;
return replaceSchemeWithGatewayUrl(
data,
gatewayUrls,
0,
clientId,
) as any as TData;
}
if (typeof data === "object") {
if (!data) {
@@ -219,13 +226,13 @@ export function replaceObjectSchemesWithGatewayUrls<TData = unknown>(
}
if (Array.isArray(data)) {
return data.map((entry) =>
replaceObjectSchemesWithGatewayUrls(entry, gatewayUrls),
replaceObjectSchemesWithGatewayUrls(entry, gatewayUrls, clientId),
) as any as TData;
}
return Object.fromEntries(
Object.entries(data).map(([key, value]) => [
key,
replaceObjectSchemesWithGatewayUrls(value, gatewayUrls),
replaceObjectSchemesWithGatewayUrls(value, gatewayUrls, clientId),
]),
) as any as TData;
}
@@ -1,11 +1,12 @@
import { isTwGatewayUrl } from "../../common/urls";
import { replaceSchemeWithGatewayUrl } from "../../common/utils";
import { isBrowser, replaceSchemeWithGatewayUrl } from "../../common/utils";
import {
GatewayUrls,
IStorageDownloader,
IpfsDownloaderOptions,
} from "../../types";
import fetch, { Response } from "cross-fetch";
import pkg from "../../../package.json";
/**
* Default downloader used - handles downloading from all schemes specified in the gateway URLs configuration.
@@ -54,7 +55,12 @@ export class StorageDownloader implements IStorageDownloader {
}
// Replace recognized scheme with the highest priority gateway URL that hasn't already been attempted
let resolvedUri = replaceSchemeWithGatewayUrl(uri, gatewayUrls, attempts);
let resolvedUri = replaceSchemeWithGatewayUrl(
uri,
gatewayUrls,
attempts,
this.clientId,
);
// If every gateway URL we know about for the designated scheme has been tried (via recursion) and failed, throw an error
if (!resolvedUri) {
console.error(
@@ -72,23 +78,24 @@ export class StorageDownloader implements IStorageDownloader {
let headers: HeadersInit = {};
if (isTwGatewayUrl(resolvedUri)) {
const bundleId =
typeof globalThis !== "undefined" && "APP_BUNDLE_ID" in globalThis
? ((globalThis as any).APP_BUNDLE_ID as string)
: undefined;
if (this.secretKey) {
headers = { "x-secret-key": this.secretKey };
} else if (this.clientId) {
if (
typeof globalThis !== "undefined" &&
"APP_BUNDLE_ID" in globalThis
) {
resolvedUri =
resolvedUri +
`?bundleId=${(globalThis as any).APP_BUNDLE_ID as string}`;
if (!resolvedUri.includes("bundleId")) {
resolvedUri = resolvedUri + (bundleId ? `?bundleId=${bundleId}` : "");
}
headers = {
"x-client-Id": this.clientId,
};
headers["x-client-Id"] = this.clientId;
}
// if we have a authorization token on global context then add that to the headers
if (typeof globalThis !== "undefined" && "TW_AUTH_TOKEN" in globalThis) {
if (
typeof globalThis !== "undefined" &&
"TW_AUTH_TOKEN" in globalThis &&
typeof (globalThis as any).TW_AUTH_TOKEN === "string"
) {
headers = {
...headers,
authorization: `Bearer ${
@@ -96,6 +103,14 @@ export class StorageDownloader implements IStorageDownloader {
}`,
};
}
headers["x-sdk-version"] = pkg.version;
headers["x-sdk-name"] = pkg.name;
headers["x-sdk-platform"] = bundleId
? "react-native"
: isBrowser()
? "browser"
: "node";
}
if (isTooManyRequests(resolvedUri)) {
+14 -2
View File
@@ -60,6 +60,7 @@ export class ThirdwebStorage<T extends UploadOptions = IpfsUploadBatchOptions>
private uploader: IStorageUploader<T>;
private downloader: IStorageDownloader;
private gatewayUrls: GatewayUrls;
private clientId?: string;
constructor(options?: ThirdwebStorageOptions<T>) {
this.uploader =
@@ -80,6 +81,7 @@ export class ThirdwebStorage<T extends UploadOptions = IpfsUploadBatchOptions>
options?.clientId,
options?.secretKey,
);
this.clientId = options?.clientId;
}
/**
@@ -96,7 +98,12 @@ export class ThirdwebStorage<T extends UploadOptions = IpfsUploadBatchOptions>
* ```
*/
resolveScheme(url: string): string {
return replaceSchemeWithGatewayUrl(url, this.gatewayUrls) as string;
return replaceSchemeWithGatewayUrl(
url,
this.gatewayUrls,
0,
this.clientId,
) as string;
}
/**
@@ -133,7 +140,11 @@ export class ThirdwebStorage<T extends UploadOptions = IpfsUploadBatchOptions>
// If we get a JSON object, recursively replace any schemes with gatewayUrls
const json = await res.json();
return replaceObjectSchemesWithGatewayUrls(json, this.gatewayUrls) as TJSON;
return replaceObjectSchemesWithGatewayUrls(
json,
this.gatewayUrls,
this.clientId,
) as TJSON;
}
/**
@@ -257,6 +268,7 @@ export class ThirdwebStorage<T extends UploadOptions = IpfsUploadBatchOptions>
cleaned = replaceObjectSchemesWithGatewayUrls(
cleaned,
this.gatewayUrls,
this.clientId,
) as unknown[];
}
@@ -13,6 +13,7 @@ import {
} from "../../types";
import fetch from "cross-fetch";
import FormData from "form-data";
import pkg from "../../../package.json";
/**
* Default uploader used - handles uploading arbitrary data to IPFS
@@ -241,7 +242,7 @@ export class IpfsUploader implements IStorageUploader<IpfsUploadBatchOptions> {
if (options?.uploadWithoutDirectory) {
return resolve([`ipfs://${cid}`]);
} else {
return resolve(fileNames.map((name) => `ipfs://${cid}/${name}`));
return resolve(fileNames.map((n) => `ipfs://${cid}/${n}`));
}
}
@@ -278,15 +279,27 @@ export class IpfsUploader implements IStorageUploader<IpfsUploadBatchOptions> {
xhr.setRequestHeader("x-client-id", this.clientId);
}
if (typeof globalThis !== "undefined" && "APP_BUNDLE_ID" in globalThis) {
xhr.setRequestHeader(
"x-bundle-id",
(globalThis as any).APP_BUNDLE_ID as string,
);
const bundleId =
typeof globalThis !== "undefined" && "APP_BUNDLE_ID" in globalThis
? ((globalThis as any).APP_BUNDLE_ID as string)
: undefined;
if (bundleId) {
xhr.setRequestHeader("x-bundle-id", bundleId);
}
xhr.setRequestHeader("x-sdk-version", pkg.version);
xhr.setRequestHeader("x-sdk-name", pkg.name);
xhr.setRequestHeader(
"x-sdk-platform",
bundleId ? "react-native" : isBrowser() ? "browser" : "node",
);
// if we have a authorization token on global context then add that to the headers
if (typeof globalThis !== "undefined" && "TW_AUTH_TOKEN" in globalThis) {
if (
typeof globalThis !== "undefined" &&
"TW_AUTH_TOKEN" in globalThis &&
typeof (globalThis as any).TW_AUTH_TOKEN === "string"
) {
xhr.setRequestHeader(
"authorization",
`Bearer ${(globalThis as any).TW_AUTH_TOKEN as string}`,
@@ -319,7 +332,11 @@ export class IpfsUploader implements IStorageUploader<IpfsUploadBatchOptions> {
}
// if we have a authorization token on global context then add that to the headers
if (typeof globalThis !== "undefined" && "TW_AUTH_TOKEN" in globalThis) {
if (
typeof globalThis !== "undefined" &&
"TW_AUTH_TOKEN" in globalThis &&
typeof (globalThis as any).TW_AUTH_TOKEN === "string"
) {
headers["authorization"] = `Bearer ${
(globalThis as any).TW_AUTH_TOKEN as string
}`;
+15 -11
View File
@@ -4,19 +4,22 @@ import { readFileSync } from "fs";
import { getGatewayUrlForCid, IpfsUploader, ThirdwebStorage } from "../src";
import { DEFAULT_GATEWAY_URLS, prepareGatewayUrls } from "../src/common/urls";
const apiSecretKey = process.env.TW_SECRET_KEY as string;
// load env variables
require("dotenv-mono").load();
const secretKey = process.env.TW_SECRET_KEY as string;
describe("IPFS", async () => {
if (!apiSecretKey) {
if (!secretKey) {
throw new Error("TW_SECRET_KEY is not set in the environment variables");
}
const storage = new ThirdwebStorage({
secretKey: apiSecretKey,
secretKey: secretKey,
});
const authorizedUrls = prepareGatewayUrls(
DEFAULT_GATEWAY_URLS,
undefined,
apiSecretKey,
secretKey,
);
it("Should replace tokens in tokenized gateway URL", async () => {
@@ -103,6 +106,7 @@ describe("IPFS", async () => {
...DEFAULT_GATEWAY_URLS["ipfs://"],
],
},
secretKey,
});
const uri = await storageWithBadGateways.upload(
@@ -363,16 +367,16 @@ describe("IPFS", async () => {
it("Should upload files with gateway URLs if specified on class", async () => {
const uploader = new IpfsUploader({
uploadWithGatewayUrl: true,
secretKey: apiSecretKey,
secretKey,
});
const singleStorage = new ThirdwebStorage({
uploader,
secretKey: apiSecretKey,
secretKey,
});
const _authorizedUrls = prepareGatewayUrls(
DEFAULT_GATEWAY_URLS,
undefined,
apiSecretKey,
secretKey,
);
const uri = await singleStorage.upload(
@@ -454,7 +458,7 @@ describe("IPFS", async () => {
getGatewayUrlForCid(
authorizedUrls["ipfs://"][0],
// CID changes based on file contents (prod gateway vs staging gateway since they get written)
`bafybeidnzwz6rm3jdf6vx5z7eb5ssfmeq64b5ihhjc7ioivxtc2x3f5r4m/0`,
`bafybeie4otkctycxgas34kjsvapcbqspqfj2xzjvyaet26i3nvlxv56oxy/0`,
),
);
});
@@ -462,16 +466,16 @@ describe("IPFS", async () => {
it("Should return URIs with gateway URLs if specified on class", async () => {
const uploader = new IpfsUploader({
uploadWithGatewayUrl: true,
secretKey: apiSecretKey,
secretKey,
});
const storageSingleton = new ThirdwebStorage({
uploader,
secretKey: apiSecretKey,
secretKey,
});
const _authorizedUrls = prepareGatewayUrls(
DEFAULT_GATEWAY_URLS,
undefined,
apiSecretKey,
secretKey,
);
const uri = await storageSingleton.upload(
+2 -2
View File
@@ -1,5 +1,5 @@
{
"extends": "@thirdweb-dev/tsconfig/base.json",
"extends": "@thirdweb-dev/tsconfig/sdk.json",
"include": ["."],
"exclude": ["dist", "build", "node_modules"],
"exclude": ["dist", "build", "node_modules"]
}
+22
View File
@@ -1,5 +1,27 @@
# @thirdweb-dev/unity-js-bridge
## 0.2.67
### Patch Changes
- Updated dependencies [[`34b31599`](https://github.com/thirdweb-dev/js/commit/34b315993c0abaccb9640a5d5804c2c93af569c2), [`7f531122`](https://github.com/thirdweb-dev/js/commit/7f5311222b14da04877df056baae36409dff4696)]:
- @thirdweb-dev/wallets@1.1.13
- @thirdweb-dev/sdk@3.10.49
- @thirdweb-dev/auth@3.2.30
## 0.2.66
### Patch Changes
- [#1461](https://github.com/thirdweb-dev/js/pull/1461) [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30) Thanks [@0xFirekeeper](https://github.com/0xFirekeeper)! - add xai-goerli chain and support BigInteger from Unity
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`27c225a5`](https://github.com/thirdweb-dev/js/commit/27c225a51221417592b5940887abd1ccb8b67e47), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
- @thirdweb-dev/storage@1.2.5
- @thirdweb-dev/wallets@1.1.12
- @thirdweb-dev/sdk@3.10.48
- @thirdweb-dev/chains@0.1.43
- @thirdweb-dev/auth@3.2.29
## 0.2.65
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/unity-js-bridge",
"version": "0.2.65",
"version": "0.2.67",
"main": "dist/thirdweb-unity-bridge.js",
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/unity-js-bridge",
"license": "Apache-2.0",
+10 -12
View File
@@ -71,13 +71,13 @@ interface TWBridge {
initialize: (chain: ChainIdOrName, options: string) => void;
connect: (
wallet: PossibleWallet,
chainId?: number,
chainId: string,
password?: string,
email?: string,
personalWallet?: PossibleWallet,
) => Promise<string>;
disconnect: () => Promise<void>;
switchNetwork: (chainId: number) => Promise<void>;
switchNetwork: (chainId: string) => Promise<void>;
invoke: (route: string, payload: string) => Promise<string | undefined>;
invokeListener: (
taskId: string,
@@ -299,7 +299,7 @@ class ThirdwebBridge implements TWBridge {
public async connect(
wallet: PossibleWallet = "injected",
chainId?: number | undefined,
chainId: string,
password?: string,
email?: string,
personalWallet: PossibleWallet = "localWallet",
@@ -307,15 +307,13 @@ class ThirdwebBridge implements TWBridge {
if (!this.activeSDK) {
throw new Error("SDK not initialized");
}
if (chainId === 0) {
chainId = undefined;
}
const walletInstance = this.walletMap.get(wallet);
const chainIdNumber = Number(chainId);
if (walletInstance) {
// local wallet needs to be generated or loaded before connecting
if (walletInstance.walletId === walletIds.localWallet) {
await this.initializeLocalWallet(password as string);
walletInstance.connect({ chainId });
walletInstance.connect({ chainId: chainIdNumber });
}
if (walletInstance.walletId === walletIds.magicLink) {
@@ -323,13 +321,13 @@ class ThirdwebBridge implements TWBridge {
if (!email) {
throw new Error("Email is required for Magic Link Wallet");
}
await magicLinkWallet.connect({ chainId, email });
await magicLinkWallet.connect({ chainId: chainIdNumber, email: email });
} else if (walletInstance.walletId === walletIds.paper) {
const paperWallet = walletInstance as PaperWallet;
if (!email) {
throw new Error("Email is required for Paper Wallet");
}
await paperWallet.connect({ chainId, email });
await paperWallet.connect({ chainId: chainIdNumber, email: email });
} else if (walletInstance.walletId === walletIds.smartWallet) {
const smartWallet = walletInstance as SmartWallet;
const eoaWallet = this.walletMap.get(personalWallet);
@@ -351,7 +349,7 @@ class ThirdwebBridge implements TWBridge {
);
}
} else {
await walletInstance.connect({ chainId });
await walletInstance.connect({ chainId: chainIdNumber });
}
this.activeWallet = walletInstance;
@@ -370,9 +368,9 @@ class ThirdwebBridge implements TWBridge {
}
}
public async switchNetwork(chainId: number) {
public async switchNetwork(chainId: string) {
if (chainId && this.activeWallet && "switchChain" in this.activeWallet) {
await this.activeWallet.switchChain(chainId);
await this.activeWallet.switchChain(Number(chainId));
this.updateSDKSigner(await this.activeWallet.getSigner());
} else {
throw new Error("Error Switching Network");
+21
View File
@@ -1,5 +1,26 @@
# @thirdweb-dev/wallets
## 1.1.13
### Patch Changes
- [#1477](https://github.com/thirdweb-dev/js/pull/1477) [`34b31599`](https://github.com/thirdweb-dev/js/commit/34b315993c0abaccb9640a5d5804c2c93af569c2) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Pass unauth'd RPCs to wallets when adding new chains
- Updated dependencies [[`7f531122`](https://github.com/thirdweb-dev/js/commit/7f5311222b14da04877df056baae36409dff4696)]:
- @thirdweb-dev/sdk@3.10.49
## 1.1.12
### Patch Changes
- [#1473](https://github.com/thirdweb-dev/js/pull/1473) [`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4) Thanks [@jnsdls](https://github.com/jnsdls)! - do not pass empty auth tokens
- [#1472](https://github.com/thirdweb-dev/js/pull/1472) [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add sdk information to service request headers
- Updated dependencies [[`73462ef1`](https://github.com/thirdweb-dev/js/commit/73462ef10800aeeb5976634e2bc6fb5d3e8501e4), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`70c4a119`](https://github.com/thirdweb-dev/js/commit/70c4a119d691a37ec999d9f6087902d532cc82ed), [`a1732663`](https://github.com/thirdweb-dev/js/commit/a17326634e758c3bf42f0cc3869b8792f1e18cc9), [`f0443bd9`](https://github.com/thirdweb-dev/js/commit/f0443bd989dbba50d0836d1cf274bfb2f44a53fd), [`cb1c9937`](https://github.com/thirdweb-dev/js/commit/cb1c9937fadb2d06eb148cf9819f2b3601376308), [`588b2106`](https://github.com/thirdweb-dev/js/commit/588b21060139a7c0bf5805e2c629a16792ed2c76), [`269e68c0`](https://github.com/thirdweb-dev/js/commit/269e68c0a15e8f78cb5b68c9456ca8094b9e1f30)]:
- @thirdweb-dev/sdk@3.10.48
- @thirdweb-dev/chains@0.1.43
## 1.1.11
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@thirdweb-dev/wallets",
"version": "1.1.11",
"version": "1.1.13",
"main": "dist/thirdweb-dev-wallets.cjs.js",
"module": "dist/thirdweb-dev-wallets.esm.js",
"types": "dist/thirdweb-dev-wallets.cjs.d.ts",
@@ -15,7 +15,8 @@ import type {
import BloctoSDK from "@blocto/sdk";
import { providers, utils } from "ethers";
import { walletIds } from "../../constants/walletIds";
import { Chain } from "@thirdweb-dev/chains";
import type { Chain } from "@thirdweb-dev/chains";
import { getValidPublicRPCUrl } from "../../utils/url";
type BloctoSigner = providers.JsonRpcSigner;
type BloctoOptions = Partial<EthereumProviderConfig>;
@@ -165,7 +166,12 @@ export class BloctoConnector extends WagmiConnector<
try {
await provider.request({
method: "wallet_addEthereumChain",
params: [{ chainId: id, rpcUrls: [chain?.rpc[0] ?? ""] }],
params: [
{
chainId: id,
rpcUrls: getValidPublicRPCUrl(chain), // no client id on purpose here
},
],
});
await provider.request({
@@ -15,6 +15,7 @@ import type { CoinbaseWalletSDKOptions } from "@coinbase/wallet-sdk/dist/Coinbas
import type { Chain } from "@thirdweb-dev/chains";
import { providers, utils } from "ethers";
import { walletIds } from "../../constants/walletIds";
import { getValidPublicRPCUrl } from "../../utils/url";
type Options = CoinbaseWalletSDKOptions & {
/**
@@ -231,7 +232,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
chainId: id,
chainName: chain.name,
nativeCurrency: chain.nativeCurrency,
rpcUrls: chain.rpc,
rpcUrls: getValidPublicRPCUrl(chain), // no client id on purpose here
blockExplorerUrls: this.getBlockExplorerUrls(chain),
},
],
@@ -16,6 +16,7 @@ import {
} from "../../../lib/wagmi-core";
import { Ethereum } from "../injected/types";
import { AsyncStorage } from "../../../core";
import { getValidPublicRPCUrl } from "../../utils/url";
export type FrameConnectorOptions = {
/**
@@ -241,7 +242,7 @@ export class FrameConnector extends WagmiConnector<
chainId: chainIdHex,
chainName: chain.name,
nativeCurrency: chain.nativeCurrency,
rpc: [chain.rpc[0] ?? ""],
rpcUrls: getValidPublicRPCUrl(chain), // no client id on purpose here
blockExplorerUrls: this.getBlockExplorerUrls(chain),
},
],
@@ -13,8 +13,9 @@ import {
} from "../../../lib/wagmi-core";
import { assertWindowEthereum } from "../../utils/assertWindowEthereum";
import { getInjectedName } from "../../utils/getInjectedName";
import { getValidPublicRPCUrl } from "../../utils/url";
import { Ethereum } from "./types";
import type { Chain } from "@thirdweb-dev/chains";
import { getValidChainRPCs, type Chain } from "@thirdweb-dev/chains";
import { utils, providers } from "ethers";
export type InjectedConnectorOptions = {
@@ -340,6 +341,7 @@ export class InjectedConnector extends WagmiConnector<
?.originalError?.code === 4902
) {
try {
console.log("adding chain", getValidChainRPCs(chain));
// request provider to add chain
await provider.request({
method: "wallet_addEthereumChain",
@@ -348,7 +350,7 @@ export class InjectedConnector extends WagmiConnector<
chainId: chainIdHex,
chainName: chain.name,
nativeCurrency: chain.nativeCurrency,
rpcUrls: chain.rpc as string[],
rpcUrls: getValidPublicRPCUrl(chain), // no client id on purpose here
blockExplorerUrls: this.getBlockExplorerUrls(chain),
},
],
@@ -2,8 +2,12 @@ import { providers, utils } from "ethers";
import { UserOperationStruct } from "@account-abstraction/contracts";
import { deepHexlify } from "@account-abstraction/utils";
import { isTwUrl } from "../../../utils/url";
import pkg from "../../../../../package.json";
const DEBUG = false;
function isBrowser() {
return typeof window !== "undefined";
}
export class HttpRpcClient {
private readonly userOpJsonRpcProvider: providers.JsonRpcProvider;
@@ -27,30 +31,38 @@ export class HttpRpcClient {
const headers: Record<string, string> = {};
if (isTwUrl(this.bundlerUrl)) {
if (secretKey && clientId) {
throw new Error(
"Cannot use both secret key and client ID. Please use secretKey for server-side applications and clientId for client-side applications.",
);
}
const bundleId =
typeof globalThis !== "undefined" && "APP_BUNDLE_ID" in globalThis
? ((globalThis as any).APP_BUNDLE_ID as string)
: undefined;
if (secretKey) {
headers["x-secret-key"] = secretKey;
} else if (clientId) {
headers["x-client-id"] = clientId;
if (
typeof globalThis !== "undefined" &&
"APP_BUNDLE_ID" in globalThis
) {
headers["x-bundle-id"] = (globalThis as any).APP_BUNDLE_ID as string;
if (bundleId) {
headers["x-bundle-id"] = bundleId;
}
}
if (typeof globalThis !== "undefined" && "TW_AUTH_TOKEN" in globalThis) {
if (
typeof globalThis !== "undefined" &&
"TW_AUTH_TOKEN" in globalThis &&
typeof (globalThis as any).TW_AUTH_TOKEN === "string"
) {
headers["authorization"] = `Bearer ${
(globalThis as any).TW_AUTH_TOKEN as string
}`;
}
headers["x-sdk-version"] = pkg.version;
headers["x-sdk-name"] = pkg.name;
headers["x-sdk-platform"] = bundleId
? "react-native"
: isBrowser()
? "browser"
: "node";
}
this.userOpJsonRpcProvider = new providers.JsonRpcProvider(
@@ -46,7 +46,11 @@ class VerifyingPaymasterAPI extends PaymasterAPI {
headers["x-bundle-id"] = (globalThis as any).APP_BUNDLE_ID as string;
}
}
if (typeof globalThis !== "undefined" && "TW_AUTH_TOKEN" in globalThis) {
if (
typeof globalThis !== "undefined" &&
"TW_AUTH_TOKEN" in globalThis &&
typeof (globalThis as any).TW_AUTH_TOKEN === "string"
) {
headers["authorization"] = `Bearer ${
(globalThis as any).TW_AUTH_TOKEN as string
}`;
@@ -6,11 +6,12 @@ import {
UserRejectedRequestError,
WagmiConnector,
} from "../../../lib/wagmi-core";
import type { Chain } from "@thirdweb-dev/chains";
import { type Chain } from "@thirdweb-dev/chains";
import type WalletConnectProvider from "@walletconnect/ethereum-provider";
import { providers, utils } from "ethers";
import { walletIds } from "../../constants/walletIds";
import { QRModalOptions } from "./qrModalOptions";
import { getValidPublicRPCUrl } from "../../utils/url";
const chainsToRequest = new Set([1, 137, 10, 42161, 56]);
@@ -291,7 +292,7 @@ export class WalletConnectConnector extends WagmiConnector<
chainId: utils.hexValue(chain.chainId),
chainName: chain.name,
nativeCurrency: chain.nativeCurrency,
rpcUrls: [...chain.rpc],
rpcUrls: getValidPublicRPCUrl(chain), // no clientId on purpose
...blockExplorerUrls,
},
],
+18
View File
@@ -1,6 +1,24 @@
import { getValidChainRPCs, type Chain } from "@thirdweb-dev/chains";
export function isTwUrl(url: string): boolean {
const host = new URL(url).hostname;
return (
host.endsWith(".thirdweb.com") || host === "localhost" || host === "0.0.0.0"
);
}
export function getValidPublicRPCUrl(chain: Chain) {
return getValidChainRPCs(chain).map((rpc) => {
try {
const url = new URL(rpc);
// remove client id from url
if (url.hostname.endsWith(".thirdweb.com")) {
url.pathname = "";
url.search = "";
}
return url.toString();
} catch (e) {
return rpc;
}
});
}
+232 -2585
View File
File diff suppressed because it is too large Load Diff
+9 -6
View File
@@ -67,12 +67,14 @@
"test": {
"outputs": [],
"inputs": ["src/**", "test/**"],
"dependsOn": ["build"]
"dependsOn": ["build"],
"env": ["TW_SECRET_KEY"]
},
"test:solana": {
"outputs": ["coverage/solana/**"],
"inputs": ["src/core/**", "src/solana/**", "test/solana/**"],
"dependsOn": ["build"]
"dependsOn": ["build"],
"env": ["TW_SECRET_KEY"]
},
"test:evm": {
"outputs": ["coverage/evm/**"],
@@ -102,23 +104,24 @@
},
"e2e-cra-5#e2e": {
"outputs": ["playwright-report/**"],
"inputs": ["src/**", "fixtures/**"],
"inputs": ["src/**", "fixtures/**", "package.json"],
"dependsOn": ["build"]
},
"e2e-next-12#e2e": {
"outputs": ["playwright-report/**"],
"inputs": ["src/**", "fixtures/**"],
"inputs": ["src/**", "fixtures/**", "package.json"],
"dependsOn": ["build"]
},
"e2e-vite-3#e2e": {
"outputs": ["playwright-report/**"],
"inputs": ["src/**", "fixtures/**"],
"inputs": ["src/**", "fixtures/**", "package.json"],
"dependsOn": ["build"]
},
"thirdweb#e2e": {
"outputs": [],
"inputs": ["src/**", "e2e/**"],
"dependsOn": ["build"]
"dependsOn": ["build"],
"env": ["TW_SECRET_KEY"]
},
"lint": {
"outputs": []