Compare commits
74
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cbf5508bd5 | ||
|
|
3731459d33 | ||
|
|
64f24f1bb1 | ||
|
|
cac6c30bca | ||
|
|
e7740a59db | ||
|
|
7a37e564fd | ||
|
|
e173636f4b | ||
|
|
8c6cdaa288 | ||
|
|
ad9b3febff | ||
|
|
94f49b1294 | ||
|
|
517e2a75e3 | ||
|
|
72692689e9 | ||
|
|
efc56fa580 | ||
|
|
564b17e760 | ||
|
|
b4507db963 | ||
|
|
f451da6395 | ||
|
|
ee47840767 | ||
|
|
bef97f72f4 | ||
|
|
3e87dd3ccb | ||
|
|
def42511ff | ||
|
|
c42545a647 | ||
|
|
6e20d1f21a | ||
|
|
e684d7e1ca | ||
|
|
f545a67e9f | ||
|
|
034a257442 | ||
|
|
1bfb91dbf3 | ||
|
|
5d95cbcdb2 | ||
|
|
639e535ed5 | ||
|
|
af3acc6b10 | ||
|
|
eca47763cd | ||
|
|
37b5bec897 | ||
|
|
48d91e4431 | ||
|
|
a20be881e3 | ||
|
|
47f8945325 | ||
|
|
1b0bf99da7 | ||
|
|
f03be398e0 | ||
|
|
27996cb4bc | ||
|
|
2eaa67acbe | ||
|
|
aafd7968df | ||
|
|
48797c7cf0 | ||
|
|
4edcb37100 | ||
|
|
83dcaf7058 | ||
|
|
b4e005be7f | ||
|
|
ccb7db4873 | ||
|
|
9151aa7dc8 | ||
|
|
5a01c537e3 | ||
|
|
f09c153ff7 | ||
|
|
15431621fd | ||
|
|
887af24450 | ||
|
|
15514f190a | ||
|
|
72589ec234 | ||
|
|
f8bceec10c | ||
|
|
7c0744a006 | ||
|
|
846022e2cf | ||
|
|
96bd92e724 | ||
|
|
c2b6d977ed | ||
|
|
7cb8e59be4 | ||
|
|
04a47e8971 | ||
|
|
8a6a97a3e9 | ||
|
|
612bcdd16f | ||
|
|
0ed77d2c9e | ||
|
|
7129aef6e1 | ||
|
|
f50b74819d | ||
|
|
3eba69afd7 | ||
|
|
98c2253e8f | ||
|
|
32d91ef709 | ||
|
|
b79dc18f7a | ||
|
|
4af785c37c | ||
|
|
6f818f393e | ||
|
|
97ed4779a9 | ||
|
|
2d3fca5237 | ||
|
|
7016019f2a | ||
|
|
4e7b293c54 | ||
|
|
c9c0e4ff39 |
@@ -13,6 +13,6 @@ runs:
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: yarn install
|
||||
run: yarn install --frozen-lockfile
|
||||
env:
|
||||
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: "1"
|
||||
|
||||
+2
-1
@@ -16,4 +16,5 @@ public/dist
|
||||
.yalc/
|
||||
yalc.lock
|
||||
build/
|
||||
playwright-report/
|
||||
playwright-report/
|
||||
.vscode/
|
||||
@@ -28,7 +28,6 @@
|
||||
| [/storage](./packages/storage) | Best in class decentralized storage SDK for Browser and Node | <a href="https://www.npmjs.com/package/@thirdweb-dev/storage"><img src="https://img.shields.io/npm/v/@thirdweb-dev/storage?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
| [/cli](./packages/cli) | Publish and deploy smart contracts without dealing with private keys | <a href="https://www.npmjs.com/package/thirdweb"><img src="https://img.shields.io/npm/v/thirdweb?color=red&label=npm&logo=npm" alt="npm version"/></a> |
|
||||
|
||||
|
||||
## Documentation
|
||||
|
||||
Visit [https://portal.thirdweb.com/](https://portal.thirdweb.com/) to view the full documentation.
|
||||
|
||||
+3
-3
@@ -15,8 +15,8 @@
|
||||
"scripts": {
|
||||
"test": "turbo run test test:evm test:solana",
|
||||
"e2e": "turbo run e2e",
|
||||
"build": "turbo run build",
|
||||
"build:release": "turbo run build --force",
|
||||
"build": "turbo run build --filter=./packages/*",
|
||||
"build:release": "turbo run build --force --filter=./packages/*",
|
||||
"dev": "turbo run dev --no-cache --parallel --continue",
|
||||
"fix:repo": "manypkg fix",
|
||||
"lint": "turbo run lint",
|
||||
@@ -28,7 +28,7 @@
|
||||
"release": "node ./scripts/pre-release.mjs && changeset publish",
|
||||
"version-packages:nightly": "changeset version --snapshot nightly",
|
||||
"release:nightly": "node ./scripts/pre-release.mjs && changeset publish --tag nightly",
|
||||
"push": "turbo run push"
|
||||
"push": "turbo run push --filter=./packages/*"
|
||||
},
|
||||
"packageManager": "[email protected]",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 2.0.37
|
||||
|
||||
## 2.0.36
|
||||
|
||||
## 2.0.35
|
||||
|
||||
## 2.0.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#425](https://github.com/thirdweb-dev/js/pull/425) [`f545a67`](https://github.com/thirdweb-dev/js/commit/f545a67e9fb597d27bb39ca515d24d306fbb121a) Thanks [@adam-maj](https://github.com/adam-maj)! - Add sameSite none and include credentials
|
||||
|
||||
## 2.0.33
|
||||
|
||||
## 2.0.32
|
||||
|
||||
## 2.0.31
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#397](https://github.com/thirdweb-dev/js/pull/397) [`72589ec`](https://github.com/thirdweb-dev/js/commit/72589ec234d86939b67b0ca8b3b789f2e9c54cc2) Thanks [@adam-maj](https://github.com/adam-maj)! - Call user callback in getUser
|
||||
|
||||
## 2.0.30
|
||||
|
||||
## 2.0.29
|
||||
|
||||
## 2.0.28
|
||||
|
||||
## 2.0.27
|
||||
|
||||
## 2.0.26
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "2.0.27",
|
||||
"version": "2.0.37",
|
||||
"exports": {
|
||||
"./next": {
|
||||
"module": "./next/dist/thirdweb-dev-auth-next.esm.js",
|
||||
@@ -73,7 +73,7 @@
|
||||
"eslint-plugin-inclusive-language": "^2.2.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"ethers": "^5.7.1",
|
||||
"ethers": "^5.7.2",
|
||||
"express": "^4.18.1",
|
||||
"next": "^12.2.0",
|
||||
"next-auth": "^4.10.3",
|
||||
|
||||
@@ -43,7 +43,7 @@ export default async function handler(
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
sameSite: "none",
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -40,11 +40,11 @@ export function ThirdwebNextAuth(cfg: ThirdwebNextAuthConfig) {
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
sameSite: "none",
|
||||
}),
|
||||
);
|
||||
|
||||
return { address };
|
||||
return { id: address, address };
|
||||
} catch (err) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,13 @@ export function ThirdwebAuth(cfg: ThirdwebAuthConfig) {
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
user = { address };
|
||||
|
||||
let data = {};
|
||||
if (ctx.callbacks?.user) {
|
||||
data = await ctx.callbacks.user(address);
|
||||
}
|
||||
|
||||
user = { ...data, address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export default async function handler(
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
sameSite: "none",
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -70,7 +70,13 @@ export function ThirdwebAuth(cfg: ThirdwebAuthConfig) {
|
||||
if (token) {
|
||||
try {
|
||||
const address = await sdk.auth.authenticate(domain, token);
|
||||
user = { address };
|
||||
|
||||
let data = {};
|
||||
if (ctx.callbacks?.user) {
|
||||
data = await ctx.callbacks.user(address);
|
||||
}
|
||||
|
||||
user = { ...data, address };
|
||||
} catch {
|
||||
// No-op
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ export default async function handler(
|
||||
path: "/",
|
||||
httpOnly: true,
|
||||
secure: true,
|
||||
sameSite: "strict",
|
||||
sameSite: "none",
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,109 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.9.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#441](https://github.com/thirdweb-dev/js/pull/441) [`64f24f1`](https://github.com/thirdweb-dev/js/commit/64f24f1bb167c3d0cb3beca51fd300eaec21cc27) Thanks [@adam-maj](https://github.com/adam-maj)! - CLI autoupdates on run
|
||||
|
||||
- [#447](https://github.com/thirdweb-dev/js/pull/447) [`e7740a5`](https://github.com/thirdweb-dev/js/commit/e7740a59db022a3396194ac66cd195d8ae754d57) Thanks [@adam-maj](https://github.com/adam-maj)! - Detect whether forge is installed
|
||||
|
||||
- Updated dependencies [[`3731459`](https://github.com/thirdweb-dev/js/commit/3731459d33f1ded7ebb69124809449b901b3ad3d), [`cac6c30`](https://github.com/thirdweb-dev/js/commit/cac6c30bca5e17df81d746ef81316af47d5e252e), [`7a37e56`](https://github.com/thirdweb-dev/js/commit/7a37e564fd5d5a9df84c8da44ecaf6c42f67a0e2)]:
|
||||
- @thirdweb-dev/sdk@3.6.7
|
||||
|
||||
## 0.9.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`8c6cdaa`](https://github.com/thirdweb-dev/js/commit/8c6cdaa2887fb2cc40d3ee6991233d195d103805)]:
|
||||
- @thirdweb-dev/sdk@3.6.6
|
||||
|
||||
## 0.9.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#444](https://github.com/thirdweb-dev/js/pull/444) [`94f49b1`](https://github.com/thirdweb-dev/js/commit/94f49b1294bc0208171b16ed413cbb44644af017) Thanks [@adam-maj](https://github.com/adam-maj)! - Add changeset
|
||||
|
||||
## 0.9.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`efc56fa`](https://github.com/thirdweb-dev/js/commit/efc56fa5802490ac8ef50037658d046afd89e9a1)]:
|
||||
- @thirdweb-dev/sdk@3.6.5
|
||||
|
||||
## 0.9.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#430](https://github.com/thirdweb-dev/js/pull/430) [`e684d7e`](https://github.com/thirdweb-dev/js/commit/e684d7e1ca16f633bce8698529d16bf60c264aa4) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix uploading contracts with special characters in the comments
|
||||
|
||||
- [#435](https://github.com/thirdweb-dev/js/pull/435) [`bef97f7`](https://github.com/thirdweb-dev/js/commit/bef97f72f4860596b7b70b05e67fcadf2c9a012e) Thanks [@adam-maj](https://github.com/adam-maj)! - Make solc default backup compilation
|
||||
|
||||
- [#432](https://github.com/thirdweb-dev/js/pull/432) [`3e87dd3`](https://github.com/thirdweb-dev/js/commit/3e87dd3ccb04a2b73437357c939a251e83b783b2) Thanks [@adam-maj](https://github.com/adam-maj)! - Display file name on duplicate contract names
|
||||
|
||||
- [#431](https://github.com/thirdweb-dev/js/pull/431) [`c42545a`](https://github.com/thirdweb-dev/js/commit/c42545a64725492136025fa1dcdb4d46ba674a30) Thanks [@adam-maj](https://github.com/adam-maj)! - Add changeset
|
||||
|
||||
- [#428](https://github.com/thirdweb-dev/js/pull/428) [`6e20d1f`](https://github.com/thirdweb-dev/js/commit/6e20d1f21a622f102e94b956f700d0871c0dc779) Thanks [@adam-maj](https://github.com/adam-maj)! - Update CLI to enable create contract inside contracts project
|
||||
|
||||
- Updated dependencies [[`f451da6`](https://github.com/thirdweb-dev/js/commit/f451da6395689a5f89800ee63f34b6175b61f703), [`af3acc6`](https://github.com/thirdweb-dev/js/commit/af3acc6b10751b840e56aef6400da5eea6040df2), [`1bfb91d`](https://github.com/thirdweb-dev/js/commit/1bfb91dbf3a39160c987a425813ac5dbb84703ad), [`ee47840`](https://github.com/thirdweb-dev/js/commit/ee478407673b0416e0c1cfe2be11bd6963395348), [`def4251`](https://github.com/thirdweb-dev/js/commit/def42511ff5a20d83f9094164dafb87e412571b5), [`034a257`](https://github.com/thirdweb-dev/js/commit/034a257442314c67729f7bafcbe3740cff33fa32), [`eca4776`](https://github.com/thirdweb-dev/js/commit/eca47763cd89cc3b7aa57b542971837987540b55), [`639e535`](https://github.com/thirdweb-dev/js/commit/639e535ed55280ad9d081001aab3f5af72bb3e45)]:
|
||||
- @thirdweb-dev/sdk@3.6.4
|
||||
|
||||
## 0.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#415](https://github.com/thirdweb-dev/js/pull/415) [`48d91e4`](https://github.com/thirdweb-dev/js/commit/48d91e4431a3740d0f98f730ed5abf5b287f92c1) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix mappings for prebuilts redirect on deploy
|
||||
|
||||
## 0.9.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#403](https://github.com/thirdweb-dev/js/pull/403) [`27996cb`](https://github.com/thirdweb-dev/js/commit/27996cb4bc6f054f45b0a66b0a3aca732e0ef610) Thanks [@avneesh0612](https://github.com/avneesh0612)! - Add CLI Support for solana with --solana flag on create command
|
||||
|
||||
- [#283](https://github.com/thirdweb-dev/js/pull/283) [`2eaa67a`](https://github.com/thirdweb-dev/js/commit/2eaa67acbe21464e7715d0b696afdc024460a44d) Thanks [@adam-maj](https://github.com/adam-maj)! - add capability to deploy apps
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#413](https://github.com/thirdweb-dev/js/pull/413) [`1b0bf99`](https://github.com/thirdweb-dev/js/commit/1b0bf99da796df88ff307dd004cdaf239fb2b1ba) Thanks [@furqanrydhan](https://github.com/furqanrydhan)! - small interface tweaks
|
||||
|
||||
- Updated dependencies [[`48797c7`](https://github.com/thirdweb-dev/js/commit/48797c7cf0695965e33eb6bf602be4652f7085a8), [`83dcaf7`](https://github.com/thirdweb-dev/js/commit/83dcaf70584af8c5cdf0427f9fc1ba82d89f0887), [`f03be39`](https://github.com/thirdweb-dev/js/commit/f03be398e0d7b75c9c5b4fb643f35903e89a17e7), [`2eaa67a`](https://github.com/thirdweb-dev/js/commit/2eaa67acbe21464e7715d0b696afdc024460a44d), [`47f8945`](https://github.com/thirdweb-dev/js/commit/47f8945325447874b1ace0359919c1d54fd55436)]:
|
||||
- @thirdweb-dev/sdk@3.6.3
|
||||
|
||||
## 0.8.18
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ccb7db4`](https://github.com/thirdweb-dev/js/commit/ccb7db48739b8dddcb2c032b3b6e3e5200485715), [`9151aa7`](https://github.com/thirdweb-dev/js/commit/9151aa7dc80754a7aa4fd3f6ce0207bccbb6451f), [`5a01c53`](https://github.com/thirdweb-dev/js/commit/5a01c537e30bd7ef562aad1012413990de6faedf)]:
|
||||
- @thirdweb-dev/sdk@3.6.2
|
||||
|
||||
## 0.8.17
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`15514f1`](https://github.com/thirdweb-dev/js/commit/15514f190a844d809ae5b1edb580aab46a682485), [`7c0744a`](https://github.com/thirdweb-dev/js/commit/7c0744a006e78987ad8b271b2c64f4bac7759510), [`f8bceec`](https://github.com/thirdweb-dev/js/commit/f8bceec10c60b30dc3d6f45926e2a9e018202578), [`887af24`](https://github.com/thirdweb-dev/js/commit/887af24450e316c2ea390cd49c0563cebe793c0f), [`96bd92e`](https://github.com/thirdweb-dev/js/commit/96bd92e724ec7d880d23348071b26ab8c21dd868)]:
|
||||
- @thirdweb-dev/sdk@3.6.1
|
||||
|
||||
## 0.8.16
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`7cb8e59`](https://github.com/thirdweb-dev/js/commit/7cb8e59be48dc923316eb36ab43a1bef7364f6b1), [`0ed77d2`](https://github.com/thirdweb-dev/js/commit/0ed77d2c9e7526444ef660aab82a950865234aa6), [`04a47e8`](https://github.com/thirdweb-dev/js/commit/04a47e8971d28da2532ebd9db824eeb459c17bd4)]:
|
||||
- @thirdweb-dev/sdk@3.6.0
|
||||
|
||||
## 0.8.15
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`3eba69a`](https://github.com/thirdweb-dev/js/commit/3eba69afd78b7aa472a9c00c9d4220bb69ad1d3e), [`4af785c`](https://github.com/thirdweb-dev/js/commit/4af785c37c831ecd7087c1c9eb9095922cac0855), [`6f818f3`](https://github.com/thirdweb-dev/js/commit/6f818f393eb9023b53a3358d62d60ec23a9246bd), [`b79dc18`](https://github.com/thirdweb-dev/js/commit/b79dc18f7ab5155bbf4af02dc1a953546160bad0)]:
|
||||
- @thirdweb-dev/sdk@3.5.2
|
||||
|
||||
## 0.8.14
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`4e7b293`](https://github.com/thirdweb-dev/js/commit/4e7b293c543244de79c150ca8c37d941221fc9a3), [`c9c0e4f`](https://github.com/thirdweb-dev/js/commit/c9c0e4ff39b054af746f3aec75fcbd0a3ef7239d)]:
|
||||
- @thirdweb-dev/sdk@3.5.1
|
||||
|
||||
## 0.8.13
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
export const CREATE_MESSAGES = {
|
||||
typeOfProject: "What type of project do you want to create?",
|
||||
projectName: "What is your project named?",
|
||||
contractName: "What will be the name of your new smart contract?",
|
||||
chain: "Which blockchain do you want to use?",
|
||||
framework: "What framework do you want to use?",
|
||||
language: "What language do you want to use?",
|
||||
contract: "What type of contract do you want to start from?",
|
||||
@@ -9,5 +11,5 @@ export const CREATE_MESSAGES = {
|
||||
|
||||
export const ERROR_MESSAGES = {
|
||||
noConfiguration:
|
||||
"Failed to find a supported project configuration file in current directory",
|
||||
"No contract project configuration file found in current directory",
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CREATE_MESSAGES } from "../constants/constants";
|
||||
import { prepareEnvironment } from "@gmrchk/cli-testing-library";
|
||||
|
||||
// this creates an app, can take some time that's fine
|
||||
jest.setTimeout(120_000);
|
||||
jest.setTimeout(150_000);
|
||||
|
||||
describe("npx thirdweb create", () => {
|
||||
it("should create app (CRA) successfully", async () => {
|
||||
@@ -16,6 +16,8 @@ describe("npx thirdweb create", () => {
|
||||
await pressKey("enter");
|
||||
await waitForText(CREATE_MESSAGES.projectName);
|
||||
await pressKey("enter");
|
||||
await waitForText(CREATE_MESSAGES.chain);
|
||||
await pressKey("enter");
|
||||
await waitForText(CREATE_MESSAGES.framework);
|
||||
// select CRA
|
||||
await pressKey("arrowDown");
|
||||
|
||||
@@ -15,8 +15,8 @@ describe("npx thirdweb deploy", () => {
|
||||
`${path}/BasicContract.sol`,
|
||||
);
|
||||
|
||||
const { waitForText, waitForFinish, getExitCode, writeText, getStdout } =
|
||||
await spawn("node", "./dist/cli/index.js deploy");
|
||||
const { waitForText, waitForFinish, getExitCode, writeText, getStderr } =
|
||||
await spawn("node", "./dist/cli/index.js deploy --contract");
|
||||
|
||||
expect(await exists("BasicContract.sol")).toEqual(true);
|
||||
|
||||
@@ -26,7 +26,7 @@ describe("npx thirdweb deploy", () => {
|
||||
// wait for program to finish
|
||||
await waitForFinish();
|
||||
|
||||
expect(getStdout().at(-1)).toContain(
|
||||
expect(getStderr().at(-1)).toContain(
|
||||
"https://thirdweb.com/contracts/deploy/",
|
||||
);
|
||||
|
||||
|
||||
@@ -19,6 +19,10 @@ describe("npx thirdweb detect", () => {
|
||||
await create.waitForText(CREATE_MESSAGES.framework);
|
||||
// select hardhat
|
||||
await create.pressKey("enter");
|
||||
await create.waitForText(CREATE_MESSAGES.contractName);
|
||||
// set contract name
|
||||
await create.writeText("Contract");
|
||||
await create.pressKey("enter");
|
||||
await create.waitForText(CREATE_MESSAGES.contract);
|
||||
// select ERC721
|
||||
await create.pressKey("arrowDown");
|
||||
|
||||
@@ -15,7 +15,7 @@ describe("npx thirdweb release", () => {
|
||||
`${path}/BasicContract.sol`,
|
||||
);
|
||||
|
||||
const { waitForText, waitForFinish, getExitCode, writeText, getStdout } =
|
||||
const { waitForText, waitForFinish, getExitCode, writeText, getStderr } =
|
||||
await spawn("node", "./dist/cli/index.js release");
|
||||
|
||||
expect(await exists("BasicContract.sol")).toEqual(true);
|
||||
@@ -26,7 +26,7 @@ describe("npx thirdweb release", () => {
|
||||
// wait for program to finish
|
||||
await waitForFinish();
|
||||
|
||||
expect(getStdout().at(-1)).toContain(
|
||||
expect(getStderr().at(-1)).toContain(
|
||||
"https://thirdweb.com/contracts/release/",
|
||||
);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.8.13",
|
||||
"version": "0.9.6",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -10,7 +10,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@gmrchk/cli-testing-library": "^0.1.2",
|
||||
"@types/async-retry": "1.3.0",
|
||||
"@types/async-retry": "^1.3.0",
|
||||
"@types/cross-spawn": "^6.0.2",
|
||||
"@types/inquirer": "^8.2.1",
|
||||
"@types/jest": "^29.0.0",
|
||||
@@ -32,14 +32,15 @@
|
||||
"@thirdweb-dev/sdk": "*",
|
||||
"async-retry": "^1.3.3",
|
||||
"commander": "^9.1.0",
|
||||
"detect-package-manager": "^2.0.1",
|
||||
"enquirer": "^2.3.6",
|
||||
"ethers": "^5.7.0",
|
||||
"ethers": "^5.7.2",
|
||||
"got": "11.8.5",
|
||||
"inquirer": "^8.2.3",
|
||||
"open": "^8.4.0",
|
||||
"prompts": "^2.4.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"solc": "0.8.13",
|
||||
"solc": "0.8.17",
|
||||
"tar": "^6.1.11",
|
||||
"tslog": "^3.3.3",
|
||||
"update-notifier": "^6.0.2",
|
||||
@@ -73,4 +74,4 @@
|
||||
"sourcemap": true,
|
||||
"clean": true
|
||||
}
|
||||
}
|
||||
}
|
||||
+229
-68
@@ -2,37 +2,37 @@
|
||||
import { detectExtensions } from "../common/feature-detector";
|
||||
import { processProject } from "../common/processor";
|
||||
import { cliVersion, pkg } from "../constants/urls";
|
||||
import { info, logger } from "../core/helpers/logger";
|
||||
import { info, logger, spinner } from "../core/helpers/logger";
|
||||
import { twCreate } from "../create/command";
|
||||
import generateDashboardUrl from "../helpers/generate-dashboard-url";
|
||||
import { deploy } from "../deploy";
|
||||
import { findPackageInstallation } from "../helpers/detect-local-packages";
|
||||
import { upload } from "../storage/command";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import chalk from "chalk";
|
||||
import { exec, spawn } from "child_process";
|
||||
import { Command } from "commander";
|
||||
import open from "open";
|
||||
import prompts from "prompts";
|
||||
|
||||
const main = async () => {
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const skipIntro = process.env.THIRDWEB_CLI_SKIP_INTRO === "true";
|
||||
|
||||
const program = new Command();
|
||||
|
||||
//yes this has to look like this, eliminates whitespace
|
||||
console.info(`
|
||||
$$\\ $$\\ $$\\ $$\\ $$\\
|
||||
$$ | $$ | \\__| $$ | $$ |
|
||||
$$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$$\\
|
||||
\\_$$ _| $$ __$$\\ $$ |$$ __$$\\ $$ __$$ |$$ | $$ | $$ |$$ __$$\\ $$ __$$\\
|
||||
$$ | $$ | $$ |$$ |$$ | \\__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
|
||||
$$ |$$\\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
|
||||
\\$$$$ |$$ | $$ |$$ |$$ | \\$$$$$$$ |\\$$$$$\\$$$$ |\\$$$$$$$\\ $$$$$$$ |
|
||||
\\____/ \\__| \\__|\\__|\\__| \\_______| \\_____\\____/ \\_______|\\_______/ `);
|
||||
console.info(`\n 💎 thirdweb-cli v${cliVersion} 💎\n`);
|
||||
import("update-notifier").then(({ default: updateNotifier }) => {
|
||||
updateNotifier({
|
||||
pkg,
|
||||
shouldNotifyInNpmScript: true,
|
||||
// check every time while we're still building the CLI
|
||||
updateCheckInterval: 0,
|
||||
}).notify();
|
||||
});
|
||||
// yes this has to look like this, eliminates whitespace
|
||||
if (!skipIntro) {
|
||||
console.info(`
|
||||
$$\\ $$\\ $$\\ $$\\ $$\\
|
||||
$$ | $$ | \\__| $$ | $$ |
|
||||
$$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$$\\
|
||||
\\_$$ _| $$ __$$\\ $$ |$$ __$$\\ $$ __$$ |$$ | $$ | $$ |$$ __$$\\ $$ __$$\\
|
||||
$$ | $$ | $$ |$$ |$$ | \\__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
|
||||
$$ |$$\\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
|
||||
\\$$$$ |$$ | $$ |$$ |$$ | \\$$$$$$$ |\\$$$$$\\$$$$ |\\$$$$$$$\\ $$$$$$$ |
|
||||
\\____/ \\__| \\__|\\__|\\__| \\_______| \\_____\\____/ \\_______|\\_______/ `);
|
||||
console.info(`\n 💎 thirdweb-cli v${cliVersion} 💎\n`);
|
||||
}
|
||||
|
||||
program
|
||||
.name("thirdweb-cli")
|
||||
@@ -40,34 +40,40 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
.version(cliVersion, "-v, --version");
|
||||
|
||||
program
|
||||
.command("create [projectPath]")
|
||||
.command("create [projectType] [projectPath]")
|
||||
.description(
|
||||
"Create a web3 app from any of our official templates: https://github.com/thirdweb-example/",
|
||||
)
|
||||
.option("--app", `Create a web3 app.`)
|
||||
.option("--contract", `Create a web3 contract project`)
|
||||
.option("--ts, --typescript", `Initialize as a TypeScript project.`)
|
||||
.option("--js, --javascript", `Initialize as a JavaScript project.`)
|
||||
.option("--forge", `Initialize as a Forge project.`)
|
||||
.option("--hardhat", `Initialize as a Hardhat project.`)
|
||||
.option("--cra", `Initialize as a Create React App project.`)
|
||||
.option("--next", `Initialize as a Next.js project.`)
|
||||
.option("--vite", `Initialize as a Vite project.`)
|
||||
.option("--app", "Create a web3 app.")
|
||||
.option("--contract", "Create a web3 contract project")
|
||||
.option("--ts, --typescript", "Initialize as a TypeScript project.")
|
||||
.option("--js, --javascript", "Initialize as a JavaScript project.")
|
||||
.option("--forge", "Initialize as a Forge project.")
|
||||
.option("--hardhat", "Initialize as a Hardhat project.")
|
||||
.option("--cra", "Initialize as a Create React App project.")
|
||||
.option("--next", "Initialize as a Next.js project.")
|
||||
.option("--vite", "Initialize as a Vite project.")
|
||||
.option(
|
||||
"--use-npm",
|
||||
`Explicitly tell the CLI to bootstrap the app using npm`,
|
||||
"Explicitly tell the CLI to bootstrap the app using npm",
|
||||
)
|
||||
.option(
|
||||
"--use-pnpm",
|
||||
`Explicitly tell the CLI to bootstrap the app using pnpm`,
|
||||
"Explicitly tell the CLI to bootstrap the app using pnpm",
|
||||
)
|
||||
.option("--framework [name]", `The preferred framework.`)
|
||||
.option("--framework [name]", "The preferred framework.")
|
||||
.option("--solana", "Initialize as a Solana project.")
|
||||
.option("--evm", "Initialize as an Ethereum project.")
|
||||
.option(
|
||||
"-t, --template [name]",
|
||||
`A template to start your project from. You can use an template repository name from the official thirdweb-example org.`,
|
||||
"A template to start your project from. You can use an template repository name from the official thirdweb-example org.",
|
||||
)
|
||||
.action(async (path, options) => {
|
||||
await twCreate(path, options);
|
||||
.option(
|
||||
"-c, --contract-name [name]",
|
||||
"Name of the new smart contract to create",
|
||||
)
|
||||
.action(async (type, path, options) => {
|
||||
await twCreate(type, path, options);
|
||||
});
|
||||
|
||||
program
|
||||
@@ -87,39 +93,33 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("--ci", "Continuous Integration mode")
|
||||
.option(
|
||||
"--dist-path [distPath]",
|
||||
"Path to the dist folder where the HTML based App is",
|
||||
)
|
||||
.option(
|
||||
"-n, --name [name]",
|
||||
"Name of the pre-built or released contract (such as nft-drop)",
|
||||
)
|
||||
.option(
|
||||
"-f, --file [name]",
|
||||
"Filter for contract files that contain this file name",
|
||||
)
|
||||
.option(
|
||||
"-cn, --contract-name [name]",
|
||||
"Filter for contracts that contain this contract name",
|
||||
)
|
||||
.option(
|
||||
"-cv, --contract-version [version]",
|
||||
"Version of the released contract",
|
||||
)
|
||||
.option("--app", "Deploy a web app to decentralized storage")
|
||||
.option("--contract", "Deploy a smart contract to blockchains")
|
||||
.action(async (options) => {
|
||||
if (options.name) {
|
||||
const url = generateDashboardUrl(options.name, options.contractVersion);
|
||||
|
||||
if (!url) {
|
||||
logger.error(
|
||||
chalk.red(
|
||||
`Could not find a contract named ${options.name} ${
|
||||
options.contractVersion || ""
|
||||
}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
info(`Open this link to deploy your contract:`);
|
||||
logger.info(chalk.blueBright(url));
|
||||
open(url.toString());
|
||||
return;
|
||||
const url = await deploy(options);
|
||||
if (url) {
|
||||
open(url);
|
||||
}
|
||||
|
||||
const url = await processProject(options, "deploy");
|
||||
info(`Open this link to deploy your contracts:`);
|
||||
logger.info(chalk.blueBright(url.toString()));
|
||||
open(url.toString());
|
||||
});
|
||||
|
||||
program
|
||||
@@ -128,13 +128,24 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
"Release your protocol so other devs can deploy them and unlock SDKs, Dashboards and Analytics",
|
||||
)
|
||||
.option("-p, --path <project-path>", "path to project", ".")
|
||||
.option(
|
||||
"-f, --file [name]",
|
||||
"Filter for contract files that contain the file name",
|
||||
)
|
||||
.option(
|
||||
"-cn, --contract-name [name]",
|
||||
"Filter for contracts that contain this contract name",
|
||||
)
|
||||
.option("--dry-run", "dry run (skip actually publishing)")
|
||||
.option("-d, --debug", "show debug logs")
|
||||
.option("--ci", "Continuous Integration mode")
|
||||
.action(async (options) => {
|
||||
const url = await processProject(options, "release");
|
||||
info(`Open this link to release your contracts:`);
|
||||
logger.info(chalk.blueBright(url.toString()));
|
||||
info(
|
||||
`Open this link to release your contracts: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
)}`,
|
||||
);
|
||||
open(url.toString());
|
||||
});
|
||||
|
||||
@@ -144,13 +155,35 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
.argument("[upload]", "path to file or directory to upload")
|
||||
.action(async (path) => {
|
||||
const storage = new ThirdwebStorage();
|
||||
const uri = await upload(storage, path);
|
||||
info(`Files stored at the following IPFS URI:`);
|
||||
logger.info(chalk.blueBright(uri.toString()));
|
||||
try {
|
||||
const uri = await upload(storage, path);
|
||||
info(
|
||||
`Files stored at the following IPFS URI: ${chalk.blueBright(
|
||||
uri.toString(),
|
||||
)}`,
|
||||
);
|
||||
|
||||
const url = storage.resolveScheme(uri);
|
||||
info(`Open this link to view your upload:`);
|
||||
logger.info(chalk.blueBright(url.toString()));
|
||||
const url = storage.resolveScheme(uri);
|
||||
info(
|
||||
`Open this link to view your upload: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
)}`,
|
||||
);
|
||||
} catch (err: any) {
|
||||
if (
|
||||
err.toString() === "No files detected in specified directory" ||
|
||||
err.toString() === "Invalid path provided" ||
|
||||
err.toString() === "No path provided"
|
||||
) {
|
||||
logger.error(
|
||||
chalk.redBright(
|
||||
"Please specify a valid file or directory to upload",
|
||||
),
|
||||
);
|
||||
} else {
|
||||
logger.error(chalk.redBright("Failed to upload files"), err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
program
|
||||
@@ -165,6 +198,134 @@ $$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$
|
||||
await detectExtensions(options);
|
||||
});
|
||||
|
||||
if (!skipIntro) {
|
||||
const versionSpinner = spinner("Checking for updates...");
|
||||
await import("update-notifier").then(
|
||||
async ({ default: updateNotifier }) => {
|
||||
const notifier = updateNotifier({
|
||||
pkg,
|
||||
shouldNotifyInNpmScript: true,
|
||||
// check every time while we're still building the CLI
|
||||
updateCheckInterval: 0,
|
||||
});
|
||||
|
||||
const versionInfo = await notifier.fetchInfo();
|
||||
versionSpinner.stop();
|
||||
|
||||
if (versionInfo.type !== "latest") {
|
||||
const res = await prompts({
|
||||
type: "toggle",
|
||||
name: "upgrade",
|
||||
message: `A new version of the CLI is available. Would you like to upgrade?`,
|
||||
initial: true,
|
||||
active: "yes",
|
||||
inactive: "no",
|
||||
});
|
||||
|
||||
if (res.upgrade) {
|
||||
const updateSpinner = spinner(
|
||||
`Upgrading CLI to version ${versionInfo.latest}...`,
|
||||
);
|
||||
|
||||
const clonedEnvironment = { ...process.env };
|
||||
clonedEnvironment.THIRDWEB_CLI_SKIP_INTRO = "true";
|
||||
|
||||
const installation = await findPackageInstallation();
|
||||
|
||||
// If the package isn't installed anywhere, just defer to npx thirdweb@latest
|
||||
if (!installation) {
|
||||
updateSpinner.succeed(
|
||||
`Now using CLI version ${versionInfo.latest}. Continuing execution...`,
|
||||
);
|
||||
|
||||
await new Promise((done, failed) => {
|
||||
const shell = spawn(
|
||||
`npx --yes thirdweb@latest ${process.argv
|
||||
.slice(2)
|
||||
.join(" ")}`,
|
||||
[],
|
||||
{ stdio: "inherit", shell: true, env: clonedEnvironment },
|
||||
);
|
||||
shell.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
done("");
|
||||
} else {
|
||||
failed();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return process.exit(0);
|
||||
}
|
||||
|
||||
// Otherwise, get the correct command based on package manager and local vs. global
|
||||
let command = "";
|
||||
switch (installation.packageManager) {
|
||||
case "npm":
|
||||
command = installation.isGlobal
|
||||
? `npm install -g thirdweb`
|
||||
: `npm install thirdweb`;
|
||||
break;
|
||||
case "yarn":
|
||||
command = installation.isGlobal
|
||||
? `yarn global add thirdweb`
|
||||
: `yarn add thirdweb`;
|
||||
break;
|
||||
case "pnpm":
|
||||
command = installation.isGlobal
|
||||
? `pnpm add -g thirdweb@latest`
|
||||
: `pnpm add thirdweb@latest`;
|
||||
break;
|
||||
default:
|
||||
console.error(
|
||||
`Could not detect package manager in use, aborting automatic upgrade.\nIf you want to upgrade the CLI, please do it manually with your package manager.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await new Promise((done, failed) => {
|
||||
exec(command, (err, stdout, stderr) => {
|
||||
if (err) {
|
||||
failed(err);
|
||||
return;
|
||||
}
|
||||
|
||||
done({ stdout, stderr });
|
||||
});
|
||||
});
|
||||
|
||||
updateSpinner.succeed(
|
||||
`Successfully upgraded CLI to version ${versionInfo.latest}. Continuing execution...`,
|
||||
);
|
||||
|
||||
// If the package is installed globally with yarn or pnpm, then npx won't recognize it
|
||||
// So we need to make sure to run the command directly
|
||||
const executionCommand =
|
||||
!installation.isGlobal || installation.packageManager === "npm"
|
||||
? `npx thirdweb`
|
||||
: `thirdweb`;
|
||||
await new Promise((done, failed) => {
|
||||
const shell = spawn(
|
||||
`${executionCommand} ${process.argv.slice(2).join(" ")}`,
|
||||
[],
|
||||
{ stdio: "inherit", shell: true, env: clonedEnvironment },
|
||||
);
|
||||
shell.on("close", (code) => {
|
||||
if (code === 0) {
|
||||
done("");
|
||||
} else {
|
||||
failed();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
await program.parseAsync();
|
||||
};
|
||||
|
||||
|
||||
@@ -76,7 +76,7 @@ export async function processProject(
|
||||
}
|
||||
}
|
||||
|
||||
let compiledResult;
|
||||
let compiledResult: { contracts: ContractPayload[] };
|
||||
const compileLoader = spinner("Compiling project...");
|
||||
try {
|
||||
compiledResult = await build(projectPath, projectType);
|
||||
@@ -106,10 +106,47 @@ export async function processProject(
|
||||
if (options.ci) {
|
||||
selectedContracts = compiledResult.contracts;
|
||||
} else {
|
||||
const choices = compiledResult.contracts.map((c) => ({
|
||||
name: c.name,
|
||||
value: c,
|
||||
}));
|
||||
const filtered = compiledResult.contracts
|
||||
.filter((c) => {
|
||||
if (typeof options.file === "string" && options.file.length > 0) {
|
||||
return c.fileName.includes(options.file);
|
||||
}
|
||||
|
||||
return true;
|
||||
})
|
||||
.filter((c) => {
|
||||
if (
|
||||
typeof options.contractName === "string" &&
|
||||
options.contractName.length > 0
|
||||
) {
|
||||
return c.name.includes(options.contractName);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (filtered.length === 0) {
|
||||
logger.error(`No contracts found matching the specified filters.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const choices = filtered.map((c) => {
|
||||
if (
|
||||
compiledResult.contracts.filter(
|
||||
(other: ContractPayload) => other.name === c.name,
|
||||
).length > 1
|
||||
) {
|
||||
return {
|
||||
name: `${c.name} - ${chalk.gray(c.fileName)}`,
|
||||
value: c,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
name: c.name,
|
||||
value: c,
|
||||
};
|
||||
});
|
||||
const prompt = createContractsPrompt(
|
||||
choices,
|
||||
`Choose which contract(s) to ${command}`,
|
||||
@@ -164,7 +201,7 @@ export async function processProject(
|
||||
const metadataURIs = await Promise.all(
|
||||
selectedContracts.map(async (c) => {
|
||||
logger.debug(`Uploading ${c.name}...`);
|
||||
return await storage.upload(JSON.parse(c.metadata), {
|
||||
return await storage.upload(JSON.parse(JSON.stringify(c.metadata)), {
|
||||
uploadWithoutDirectory: true,
|
||||
});
|
||||
}),
|
||||
|
||||
@@ -55,6 +55,7 @@ export class BrownieBuilder extends BaseBuilder {
|
||||
metadata: {},
|
||||
bytecode,
|
||||
sources: [], // TODO
|
||||
fileName: "", // TODO
|
||||
name: contractName,
|
||||
});
|
||||
break;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { findFiles } from "../../common/file-helper";
|
||||
import { hasForge } from "../../create/helpers/has-forge";
|
||||
import { execute } from "../helpers/exec";
|
||||
import { logger } from "../helpers/logger";
|
||||
import { CompileOptions } from "../interfaces/Builder";
|
||||
import { ContractPayload } from "../interfaces/ContractPayload";
|
||||
import { BaseBuilder } from "./builder-base";
|
||||
import chalk from "chalk";
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import { basename, join } from "path";
|
||||
|
||||
@@ -11,6 +13,18 @@ export class FoundryBuilder extends BaseBuilder {
|
||||
public async compile(options: CompileOptions): Promise<{
|
||||
contracts: ContractPayload[];
|
||||
}> {
|
||||
const isInstalled = await hasForge();
|
||||
if (!isInstalled) {
|
||||
console.error(
|
||||
`\n${chalk.redBright(
|
||||
`error`,
|
||||
)} You don't have forge installed on this machine!\n\nYou can install forge by following these instructions:\n${chalk.blueBright(
|
||||
`https://book.getfoundry.sh/getting-started/installation`,
|
||||
)}\n`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await execute("forge clean", options.projectPath);
|
||||
await execute("forge build --extra-output metadata", options.projectPath);
|
||||
|
||||
@@ -88,6 +102,11 @@ export class FoundryBuilder extends BaseBuilder {
|
||||
})
|
||||
.filter((path) => path !== undefined) as string[];
|
||||
|
||||
const fileNames = Object.keys(
|
||||
parsedMetadata?.settings?.compilationTarget || {},
|
||||
);
|
||||
const fileName = fileNames.length > 0 ? fileNames[0] : "";
|
||||
|
||||
if (
|
||||
this.shouldProcessContract(
|
||||
contractInfo.abi,
|
||||
@@ -99,6 +118,7 @@ export class FoundryBuilder extends BaseBuilder {
|
||||
name: contractName,
|
||||
metadata,
|
||||
bytecode,
|
||||
fileName,
|
||||
sources,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ export class HardhatBuilder extends BaseBuilder {
|
||||
//the hardhat extractor **logs out** the runtime config of hardhat, we take that stdout and parse it
|
||||
const stringifiedConfig = (
|
||||
await execute(
|
||||
`npx hardhat run ${configExtractorScriptPath} --no-compile`,
|
||||
`npx hardhat run "${configExtractorScriptPath}" --no-compile`,
|
||||
options.projectPath,
|
||||
)
|
||||
).stdout;
|
||||
@@ -123,11 +123,17 @@ export class HardhatBuilder extends BaseBuilder {
|
||||
})
|
||||
.filter((path) => path !== undefined) as string[];
|
||||
|
||||
const fileNames = Object.keys(
|
||||
meta?.settings?.compilationTarget || {},
|
||||
);
|
||||
const fileName = fileNames.length > 0 ? fileNames[0] : "";
|
||||
|
||||
if (this.shouldProcessContract(abi, deployedBytecode, contractName)) {
|
||||
contracts.push({
|
||||
metadata,
|
||||
bytecode,
|
||||
name: contractName,
|
||||
fileName,
|
||||
sources,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -140,11 +140,17 @@ export class SolcBuilder extends BaseBuilder {
|
||||
})
|
||||
.filter((path) => path !== undefined) as string[];
|
||||
|
||||
const fileNames = Object.keys(
|
||||
parsedMetadata?.settings?.compilationTarget || {},
|
||||
);
|
||||
const fileName = fileNames.length > 0 ? fileNames[0] : "";
|
||||
|
||||
if (this.shouldProcessContract(abi, deployedBytecode, contractName)) {
|
||||
contracts.push({
|
||||
metadata,
|
||||
bytecode,
|
||||
name: contractName,
|
||||
fileName,
|
||||
sources: _sources,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -72,11 +72,18 @@ export class TruffleBuilder extends BaseBuilder {
|
||||
return undefined;
|
||||
})
|
||||
.filter((path) => path !== undefined) as string[];
|
||||
|
||||
const fileNames = Object.keys(
|
||||
parsedMetadata?.settings?.compilationTarget || {},
|
||||
);
|
||||
const fileName = fileNames.length > 0 ? fileNames[0] : "";
|
||||
|
||||
if (this.shouldProcessContract(abi, deployedBytecode, contractName)) {
|
||||
contracts.push({
|
||||
metadata,
|
||||
bytecode,
|
||||
name: contractName,
|
||||
fileName,
|
||||
sources,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ export default async function detect(
|
||||
name: "continue",
|
||||
message:
|
||||
"Do you want to continue and compile this project with solc instead?",
|
||||
initial: true,
|
||||
});
|
||||
const shouldCompile = await prompt.run();
|
||||
if (!shouldCompile) {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ProjectType } from "../types/ProjectType";
|
||||
import { Detector } from "./detector";
|
||||
import { existsSync } from "fs";
|
||||
|
||||
export default class NPMDetector implements Detector {
|
||||
public projectType: ProjectType = "npm";
|
||||
|
||||
public matches(path: string): boolean {
|
||||
return existsSync(path + "/package-lock.json");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import { ProjectType } from "../types/ProjectType";
|
||||
import { Detector } from "./detector";
|
||||
import { existsSync } from "fs";
|
||||
|
||||
export default class ViteDetector implements Detector {
|
||||
public projectType: ProjectType = "vite";
|
||||
|
||||
public matches(path: string): boolean {
|
||||
return (
|
||||
existsSync(path + "/vite.config.js") ||
|
||||
existsSync(path + "/vite.config.ts")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { ProjectType } from "../types/ProjectType";
|
||||
import { Detector } from "./detector";
|
||||
import { existsSync } from "fs";
|
||||
|
||||
export default class YarnDetector implements Detector {
|
||||
public projectType: ProjectType = "yarn";
|
||||
|
||||
public matches(path: string): boolean {
|
||||
return existsSync(path + "/yarn.lock");
|
||||
}
|
||||
}
|
||||
@@ -17,6 +17,11 @@ export interface ContractPayload {
|
||||
*/
|
||||
metadata: any;
|
||||
|
||||
/**
|
||||
* The file name of the original compiled file
|
||||
*/
|
||||
fileName: string;
|
||||
|
||||
/**
|
||||
* The source file paths
|
||||
*/
|
||||
|
||||
@@ -4,4 +4,10 @@ export type ProjectType =
|
||||
| "hardhat"
|
||||
| "truffle"
|
||||
| "solc"
|
||||
| "vite"
|
||||
| "next"
|
||||
| "cra"
|
||||
| "spa-webapp"
|
||||
| "yarn"
|
||||
| "npm"
|
||||
| "none";
|
||||
|
||||
+262
-131
@@ -2,60 +2,82 @@
|
||||
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import { CREATE_MESSAGES } from "../../constants/constants";
|
||||
import detect from "../core/detection/detect";
|
||||
import { DownloadError, createApp } from "./helpers/create-app";
|
||||
import { createContract } from "./helpers/create-contract";
|
||||
import { createContractProject } from "./helpers/create-contract";
|
||||
import { getPkgManager } from "./helpers/get-pkg-manager";
|
||||
import { validateNpmName } from "./helpers/validate-pkg";
|
||||
import chalk from "chalk";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import prompts from "prompts";
|
||||
|
||||
let projectType: string = "";
|
||||
let contractName: string = "";
|
||||
let projectPath: string = "";
|
||||
let projectType: string = "";
|
||||
let framework: string = "";
|
||||
let language: string = "";
|
||||
let baseContract: string = "";
|
||||
let chain: string = "";
|
||||
/* let createType: string = "app"; */
|
||||
|
||||
export async function twCreate(pPath: string = "", options: any) {
|
||||
export async function twCreate(
|
||||
pType: string,
|
||||
pPath: string = "",
|
||||
options: any,
|
||||
) {
|
||||
if (typeof pPath === "string") {
|
||||
projectPath = pPath;
|
||||
}
|
||||
|
||||
if (options.app) {
|
||||
projectType = "app";
|
||||
if (typeof options.contractName === "string") {
|
||||
contractName = options.contractName;
|
||||
}
|
||||
|
||||
if (options.contract) {
|
||||
if (pType === "app" || options.app) {
|
||||
projectType = "app";
|
||||
} else if (pType === "contract" || options.contract) {
|
||||
projectType = "contract";
|
||||
}
|
||||
|
||||
if (options.typescript) {
|
||||
language = "typescript";
|
||||
if (projectType === "app") {
|
||||
if (options.typescript) {
|
||||
language = "typescript";
|
||||
}
|
||||
|
||||
if (options.javascript) {
|
||||
language = "javascript";
|
||||
}
|
||||
|
||||
if (options.next) {
|
||||
framework = "next";
|
||||
}
|
||||
|
||||
if (options.cra) {
|
||||
framework = "cra";
|
||||
}
|
||||
|
||||
if (options.vite) {
|
||||
framework = "vite";
|
||||
}
|
||||
|
||||
if (options.solana) {
|
||||
chain = "solana";
|
||||
}
|
||||
|
||||
if (options.evm) {
|
||||
chain = "evm";
|
||||
}
|
||||
}
|
||||
|
||||
if (options.javascript) {
|
||||
language = "javascript";
|
||||
}
|
||||
if (projectType === "contract") {
|
||||
if (options.forge) {
|
||||
framework = "forge";
|
||||
}
|
||||
|
||||
if (options.next) {
|
||||
framework = "next";
|
||||
}
|
||||
|
||||
if (options.cra) {
|
||||
framework = "cra";
|
||||
}
|
||||
|
||||
if (options.vite) {
|
||||
framework = "vite";
|
||||
}
|
||||
|
||||
if (options.forge) {
|
||||
framework = "forge";
|
||||
}
|
||||
|
||||
if (options.hardhat) {
|
||||
framework = "hardhat";
|
||||
if (options.hardhat) {
|
||||
framework = "hardhat";
|
||||
}
|
||||
}
|
||||
|
||||
if (options.framework) {
|
||||
@@ -76,103 +98,216 @@ export async function twCreate(pPath: string = "", options: any) {
|
||||
if (typeof res.projectType === "string") {
|
||||
projectType = res.projectType.trim();
|
||||
}
|
||||
} else if (!projectType && options.template) {
|
||||
} else if (!projectType || options.template) {
|
||||
// If no project type is specified, but a template is, we assume the user wants to create an app.
|
||||
// We do this so old users can still use the --template flag to create an app.
|
||||
projectType = "app";
|
||||
}
|
||||
|
||||
if (!projectPath) {
|
||||
const defaultName =
|
||||
projectType === "contract" ? "thirdweb-contracts" : "thirdweb-app";
|
||||
const res = await prompts({
|
||||
type: "text",
|
||||
name: "path",
|
||||
message: CREATE_MESSAGES.projectName,
|
||||
initial: options.template || defaultName,
|
||||
format: (name: string) => name.toLowerCase(),
|
||||
validate: (name: string) => {
|
||||
const validation = validateNpmName(
|
||||
path.basename(path.resolve(name.toLowerCase())),
|
||||
);
|
||||
if (validation.valid) {
|
||||
return true;
|
||||
}
|
||||
return "Invalid project name: " + validation.problems?.[0];
|
||||
},
|
||||
});
|
||||
|
||||
if (typeof res.path === "string") {
|
||||
projectPath = res.path.trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (!projectPath) {
|
||||
console.log(
|
||||
"\nPlease specify the project directory:\n" +
|
||||
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
|
||||
"<project-directory>",
|
||||
)}\n` +
|
||||
"For example:\n" +
|
||||
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
|
||||
"my-thirdweb-app",
|
||||
)}\n\n` +
|
||||
`Run ${chalk.cyan("npx thirdweb --help")} to see all options.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!options.template) {
|
||||
if (projectType === "app" && !framework) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: CREATE_MESSAGES.framework,
|
||||
choices: [
|
||||
{ title: "Next.js", value: "next" },
|
||||
{ title: "Create React App", value: "cra" },
|
||||
{ title: "Vite", value: "vite" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.framework === "string") {
|
||||
framework = res.framework.trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (projectType === "app" && !language) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "language",
|
||||
message: CREATE_MESSAGES.language,
|
||||
choices: [
|
||||
{ title: "JavaScript", value: "javascript" },
|
||||
{ title: "TypeScript", value: "typescript" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.language === "string") {
|
||||
language = res.language.trim();
|
||||
}
|
||||
}
|
||||
// Whether to only create a new contract without the project
|
||||
let onlyContract = false;
|
||||
if (projectType === "contract") {
|
||||
const resolvedProjectPath = path.resolve(projectPath);
|
||||
const contractProjectType = await detect(resolvedProjectPath, {});
|
||||
|
||||
if (
|
||||
projectType === "contract" &&
|
||||
framework !== "forge" &&
|
||||
framework !== "hardhat"
|
||||
contractProjectType === "foundry" &&
|
||||
fs.existsSync(path.join(resolvedProjectPath, "src"))
|
||||
) {
|
||||
onlyContract = true;
|
||||
projectPath = path.join(projectPath, "src");
|
||||
} else if (contractProjectType === "hardhat") {
|
||||
if (fs.existsSync(path.join(resolvedProjectPath, "contracts"))) {
|
||||
onlyContract = true;
|
||||
projectPath = path.join(projectPath, "contracts");
|
||||
} else {
|
||||
// If there's no expected contracts folder, check for a directory that has .sol files
|
||||
const directories = fs
|
||||
.readdirSync(resolvedProjectPath)
|
||||
.filter((file) =>
|
||||
fs.lstatSync(path.join(resolvedProjectPath, file)).isDirectory(),
|
||||
);
|
||||
for (const directory of directories) {
|
||||
const files = fs.readdirSync(path.join(projectPath, directory));
|
||||
if (files.some((file) => file.endsWith(".sol"))) {
|
||||
onlyContract = true;
|
||||
projectPath = path.join(projectPath, directory);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!onlyContract) {
|
||||
if (!projectPath) {
|
||||
const defaultName =
|
||||
projectType === "contract" ? "thirdweb-contracts" : "thirdweb-app";
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: CREATE_MESSAGES.framework,
|
||||
choices: [
|
||||
{ title: "Hardhat", value: "hardhat" },
|
||||
{ title: "Forge", value: "forge" },
|
||||
],
|
||||
type: "text",
|
||||
name: "path",
|
||||
message: CREATE_MESSAGES.projectName,
|
||||
initial: options.template || defaultName,
|
||||
format: (name: string) => name.toLowerCase(),
|
||||
validate: (name: string) => {
|
||||
const validation = validateNpmName(
|
||||
path.basename(path.resolve(name.toLowerCase())),
|
||||
);
|
||||
if (validation.valid) {
|
||||
return true;
|
||||
}
|
||||
return "Invalid project name: " + validation.problems?.[0];
|
||||
},
|
||||
});
|
||||
|
||||
if (typeof res.framework === "string") {
|
||||
framework = res.framework.trim();
|
||||
if (typeof res.path === "string") {
|
||||
projectPath = path.join(projectPath, res.path.trim());
|
||||
}
|
||||
}
|
||||
|
||||
if (!projectPath) {
|
||||
console.log(
|
||||
"\nPlease specify the project directory:\n" +
|
||||
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
|
||||
"<project-directory>",
|
||||
)}\n` +
|
||||
"For example:\n" +
|
||||
` ${chalk.cyan("npx thirdweb create")} ${chalk.green(
|
||||
"my-thirdweb-app",
|
||||
)}\n\n` +
|
||||
`Run ${chalk.cyan("npx thirdweb --help")} to see all options.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!options.template) {
|
||||
if (projectType === "app" && !chain) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "chain",
|
||||
message: CREATE_MESSAGES.chain,
|
||||
choices: [
|
||||
{ title: "EVM", value: "evm" },
|
||||
{ title: "Solana", value: "solana" },
|
||||
],
|
||||
});
|
||||
|
||||
if (res.chain === "solana") {
|
||||
chain = "solana";
|
||||
} else {
|
||||
chain = "evm";
|
||||
}
|
||||
}
|
||||
|
||||
if (projectType === "app" && !framework) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: CREATE_MESSAGES.framework,
|
||||
choices:
|
||||
// Solana doesn't support Vite just yet:
|
||||
chain === "solana"
|
||||
? [
|
||||
{ title: "Next.js", value: "next" },
|
||||
{ title: "Create React App", value: "cra" },
|
||||
// { title: "Vite", value: "vite" },
|
||||
]
|
||||
: [
|
||||
{ title: "Next.js", value: "next" },
|
||||
{ title: "Create React App", value: "cra" },
|
||||
{ title: "Vite", value: "vite" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.framework === "string") {
|
||||
framework = res.framework.trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (projectType === "app" && !language) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "language",
|
||||
message: CREATE_MESSAGES.language,
|
||||
choices: [
|
||||
{ title: "JavaScript", value: "javascript" },
|
||||
{ title: "TypeScript", value: "typescript" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.language === "string") {
|
||||
language = res.language.trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
projectType === "contract" &&
|
||||
framework !== "forge" &&
|
||||
framework !== "hardhat"
|
||||
) {
|
||||
const res = await prompts({
|
||||
type: "select",
|
||||
name: "framework",
|
||||
message: CREATE_MESSAGES.framework,
|
||||
choices: [
|
||||
{ title: "Hardhat", value: "hardhat" },
|
||||
{ title: "Forge", value: "forge" },
|
||||
],
|
||||
});
|
||||
|
||||
if (typeof res.framework === "string") {
|
||||
framework = res.framework.trim();
|
||||
}
|
||||
}
|
||||
|
||||
if (!framework) {
|
||||
console.log("Please specify a framework");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!language) {
|
||||
// Default = JavaScript
|
||||
language = "javascript";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (projectType === "contract") {
|
||||
// Select contract name
|
||||
if (!contractName) {
|
||||
const defaultName = "MyContract";
|
||||
const res = await prompts({
|
||||
type: "text",
|
||||
name: "path",
|
||||
message: CREATE_MESSAGES.contractName,
|
||||
initial: defaultName,
|
||||
validate: (name: string) => {
|
||||
const isValid = /(^[a-z0-9A-Z]+$)|(^[a-z0-9A-Z]+\.sol$)/.test(name);
|
||||
if (isValid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return `Invalid contract name 'contractName' (only alphanumeric characters allowed)`;
|
||||
},
|
||||
});
|
||||
|
||||
if (typeof res.path === "string") {
|
||||
contractName = res.path.trim();
|
||||
}
|
||||
|
||||
if (!contractName) {
|
||||
console.log(
|
||||
"\nPlease specify the contract name:\n" +
|
||||
` ${chalk.cyan(
|
||||
"npx thirdweb create --contract --name",
|
||||
)} ${chalk.green("<contract-name>")}\n` +
|
||||
"For example:\n" +
|
||||
` ${chalk.cyan(
|
||||
"npx thirdweb create --contract --name",
|
||||
)} ${chalk.green("MyContract")}\n\n` +
|
||||
`Run ${chalk.cyan("npx thirdweb --help")} to see all options.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +319,9 @@ export async function twCreate(pPath: string = "", options: any) {
|
||||
name: "standard",
|
||||
message: CREATE_MESSAGES.contract,
|
||||
choices: [
|
||||
{ title: "Empty Contract", value: "none" },
|
||||
...(!onlyContract
|
||||
? [{ title: "Empty Contract", value: "none" }]
|
||||
: []),
|
||||
{ title: "ERC721", value: "erc721" },
|
||||
{ title: "ERC20", value: "erc20" },
|
||||
{ title: "ERC1155", value: "erc1155" },
|
||||
@@ -238,20 +375,11 @@ export async function twCreate(pPath: string = "", options: any) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!framework) {
|
||||
console.log("Please specify a framework");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!language) {
|
||||
// Default = JavaScript
|
||||
language = "javascript";
|
||||
}
|
||||
}
|
||||
|
||||
const resolvedProjectPath = path.resolve(projectPath);
|
||||
const projectName = path.basename(resolvedProjectPath);
|
||||
// Resolve project path
|
||||
projectPath = path.resolve(projectPath);
|
||||
const projectName = path.basename(projectPath);
|
||||
|
||||
const { valid, problems } = validateNpmName(projectName);
|
||||
if (!valid) {
|
||||
@@ -283,18 +411,21 @@ export async function twCreate(pPath: string = "", options: any) {
|
||||
try {
|
||||
if (projectType === "app") {
|
||||
await createApp({
|
||||
appPath: resolvedProjectPath,
|
||||
appPath: projectPath,
|
||||
packageManager,
|
||||
framework,
|
||||
language,
|
||||
template,
|
||||
chain,
|
||||
});
|
||||
} else {
|
||||
await createContract({
|
||||
contractPath: resolvedProjectPath,
|
||||
await createContractProject({
|
||||
contractPath: projectPath,
|
||||
packageManager,
|
||||
framework,
|
||||
contractName,
|
||||
baseContract,
|
||||
onlyContract,
|
||||
});
|
||||
}
|
||||
} catch (reason) {
|
||||
|
||||
@@ -22,12 +22,14 @@ export async function createApp({
|
||||
framework,
|
||||
language,
|
||||
template,
|
||||
chain,
|
||||
}: {
|
||||
appPath: string;
|
||||
packageManager: PackageManager;
|
||||
framework?: string;
|
||||
language?: string;
|
||||
template?: string;
|
||||
chain?: string;
|
||||
}): Promise<void> {
|
||||
let frameworkPath = "";
|
||||
|
||||
@@ -43,7 +45,9 @@ export async function createApp({
|
||||
process.exit(1);
|
||||
}
|
||||
} else if (framework) {
|
||||
frameworkPath = `${framework}-${language || "javascript"}-starter`;
|
||||
frameworkPath = `${framework}-${language || "javascript"}-${
|
||||
chain === "solana" ? "solana-" : ""
|
||||
}starter`;
|
||||
const found = await hasTemplate(frameworkPath);
|
||||
|
||||
if (!found) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { hasBaseContract, readBaseContract } from "./base-contracts";
|
||||
import { DownloadError } from "./create-app";
|
||||
import { PackageManager } from "./get-pkg-manager";
|
||||
import { tryGitInit } from "./git";
|
||||
import { hasForge } from "./has-forge";
|
||||
import { install } from "./install";
|
||||
import { isFolderEmpty } from "./is-folder-empty";
|
||||
import { getOnline } from "./is-online";
|
||||
@@ -11,22 +12,28 @@ import { submodules } from "./submodules";
|
||||
import { downloadAndExtractRepo } from "./templates";
|
||||
import retry from "async-retry";
|
||||
import chalk from "chalk";
|
||||
import fs from "fs";
|
||||
import { writeFile } from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
interface ICreateContract {
|
||||
interface ICreateContractProject {
|
||||
contractPath: string;
|
||||
packageManager: PackageManager;
|
||||
contractName: string;
|
||||
framework?: string;
|
||||
baseContract?: string;
|
||||
onlyContract: boolean;
|
||||
}
|
||||
|
||||
export async function createContract({
|
||||
export async function createContractProject({
|
||||
contractPath,
|
||||
packageManager,
|
||||
framework,
|
||||
contractName,
|
||||
baseContract,
|
||||
}: ICreateContract) {
|
||||
onlyContract,
|
||||
}: ICreateContractProject) {
|
||||
// Check that the selected base contract is valid
|
||||
if (baseContract) {
|
||||
const found = hasBaseContract(baseContract);
|
||||
|
||||
@@ -40,8 +47,8 @@ export async function createContract({
|
||||
}
|
||||
}
|
||||
|
||||
// Check that we have write permission for the specified directory
|
||||
const root = path.resolve(contractPath);
|
||||
|
||||
if (!(await isWriteable(path.dirname(root)))) {
|
||||
console.error(
|
||||
"The application path is not writable, please check folder permissions and try again.",
|
||||
@@ -52,117 +59,179 @@ export async function createContract({
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const projectName = path.basename(root);
|
||||
|
||||
await makeDir(root);
|
||||
if (!isFolderEmpty(root, projectName)) {
|
||||
// Check that the contract name is valid
|
||||
if (!/(^[a-z0-9A-Z]+$)|(^[a-z0-9A-Z]+\.sol$)/.test(contractName)) {
|
||||
console.error(
|
||||
`Contract name ${chalk.red(
|
||||
`"${contractName}"`,
|
||||
)} is not valid (only alphanumeric characters are allowed).`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
// Clean the contract name
|
||||
contractName = contractName.replace(/\.sol$/, "") + ".sol";
|
||||
|
||||
const useYarn = packageManager === "yarn";
|
||||
const isOnline = !useYarn || (await getOnline());
|
||||
const originalDirectory = process.cwd();
|
||||
|
||||
console.log(
|
||||
`Creating a new thirdweb contracts project in ${chalk.green(root)}.`,
|
||||
);
|
||||
console.log();
|
||||
|
||||
process.chdir(root);
|
||||
|
||||
function isErrorLike(err: unknown): err is { message: string } {
|
||||
return (
|
||||
typeof err === "object" &&
|
||||
err !== null &&
|
||||
typeof (err as { message?: unknown }).message === "string"
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`Downloading files. This might take a moment.`);
|
||||
|
||||
let starter = "";
|
||||
if (framework === "hardhat") {
|
||||
starter = "hardhat-javascript-starter";
|
||||
} else if (framework === "forge") {
|
||||
starter = "forge-starter";
|
||||
} else {
|
||||
console.error("Please provide a valid contracts framework.");
|
||||
if (onlyContract) {
|
||||
// If we are already in a contracts project, just create a new contract
|
||||
if (fs.existsSync(path.join(root, contractName))) {
|
||||
console.error(
|
||||
`A contract with the name ${chalk.red(
|
||||
`"${contractName}"`,
|
||||
)} already exists in specified directory.`,
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await retry(
|
||||
() => downloadAndExtractRepo(root, { name: starter, filePath: "" }),
|
||||
{
|
||||
retries: 3,
|
||||
},
|
||||
);
|
||||
|
||||
// Modify the /contracts/MyContract.sol contents to match the base contract
|
||||
if (baseContract && baseContract.length > 0) {
|
||||
const baseContractText = readBaseContract(baseContract);
|
||||
|
||||
// Set the contents of the Contract.sol file to the base contract
|
||||
let contractFile = "";
|
||||
if (framework === "hardhat") {
|
||||
contractFile = path.join(root, "contracts", "Contract.sol");
|
||||
}
|
||||
if (framework === "forge") {
|
||||
contractFile = path.join(root, "src", "Contract.sol");
|
||||
}
|
||||
contractFile = path.join(root, contractName);
|
||||
|
||||
// Write the base contract to the MyContract.sol file
|
||||
await writeFile(contractFile, baseContractText);
|
||||
|
||||
console.log(
|
||||
`${chalk.green("Success!")} Created ${contractName} at ${contractPath}`,
|
||||
);
|
||||
}
|
||||
} catch (reason) {
|
||||
throw new DownloadError(
|
||||
isErrorLike(reason) ? reason.message : String(reason),
|
||||
);
|
||||
}
|
||||
|
||||
console.log("Installing packages. This might take a couple of minutes.");
|
||||
console.log();
|
||||
|
||||
await install(root, null, { packageManager, isOnline });
|
||||
console.log();
|
||||
|
||||
if (tryGitInit(root)) {
|
||||
console.log("Initialized a git repository.");
|
||||
console.log();
|
||||
}
|
||||
|
||||
if (framework === "forge") {
|
||||
await submodules();
|
||||
}
|
||||
|
||||
let cdpath: string;
|
||||
if (path.join(originalDirectory, projectName) === contractPath) {
|
||||
cdpath = projectName;
|
||||
} else {
|
||||
cdpath = contractPath;
|
||||
}
|
||||
// Otherwise, create a new contracts project
|
||||
const projectName = path.basename(root);
|
||||
|
||||
console.log(
|
||||
`${chalk.green("Success!")} Created ${projectName} at ${contractPath}`,
|
||||
);
|
||||
console.log();
|
||||
console.log("Inside that directory, you can run several commands:");
|
||||
console.log();
|
||||
console.log(chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} build`));
|
||||
console.log(
|
||||
" Compiles your contracts and detects thirdweb extensions implemented on them.",
|
||||
);
|
||||
console.log();
|
||||
console.log(chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} deploy`));
|
||||
console.log(" Deploys your contracts with the thirdweb deploy flow.");
|
||||
console.log();
|
||||
console.log(
|
||||
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} release`),
|
||||
);
|
||||
console.log(" Releases your contracts with the thirdweb release flow.");
|
||||
console.log();
|
||||
console.log("We suggest that you begin by typing:");
|
||||
console.log();
|
||||
console.log(chalk.cyan(" cd"), cdpath);
|
||||
console.log();
|
||||
await makeDir(root);
|
||||
if (!isFolderEmpty(root, projectName)) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const isOnline = !useYarn || (await getOnline());
|
||||
const originalDirectory = process.cwd();
|
||||
|
||||
console.log(
|
||||
`Creating a new thirdweb contracts project in ${chalk.green(root)}.`,
|
||||
);
|
||||
console.log();
|
||||
|
||||
process.chdir(root);
|
||||
|
||||
function isErrorLike(err: unknown): err is { message: string } {
|
||||
return (
|
||||
typeof err === "object" &&
|
||||
err !== null &&
|
||||
typeof (err as { message?: unknown }).message === "string"
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
console.log(`Downloading files. This might take a moment.`);
|
||||
|
||||
let starter = "";
|
||||
if (framework === "hardhat") {
|
||||
starter = "hardhat-javascript-starter";
|
||||
} else if (framework === "forge") {
|
||||
starter = "forge-starter";
|
||||
} else {
|
||||
console.error("Please provide a valid contracts framework.");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await retry(
|
||||
() => downloadAndExtractRepo(root, { name: starter, filePath: "" }),
|
||||
{
|
||||
retries: 3,
|
||||
},
|
||||
);
|
||||
|
||||
// Add in a new contracts file with specific base contract
|
||||
if (baseContract && baseContract.length > 0) {
|
||||
const baseContractText = readBaseContract(baseContract);
|
||||
|
||||
// Set the filename of the new file and delete the dummy Contract.sol file
|
||||
let contractFile = "";
|
||||
if (framework === "hardhat") {
|
||||
fs.unlinkSync(path.join(root, "contracts", "Contract.sol"));
|
||||
contractFile = path.join(root, "contracts", contractName);
|
||||
}
|
||||
if (framework === "forge") {
|
||||
fs.unlinkSync(path.join(root, "src", "Contract.sol"));
|
||||
contractFile = path.join(root, "src", contractName);
|
||||
}
|
||||
|
||||
// Write the base contract to the new file
|
||||
await writeFile(contractFile, baseContractText);
|
||||
}
|
||||
} catch (reason) {
|
||||
throw new DownloadError(
|
||||
isErrorLike(reason) ? reason.message : String(reason),
|
||||
);
|
||||
}
|
||||
|
||||
console.log("Installing packages. This might take a couple of minutes.");
|
||||
console.log();
|
||||
|
||||
await install(root, null, { packageManager, isOnline });
|
||||
console.log();
|
||||
|
||||
if (tryGitInit(root)) {
|
||||
console.log("Initialized a git repository.");
|
||||
console.log();
|
||||
}
|
||||
|
||||
if (framework === "forge") {
|
||||
await submodules();
|
||||
}
|
||||
|
||||
let cdpath: string;
|
||||
if (path.join(originalDirectory, projectName) === contractPath) {
|
||||
cdpath = projectName;
|
||||
} else {
|
||||
cdpath = contractPath;
|
||||
}
|
||||
|
||||
console.log(
|
||||
`${chalk.green("Success!")} Created ${projectName} at ${contractPath}`,
|
||||
);
|
||||
console.log();
|
||||
console.log("Inside that directory, you can run several commands:");
|
||||
console.log();
|
||||
console.log(
|
||||
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} build`),
|
||||
);
|
||||
console.log(
|
||||
" Compiles your contracts and detects thirdweb extensions implemented on them.",
|
||||
);
|
||||
console.log();
|
||||
console.log(
|
||||
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} deploy`),
|
||||
);
|
||||
console.log(" Deploys your contracts with the thirdweb deploy flow.");
|
||||
console.log();
|
||||
console.log(
|
||||
chalk.cyan(` ${packageManager}${useYarn ? "" : " run"} release`),
|
||||
);
|
||||
console.log(" Releases your contracts with the thirdweb release flow.");
|
||||
console.log();
|
||||
console.log("We suggest that you begin by typing:");
|
||||
console.log();
|
||||
console.log(chalk.cyan(" cd"), cdpath);
|
||||
console.log();
|
||||
|
||||
if (framework === "forge") {
|
||||
const isInstalled = await hasForge();
|
||||
|
||||
if (!isInstalled) {
|
||||
console.log(
|
||||
`\n${chalk.yellowBright(
|
||||
`warning`,
|
||||
)} You don't have forge installed on this machine, and will need it to run this project! \n\nYou can install forge by following these instructions:\n${chalk.blueBright(
|
||||
`https://book.getfoundry.sh/getting-started/installation`,
|
||||
)}\n`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { exec } from "child_process";
|
||||
|
||||
export async function hasForge() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
return await new Promise((resolve, reject) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
exec("forge --version", (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
resolve(false);
|
||||
}
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,11 +1,26 @@
|
||||
import spawn from "cross-spawn";
|
||||
|
||||
export async function runCommand(command: string, args: string[]) {
|
||||
export async function runCommand(
|
||||
command: string,
|
||||
args: string[],
|
||||
logging: boolean = false,
|
||||
) {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
/**
|
||||
* Spawn the installation process.
|
||||
*/
|
||||
const child = spawn(command, args);
|
||||
child.stdout?.on("data", (data) => {
|
||||
if (logging) {
|
||||
console.log(data.toString());
|
||||
}
|
||||
});
|
||||
|
||||
child.stderr?.on("error", (err) => {
|
||||
if (logging) {
|
||||
console.error(err);
|
||||
}
|
||||
});
|
||||
child.on("close", (code) => {
|
||||
if (code !== 0) {
|
||||
reject({ command: `${command}` });
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import NPMDetector from "../core/detection/npm";
|
||||
import ViteDetector from "../core/detection/vite";
|
||||
import YarnDetector from "../core/detection/yarn";
|
||||
import { runCommand } from "../create/helpers/run-command";
|
||||
import { upload } from "../storage/command";
|
||||
import { DEFAULT_IPFS_GATEWAY } from "@thirdweb-dev/sdk";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
|
||||
export async function deployApp(distPath = "dist", projectPath = ".") {
|
||||
const storage = new ThirdwebStorage();
|
||||
const supportedFrameworks = [new ViteDetector()];
|
||||
|
||||
const possibleProjects = supportedFrameworks
|
||||
.filter((detector) => detector.matches(projectPath))
|
||||
.map((detector) => detector.projectType);
|
||||
|
||||
const hasYarn = new YarnDetector().matches(".");
|
||||
const hasNPM = new NPMDetector().matches(".");
|
||||
|
||||
if (possibleProjects.length === 0) {
|
||||
throw new Error("No supported project detected");
|
||||
}
|
||||
|
||||
try {
|
||||
if (hasYarn) {
|
||||
await runCommand("yarn", ["build"]);
|
||||
} else if (hasNPM) {
|
||||
await runCommand("npm", ["build"]);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Can't build project");
|
||||
return Promise.reject("Can't build project");
|
||||
}
|
||||
|
||||
try {
|
||||
let url = await upload(storage, distPath);
|
||||
url = url.replace("ipfs://", DEFAULT_IPFS_GATEWAY);
|
||||
return `${url}/index.html`;
|
||||
} catch (err) {
|
||||
console.error("Can't upload project");
|
||||
return Promise.reject("Can't upload project");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
import { processProject } from "../common/processor";
|
||||
import { info, logger } from "../core/helpers/logger";
|
||||
import generateDashboardUrl from "../helpers/generate-dashboard-url";
|
||||
import { deployApp } from "./app";
|
||||
import chalk from "chalk";
|
||||
|
||||
type DeployOptions = {
|
||||
name: string;
|
||||
contractVersion: string;
|
||||
app: boolean;
|
||||
path?: string;
|
||||
distPath?: string;
|
||||
};
|
||||
|
||||
export async function deploy(options: DeployOptions) {
|
||||
if (options.name) {
|
||||
const url = generateDashboardUrl(options.name, options.contractVersion);
|
||||
|
||||
if (!url) {
|
||||
logger.error(
|
||||
chalk.red(
|
||||
`Could not find a contract named ${options.name} ${
|
||||
options.contractVersion || ""
|
||||
}`,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
info(`Open this link to deploy your contract: ${chalk.blueBright(url)}`);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
if (options.app) {
|
||||
try {
|
||||
let url = await deployApp(options.distPath, options.path);
|
||||
info(`Here is the link to your app: ${chalk.blueBright(url.toString())}`);
|
||||
return url.toString();
|
||||
} catch (err) {
|
||||
logger.error("Failed to deploy app, No compatible project found", err);
|
||||
return Promise.reject(
|
||||
"failed to deploy app, no compatible project found",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const url = await processProject(options, "deploy");
|
||||
info(
|
||||
`Open this link to deploy your contracts: ${chalk.blueBright(
|
||||
url.toString(),
|
||||
)}`,
|
||||
);
|
||||
return url.toString();
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import { exec } from "child_process";
|
||||
|
||||
type PackageManager = "npm" | "yarn" | "pnpm";
|
||||
|
||||
interface Installation {
|
||||
packageManager: PackageManager;
|
||||
isGlobal: boolean;
|
||||
}
|
||||
|
||||
export async function findPackageInstallation(): Promise<
|
||||
Installation | undefined
|
||||
> {
|
||||
const isLocal = await isInstalledLocally();
|
||||
if (isLocal) {
|
||||
const packageManager = await import("detect-package-manager").then(
|
||||
({ detect }) => {
|
||||
return detect();
|
||||
},
|
||||
);
|
||||
|
||||
return { packageManager, isGlobal: false };
|
||||
}
|
||||
|
||||
const isGlobalNpm = await isInstalledGloballyWithNpm();
|
||||
if (isGlobalNpm) {
|
||||
return { packageManager: "npm", isGlobal: true };
|
||||
}
|
||||
|
||||
const isGlobalYarn = await isInstalledGloballyWithYarn();
|
||||
if (isGlobalYarn) {
|
||||
return { packageManager: "yarn", isGlobal: true };
|
||||
}
|
||||
|
||||
const isGlobalPnpm = await isInstalledGloballyWithPnpm();
|
||||
if (isGlobalPnpm) {
|
||||
return { packageManager: "pnpm", isGlobal: true };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// For LOCAL packages, npm ls picks up things installed by yarn and pnpm too
|
||||
async function isInstalledLocally(): Promise<boolean> {
|
||||
const packages = await detectPackages("npm ls --depth=0");
|
||||
return containsThirdweb(packages || []);
|
||||
}
|
||||
|
||||
// But for GLOBAL packages, we need to use a separate command for each one
|
||||
async function isInstalledGloballyWithNpm(): Promise<boolean> {
|
||||
const packages = await detectPackages("npm ls -g --depth=0");
|
||||
return containsThirdweb(packages || []);
|
||||
}
|
||||
|
||||
async function isInstalledGloballyWithYarn(): Promise<boolean> {
|
||||
const packages = await detectPackages("yarn --cwd `yarn global dir` list");
|
||||
return containsThirdweb(packages || []);
|
||||
}
|
||||
|
||||
async function isInstalledGloballyWithPnpm(): Promise<boolean> {
|
||||
const packages: string[] = await new Promise((resolve) => {
|
||||
exec(`pnpm list -g --depth=0`, (err, stdout) => {
|
||||
var pkgs: string[] = [];
|
||||
pkgs = stdout.split("dependencies:")[1]?.trim().split("\n") || [];
|
||||
pkgs = pkgs.map((pkg) => pkg.replace(" ", "@"));
|
||||
resolve(pkgs);
|
||||
});
|
||||
});
|
||||
return containsThirdweb(packages || []);
|
||||
}
|
||||
|
||||
function containsThirdweb(packages: string[]) {
|
||||
return packages.some((pkg) => pkg.match(/^thirdweb/));
|
||||
}
|
||||
|
||||
async function detectPackages(cmd: string): Promise<string[]> {
|
||||
return new Promise((resolve) => {
|
||||
exec(cmd, (err, stdout) => {
|
||||
var packages: string[] = [];
|
||||
packages = stdout.split("\n");
|
||||
// We're one short on '-' to support both yarn and npm
|
||||
packages = packages.filter(function (item) {
|
||||
if (item.match(/^├─.+/g) !== null) {
|
||||
return true;
|
||||
}
|
||||
if (item.match(/^└─.+/g) !== null) {
|
||||
return true;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
packages = packages
|
||||
.map(function (item) {
|
||||
if (item.match(/^├─.+/g) !== null) {
|
||||
return item.replace(/(^├──\s|^├─\s)/g, "");
|
||||
}
|
||||
if (item.match(/^└─.+/g) !== null) {
|
||||
return item.replace(/(^└──\s|^├─\s)/g, "");
|
||||
}
|
||||
})
|
||||
.filter((item) => !!item) as string[];
|
||||
resolve(packages);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -13,18 +13,18 @@ export default function generateDashboardUrl(
|
||||
// Pre-built contract
|
||||
else {
|
||||
const mapping = {
|
||||
"signature-drop": "drop/signature-drop",
|
||||
"nft-drop": "drop/nft-drop",
|
||||
"edition-drop": "drop/edition-drop",
|
||||
"nft-collection": "token/nft-collection",
|
||||
edition: "token/edition",
|
||||
"token-drop": "drop/token-drop",
|
||||
token: "token/token",
|
||||
marketplace: "marketplace/marketplace",
|
||||
split: "governance/split",
|
||||
vote: "governance/vote",
|
||||
pack: "token/pack",
|
||||
multiwrap: "token/multiwrap",
|
||||
"signature-drop": "SignatureDrop",
|
||||
"nft-drop": "DropERC721",
|
||||
"edition-drop": "DropERC1155",
|
||||
"nft-collection": "TokenERC721",
|
||||
edition: "TokenERC1155",
|
||||
"token-drop": "DropERC20",
|
||||
token: "TokenERC20",
|
||||
marketplace: "Marketplace",
|
||||
split: "Split",
|
||||
vote: "VoteERC20",
|
||||
pack: "Pack",
|
||||
multiwrap: "Multiwrap",
|
||||
};
|
||||
|
||||
const foundMapping = mapping[name as keyof typeof mapping];
|
||||
@@ -33,6 +33,6 @@ export default function generateDashboardUrl(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return `https://thirdweb.com/contracts/new/pre-built/${foundMapping}`;
|
||||
return `https://thirdweb.com/thirdweb.eth/${foundMapping}`;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { logger } from "../core/helpers/logger";
|
||||
import { spinner } from "../core/helpers/logger";
|
||||
import { BufferOrStringWithName, ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import chalk from "chalk";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
@@ -33,22 +31,12 @@ export async function upload(
|
||||
uploadPath: string,
|
||||
): Promise<string> {
|
||||
if (!uploadPath) {
|
||||
logger.error(
|
||||
`Please pass a path to a file or directory to upload with the following format:\n ${chalk.blueBright(
|
||||
`npx thirdweb@latest upload path/to/file.jpg`,
|
||||
)}\n`,
|
||||
);
|
||||
process.exit(1);
|
||||
return Promise.reject("No path provided");
|
||||
}
|
||||
|
||||
const pathExists = fs.existsSync(uploadPath);
|
||||
if (!pathExists) {
|
||||
logger.error(
|
||||
`Invalid path ${chalk.blueBright(
|
||||
uploadPath,
|
||||
)} provided. Please provide a valid path to a file or directory to upload."`,
|
||||
);
|
||||
process.exit(1);
|
||||
return Promise.reject("Invalid path provided");
|
||||
}
|
||||
|
||||
let uri = "";
|
||||
@@ -57,12 +45,7 @@ export async function upload(
|
||||
const files = recurseFiles(uploadPath, uploadPath);
|
||||
|
||||
if (files.length === 0) {
|
||||
logger.error(
|
||||
`No files detected in specified directory ${chalk.blueBright(
|
||||
uploadPath,
|
||||
)} to upload.`,
|
||||
);
|
||||
process.exit(1);
|
||||
return Promise.reject("No files detected in specified directory");
|
||||
}
|
||||
|
||||
const spin = spinner(
|
||||
@@ -82,12 +65,7 @@ export async function upload(
|
||||
uri = await storage.upload(file, { uploadWithoutDirectory: true });
|
||||
spin.succeed("Succesfully uploaded file to IPFS.");
|
||||
} else {
|
||||
logger.error(
|
||||
`Path ${chalk.blueBright(
|
||||
uploadPath,
|
||||
)} does not point to a valid file or directory. Please provide a valid path to a file or directory to upload`,
|
||||
);
|
||||
process.exit(1);
|
||||
return Promise.reject("Invalid path provided");
|
||||
}
|
||||
|
||||
return uri;
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @thirdweb-dev/contracts-js
|
||||
|
||||
## 1.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#438](https://github.com/thirdweb-dev/js/pull/438) [`f451da6`](https://github.com/thirdweb-dev/js/commit/f451da6395689a5f89800ee63f34b6175b61f703) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix SigMint detection for OSRF NFT Collection contracts
|
||||
|
||||
## 1.2.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#376](https://github.com/thirdweb-dev/js/pull/376) [`4af785c`](https://github.com/thirdweb-dev/js/commit/4af785c37c831ecd7087c1c9eb9095922cac0855) Thanks [@adam-maj](https://github.com/adam-maj)! - Update tiered-drop with tokens claimed
|
||||
|
||||
- [#373](https://github.com/thirdweb-dev/js/pull/373) [`6f818f3`](https://github.com/thirdweb-dev/js/commit/6f818f393eb9023b53a3358d62d60ec23a9246bd) Thanks [@adam-maj](https://github.com/adam-maj)! - Update tiered-drop contract version
|
||||
|
||||
## 1.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/contracts-js",
|
||||
"version": "1.2.0",
|
||||
"version": "1.2.2",
|
||||
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js.esm.js",
|
||||
"license": "Apache-2.0",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/contracts-js",
|
||||
"dependencies": {
|
||||
"@thirdweb-dev/contracts": "3.2.0-4"
|
||||
"@thirdweb-dev/contracts": "3.2.8-0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
"@preconstruct/cli": "^2.2.1",
|
||||
"@typechain/ethers-v5": "10.0.0",
|
||||
"ethers": "^5.7.0",
|
||||
"ethers": "^5.7.2",
|
||||
"typechain": "^8.1.0",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
||||
"@typescript-eslint/parser": "^5.33.0",
|
||||
"eslint-config-next": "^12.0.8",
|
||||
"eslint-config-next": "12.3.1",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-config-turbo": "latest",
|
||||
"eslint-plugin-react": "^7.28.0"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-typescript",
|
||||
["@babel/preset-env", { "targets": "defaults, not ie 11" }]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# folders
|
||||
dist/
|
||||
|
||||
# files
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["thirdweb"],
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
# @thirdweb-dev/pay
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#433](https://github.com/thirdweb-dev/js/pull/433) [`7269268`](https://github.com/thirdweb-dev/js/commit/72692689e9adb41e92038765fd01a36c2b7457e1) Thanks [@jnsdls](https://github.com/jnsdls)! - Initialize Pay Package
|
||||
@@ -0,0 +1,16 @@
|
||||
<p align="center">
|
||||
<br />
|
||||
<a href="https://thirdweb.com"><img src="https://github.com/thirdweb-dev/js/blob/main/packages/sdk/logo.svg?raw=true" width="200" alt=""/></a>
|
||||
<br />
|
||||
</p>
|
||||
<h1 align="center">thirdweb wallets</h1>
|
||||
<p align="center">
|
||||
<!-- <a href="https://www.npmjs.com/package/@thirdweb-dev/sdk"><img src="https://img.shields.io/npm/v/@thirdweb-dev/sdk?color=red&label=npm&logo=npm" alt="npm version"/></a> -->
|
||||
<!-- <a href="https://github.com/thirdweb-dev/js/actions/workflows/CI.yml"><img alt="Build Status" src="https://github.com/thirdweb-dev/js/actions/workflows/CI.yml/badge.svg"/></a> -->
|
||||
<!-- <a href="https://discord.gg/thirdweb"><img alt="Join our Discord!" src="https://img.shields.io/discord/834227967404146718.svg?color=7289da&label=discord&logo=discord&style=flat"/></a> -->
|
||||
|
||||
</p>
|
||||
<!-- <p align="center"><strong>Best in class Web3 SDK for Browser, Node and Mobile apps</strong></p> -->
|
||||
<br />
|
||||
|
||||
### todo
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-pay-integrations-coinbase.cjs.js",
|
||||
"module": "dist/thirdweb-dev-pay-integrations-coinbase.esm.js"
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/pay",
|
||||
"version": "0.1.0",
|
||||
"main": "dist/thirdweb-dev-pay.cjs.js",
|
||||
"module": "dist/thirdweb-dev-pay.esm.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"module": "./dist/thirdweb-dev-pay.esm.js",
|
||||
"default": "./dist/thirdweb-dev-pay.cjs.js"
|
||||
},
|
||||
"./integrations/coinbase": {
|
||||
"module": "./integrations/coinbase/dist/thirdweb-dev-pay-integrations-coinbase.esm.js",
|
||||
"default": "./integrations/coinbase/dist/thirdweb-dev-pay-integrations-coinbase.cjs.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/pay",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/thirdweb-dev/js/issues"
|
||||
},
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"files": [
|
||||
"dist/",
|
||||
"integrations/"
|
||||
],
|
||||
"preconstruct": {
|
||||
"entrypoints": [
|
||||
"index.ts",
|
||||
"integrations/**"
|
||||
],
|
||||
"___experimentalFlags_WILL_CHANGE_IN_PATCH": {
|
||||
"exports": true
|
||||
},
|
||||
"exports": true
|
||||
},
|
||||
"sideEffects": false,
|
||||
"dependencies": {
|
||||
"@coinbase/cbpay-js": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preconstruct/cli": "^2.2.1",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier --write 'src/**/*'",
|
||||
"lint": "eslint src/",
|
||||
"fix": "eslint src/ --fix",
|
||||
"clean": "rm -rf dist/",
|
||||
"build": "tsc && preconstruct build",
|
||||
"push": "yalc push"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./integrations/coinbase";
|
||||
@@ -0,0 +1,62 @@
|
||||
import { initOnRamp, InitOnRampParams } from "@coinbase/cbpay-js";
|
||||
|
||||
interface CoinbasePayOptions extends Pick<InitOnRampParams, "appId"> {}
|
||||
|
||||
const CHAIN_ID_MAP = {
|
||||
[-1]: "solana",
|
||||
1: "ethereum",
|
||||
69: "optimism",
|
||||
137: "polygon",
|
||||
} as const;
|
||||
|
||||
export type FundWalletOptions = {
|
||||
address: string;
|
||||
chainId: keyof typeof CHAIN_ID_MAP;
|
||||
assets?: string[];
|
||||
};
|
||||
|
||||
export class CoinbasePayIntegration {
|
||||
#appId: string;
|
||||
constructor(options: CoinbasePayOptions) {
|
||||
this.#appId = options.appId;
|
||||
}
|
||||
|
||||
async fundWallet(opts: FundWalletOptions): Promise<void> {
|
||||
const { address, chainId, assets } = opts;
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
initOnRamp(
|
||||
{
|
||||
appId: this.#appId,
|
||||
widgetParameters: {
|
||||
destinationWallets: [
|
||||
{
|
||||
address,
|
||||
assets,
|
||||
supportedNetworks: [CHAIN_ID_MAP[chainId]],
|
||||
},
|
||||
],
|
||||
},
|
||||
experienceLoggedIn: "embedded",
|
||||
experienceLoggedOut: "popup",
|
||||
closeOnExit: true,
|
||||
onSuccess: () => {
|
||||
res();
|
||||
},
|
||||
onExit(error) {
|
||||
if (error) {
|
||||
return rej(error);
|
||||
}
|
||||
return res();
|
||||
},
|
||||
},
|
||||
(err, instance) => {
|
||||
if (err || !instance) {
|
||||
return rej(err);
|
||||
}
|
||||
instance.open();
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "@thirdweb-dev/tsconfig/sdk.json",
|
||||
"include": ["src", "types"],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
@@ -1,5 +1,63 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 3.6.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#448](https://github.com/thirdweb-dev/js/pull/448) [`7a37e56`](https://github.com/thirdweb-dev/js/commit/7a37e564fd5d5a9df84c8da44ecaf6c42f67a0e2) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - allow `useContract` to fail faster to enable the import case
|
||||
|
||||
## 3.6.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#443](https://github.com/thirdweb-dev/js/pull/443) [`8c6cdaa`](https://github.com/thirdweb-dev/js/commit/8c6cdaa2887fb2cc40d3ee6991233d195d103805) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix magic link connector not connecting to the right chain
|
||||
|
||||
## 3.6.5
|
||||
|
||||
## 3.6.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#425](https://github.com/thirdweb-dev/js/pull/425) [`f545a67`](https://github.com/thirdweb-dev/js/commit/f545a67e9fb597d27bb39ca515d24d306fbb121a) Thanks [@adam-maj](https://github.com/adam-maj)! - Add sameSite none and include credentials
|
||||
|
||||
- [#420](https://github.com/thirdweb-dev/js/pull/420) [`639e535`](https://github.com/thirdweb-dev/js/commit/639e535ed55280ad9d081001aab3f5af72bb3e45) Thanks [@jnsdls](https://github.com/jnsdls)! - update deps
|
||||
|
||||
## 3.6.3
|
||||
|
||||
## 3.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#405](https://github.com/thirdweb-dev/js/pull/405) [`ccb7db4`](https://github.com/thirdweb-dev/js/commit/ccb7db48739b8dddcb2c032b3b6e3e5200485715) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add updateAll param to creators and royalty update hooks for Solana
|
||||
|
||||
## 3.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#392](https://github.com/thirdweb-dev/js/pull/392) [`846022e`](https://github.com/thirdweb-dev/js/commit/846022e2cfb12b846aae029b85899fb72fd2c9ad) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix unlimited price for useActiveClaimConditionForWallet
|
||||
|
||||
- [#388](https://github.com/thirdweb-dev/js/pull/388) [`7c0744a`](https://github.com/thirdweb-dev/js/commit/7c0744a006e78987ad8b271b2c64f4bac7759510) Thanks [@adam-maj](https://github.com/adam-maj)! - Add support for total supply and pagination on get all
|
||||
|
||||
## 3.6.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#386](https://github.com/thirdweb-dev/js/pull/386) [`612bcdd`](https://github.com/thirdweb-dev/js/commit/612bcdd16fc242d8b04bc70d609e44b0df47ed3f) Thanks [@jnsdls](https://github.com/jnsdls)! - [Gnosis Connector] - switch to safe.global hostname & add support for bsc and optimism chains
|
||||
|
||||
- [#364](https://github.com/thirdweb-dev/js/pull/364) [`7cb8e59`](https://github.com/thirdweb-dev/js/commit/7cb8e59be48dc923316eb36ab43a1bef7364f6b1) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add experimental `useActiveClaimConditionForWallet()` hook
|
||||
|
||||
## 3.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#369](https://github.com/thirdweb-dev/js/pull/369) [`2d3fca5`](https://github.com/thirdweb-dev/js/commit/2d3fca52373046c88392139922e9c9da79f9a2d4) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add useClaimerProofs hook
|
||||
|
||||
- [#378](https://github.com/thirdweb-dev/js/pull/378) [`32d91ef`](https://github.com/thirdweb-dev/js/commit/32d91ef709c8fb92a903e52c65b27538a80ea4eb) Thanks [@mykcryptodev](https://github.com/mykcryptodev)! - round borders for buttons and menus on safari
|
||||
|
||||
- [#377](https://github.com/thirdweb-dev/js/pull/377) [`b79dc18`](https://github.com/thirdweb-dev/js/commit/b79dc18f7ab5155bbf4af02dc1a953546160bad0) Thanks [@adam-maj](https://github.com/adam-maj)! - Add event filters
|
||||
|
||||
## 3.5.1
|
||||
|
||||
## 3.5.0
|
||||
|
||||
## 3.4.5
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.5.0",
|
||||
"version": "3.6.7",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -62,7 +62,7 @@
|
||||
},
|
||||
"sideEffects:": false,
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.18.10",
|
||||
"@babel/core": "^7.19.3",
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
"@babel/preset-react": "^7.18.6",
|
||||
"@babel/preset-typescript": "^7.18.6",
|
||||
@@ -73,6 +73,7 @@
|
||||
"@preconstruct/cli": "^2.2.1",
|
||||
"@solana/wallet-adapter-base": "^0.9.17",
|
||||
"@solana/wallet-adapter-react": "^0.15.19",
|
||||
"@solana/wallet-adapter-wallets": "^0.19.0",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"@thirdweb-dev/sdk": "*",
|
||||
"@types/color": "^3.0.3",
|
||||
@@ -87,7 +88,7 @@
|
||||
"eslint-plugin-inclusive-language": "^2.2.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"ethers": "^5.7.1",
|
||||
"ethers": "^5.7.2",
|
||||
"prettier": "^2.7.1",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
||||
@@ -14,19 +14,19 @@ export const SupportedNetworkSelect: React.FC<SupportedNetworkSelectProps> = ({
|
||||
const deprecatedNetworks = useMemo(() => {
|
||||
return SUPPORTED_CHAIN_IDS.map((supportedChain) => {
|
||||
return getChainFromChainId(supportedChain);
|
||||
}).filter((n) => !!n.deprecated);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const testnets = useMemo(() => {
|
||||
return SUPPORTED_CHAIN_IDS.map((supportedChain) => {
|
||||
return getChainFromChainId(supportedChain);
|
||||
}).filter((n) => n.testnet && !n.deprecated);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const mainnets = useMemo(() => {
|
||||
return SUPPORTED_CHAIN_IDS.map((supportedChain) => {
|
||||
return getChainFromChainId(supportedChain);
|
||||
}).filter((n) => !n.testnet && !n.deprecated);
|
||||
});
|
||||
}, []);
|
||||
return (
|
||||
<Select {...selectProps}>
|
||||
|
||||
@@ -15,7 +15,7 @@ export interface ThirdwebNftMediaProps extends SharedMediaProps {
|
||||
/**
|
||||
* This component can be used to render NFTs from the thirdweb SDK.
|
||||
* Props: {@link ThirdwebNftMediaProps}
|
||||
*
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { ThirdwebNftMedia, useContract, useNFT } from "@thirdweb-dev/react";
|
||||
|
||||
@@ -37,8 +37,19 @@ const BaseButton = styled.button<BaseButtonProps>`
|
||||
cursor: not-allowed;
|
||||
}
|
||||
&:focus {
|
||||
outline: 2px solid ${(props) => (props.theme as TwUiTheme).colors.accent};
|
||||
outline-offset: 1px;
|
||||
position: relative;
|
||||
border-radius: 0.5em;
|
||||
outline: 0;
|
||||
}
|
||||
&:focus:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: -5px;
|
||||
right: -5px;
|
||||
bottom: -5px;
|
||||
left: -5px;
|
||||
border: 2px solid ${(props) => (props.theme as TwUiTheme).colors.accent};
|
||||
border-radius: 11px;
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -8,10 +8,23 @@ export const Menu = styled.ul<MenuProps>`
|
||||
margin: 0;
|
||||
background: ${(props) => (props.theme as TwUiTheme).colors.background};
|
||||
color: ${(props) => (props.theme as TwUiTheme).colors.text};
|
||||
outline-color: ${(props) => (props.theme as TwUiTheme).colors.accent};
|
||||
outline-style: solid;
|
||||
outline-offset: 0px;
|
||||
list-style: none;
|
||||
border-radius: 0.5em;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
pointer-events: auto;
|
||||
&:focus {
|
||||
outline: 0;
|
||||
}
|
||||
&:after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
border: 1px solid ${(props) => (props.theme as TwUiTheme).colors.accent};
|
||||
border-radius: 0.5em;
|
||||
pointer-events: none;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -9,16 +9,21 @@ import {
|
||||
useContext as useWagmiContext,
|
||||
} from "wagmi";
|
||||
|
||||
// exerpt from https://docs.gnosis-safe.io/backend/available-services
|
||||
const CHAIN_ID_TO_GNOSIS_SERVER_URL = {
|
||||
// mainnet
|
||||
1: "https://safe-transaction.mainnet.gnosis.io",
|
||||
1: "https://safe-transaction-mainnet.safe.global",
|
||||
// avalanche
|
||||
43114: "https://safe-transaction.avalanche.gnosis.io",
|
||||
43114: "https://safe-transaction-avalanche.safe.global",
|
||||
// polygon
|
||||
137: "https://safe-transaction.polygon.gnosis.io",
|
||||
137: "https://safe-transaction-polygon.safe.global",
|
||||
// goerli
|
||||
5: "https://safe-transaction.goerli.gnosis.io",
|
||||
};
|
||||
5: "https://safe-transaction-goerli.safe.global",
|
||||
// bsc
|
||||
56: "https://safe-transaction-bsc.safe.global",
|
||||
// optimism
|
||||
10: "https://safe-transaction-optimism.safe.global",
|
||||
} as const;
|
||||
|
||||
export interface GnosisConnectorArguments {
|
||||
safeAddress: string;
|
||||
@@ -28,6 +33,8 @@ export interface GnosisConnectorArguments {
|
||||
const __IS_SERVER__ = typeof window === "undefined";
|
||||
|
||||
export class GnosisSafeConnector extends Connector {
|
||||
static supportedChains = Object.keys(CHAIN_ID_TO_GNOSIS_SERVER_URL);
|
||||
public supportedChains = GnosisSafeConnector.supportedChains;
|
||||
id = "gnosis";
|
||||
ready = __IS_SERVER__;
|
||||
name = "Gnosis Safe";
|
||||
@@ -60,6 +67,11 @@ export class GnosisSafeConnector extends Connector {
|
||||
};
|
||||
}
|
||||
|
||||
public isChainSupported(chainId: string | number) {
|
||||
const id = normalizeChainId(chainId);
|
||||
return !this.isChainUnsupported(id);
|
||||
}
|
||||
|
||||
private async createSafeSigner() {
|
||||
const signer = await this.previousConnector?.getSigner();
|
||||
const safeAddress = this.config?.safeAddress;
|
||||
@@ -91,7 +103,10 @@ export class GnosisSafeConnector extends Connector {
|
||||
import("@gnosis.pm/safe-ethers-lib"),
|
||||
]);
|
||||
|
||||
const ethAdapter = new safeEthersLib.default({ ethers, signer });
|
||||
const ethAdapter = new safeEthersLib.default({
|
||||
ethers,
|
||||
signerOrProvider: signer,
|
||||
});
|
||||
|
||||
const safe = await safeCoreSdk.default.create({
|
||||
ethAdapter: ethAdapter as any,
|
||||
|
||||
@@ -62,6 +62,18 @@ export class MagicConnector extends Connector {
|
||||
const { apiKey, ...options } = this.options;
|
||||
const configuration = this.getConfiguration();
|
||||
|
||||
const chains = Object.entries(this.options.rpcUrls);
|
||||
if (chains.length > 1) {
|
||||
console.warn(
|
||||
`Magic only supports connecting to one chain at a time. Using the first chain specified in rpcUrls: ${chains[0]}.`,
|
||||
);
|
||||
}
|
||||
const [chainId, rpcUrl] = chains[0];
|
||||
this.options.network = {
|
||||
chainId: parseInt(chainId),
|
||||
rpcUrl,
|
||||
};
|
||||
|
||||
try {
|
||||
invariant(
|
||||
configuration,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { NATIVE_TOKENS, SUPPORTED_CHAIN_ID } from "@thirdweb-dev/sdk";
|
||||
import { ChainId } from "@thirdweb-dev/sdk";
|
||||
import type { Chain as WagmiChain } from "wagmi";
|
||||
|
||||
export type Chain = WagmiChain & { deprecated?: boolean };
|
||||
export type Chain = WagmiChain;
|
||||
const chain: Record<string, Chain> = {
|
||||
mainnet: {
|
||||
id: ChainId.Mainnet,
|
||||
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/base";
|
||||
import { useSDK, useSDKChainId } from "../../providers/base";
|
||||
import { getErcs, DropContract, WalletAddress } from "../../types";
|
||||
import {
|
||||
cacheKeys,
|
||||
@@ -14,8 +14,12 @@ import {
|
||||
ClaimCondition,
|
||||
ClaimConditionFetchOptions,
|
||||
ClaimConditionInput,
|
||||
SnapshotEntryWithProof,
|
||||
fetchCurrencyValue,
|
||||
convertToReadableQuantity,
|
||||
fetchCurrencyMetadata,
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import { BigNumberish } from "ethers";
|
||||
import { BigNumberish, constants, utils } from "ethers";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
@@ -45,7 +49,7 @@ export type SetClaimConditionsParams = {
|
||||
/** **********************/
|
||||
|
||||
/**
|
||||
* Use this to get the active claim conditon for ERC20, ERC721 or ERC1155 based contracts. They need to extend the `claimCondition` extension for this hook to work.
|
||||
* Use this to get the active claim condition for ERC20, ERC721 or ERC1155 based contracts. They need to extend the `claimCondition` extension for this hook to work.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
@@ -60,7 +64,7 @@ export type SetClaimConditionsParams = {
|
||||
* const { data: activeClaimCondition, isLoading, error } = useActiveClaimCondition(<YourERC1155ContractInstance>, <tokenId>);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a contract that extends the ERC721 or ERC1155 spec and implements the `claimConditions` extension.
|
||||
* @param contract - an instance of a contract that extends the ERC721, ERC1155 or ERC20 spec and implements the `claimConditions` extension.
|
||||
* @param tokenId - the id of the token to fetch the claim conditions for (if the contract is an ERC1155 contract)
|
||||
* @returns a response object with the currently active claim condition
|
||||
* @twfeature ERC721ClaimableWithConditions | ERC1155ClaimableWithConditions | ERC20ClaimableWithConditions
|
||||
@@ -106,7 +110,80 @@ export function useActiveClaimCondition(
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to get all claim conditons for ERC20, ERC721 or ERC1155 based contracts. They need to extend the `claimCondition` extension for this hook to work.
|
||||
* Use this to get the claimer proofs for an adddress for ERC20, ERC721 or ERC1155 based contracts. They need to extend the `claimCondition` extension for this hook to work.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: claimerProofs, isLoading, error } = useClaimerProofs(<YourERC20ContractInstance>);
|
||||
* ```
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: claimerProofs, isLoading, error } = useClaimerProofs(<YourERC721ContractInstance>);
|
||||
* ```
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: claimerProofs, isLoading, error } = useClaimerProofs(<YourERC1155ContractInstance>, <tokenId>);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a contract that extends the ERC721, ERC1155 or ERC20 spec and implements the `claimConditions` extension.
|
||||
* @param claimerAddress - the address of the claimer to fetch the claimer proofs for
|
||||
* @param tokenId - the id of the token to fetch the claimer proofs for (if the contract is an ERC1155 contract)
|
||||
* @param claimConditionId - optional the claim condition id to get the proofs for
|
||||
* @returns a response object with the snapshot for the provided address
|
||||
* @twfeature ERC721ClaimableWithConditions | ERC1155ClaimableWithConditions | ERC20ClaimableWithConditions
|
||||
* @beta
|
||||
*/
|
||||
export function useClaimerProofs(
|
||||
contract: RequiredParam<DropContract>,
|
||||
claimerAddress: string,
|
||||
tokenId?: BigNumberish,
|
||||
claimConditionId?: BigNumberish,
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
const { erc1155, erc721, erc20 } = getErcs(contract);
|
||||
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.extensions.claimConditions.getClaimerProofs(
|
||||
contractAddress,
|
||||
tokenId,
|
||||
),
|
||||
() => {
|
||||
if (erc1155) {
|
||||
requiredParamInvariant(
|
||||
tokenId,
|
||||
"tokenId is required for ERC1155 claim conditions",
|
||||
);
|
||||
return erc1155.claimConditions.getClaimerProofs(
|
||||
tokenId,
|
||||
claimerAddress,
|
||||
claimConditionId,
|
||||
);
|
||||
}
|
||||
if (erc721) {
|
||||
return erc721.claimConditions.getClaimerProofs(
|
||||
claimerAddress,
|
||||
claimConditionId,
|
||||
);
|
||||
}
|
||||
if (erc20) {
|
||||
return erc20.claimConditions.getClaimerProofs(
|
||||
claimerAddress,
|
||||
claimConditionId,
|
||||
);
|
||||
}
|
||||
throw new Error("Contract must be ERC721, ERC1155 or ERC20");
|
||||
},
|
||||
{
|
||||
// Checks that happen here:
|
||||
// 1. if the contract is based on ERC1155 contract => tokenId cannot be `undefined`
|
||||
// 2. if the contract is NOT based on ERC1155 => we have to have either an ERC721 or ERC20 contract
|
||||
enabled: erc1155 ? tokenId !== undefined : !!erc721 || !!erc20,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to get all claim conditions for ERC20, ERC721 or ERC1155 based contracts. They need to extend the `claimCondition` extension for this hook to work.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
@@ -121,7 +198,7 @@ export function useActiveClaimCondition(
|
||||
* const { data: claimConditions, isLoading, error } = useClaimConditions(<YourERC1155ContractInstance>, <tokenId>);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a contract that extends the ERC721 or ERC1155 spec and implements the `claimConditions` extension.
|
||||
* @param contract - an instance of a contract that extends the ERC721, ERC1155 or ERC20 spec and implements the `claimConditions` extension.
|
||||
* @param tokenId - the id of the token to fetch the claim conditions for (if the contract is an ERC1155 contract)
|
||||
* @returns a response object with the list of claim conditions
|
||||
* @twfeature ERC721ClaimableWithConditions | ERC1155ClaimableWithConditions | ERC20ClaimableWithConditions
|
||||
@@ -242,6 +319,136 @@ export function useClaimIneligibilityReasons(
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use this to check the claim condition for a given wallet address (including checking for overrides that may exist for that given wallet address).
|
||||
*
|
||||
* @param contract - an instance of a contract that extends the ERC20, ERC721 or ERC1155 spec and implements the `claimConditions` extension.
|
||||
* @param walletAddress - the wallet address to check the active claim condition for
|
||||
* @param tokenId - the id of the token to fetch the claim conditions for (if the contract is an ERC1155 contract)
|
||||
* @returns the active claim conditon for the wallet address or null if there is no active claim condition
|
||||
*
|
||||
* @beta
|
||||
*/
|
||||
export function useActiveClaimConditionForWallet(
|
||||
contract: RequiredParam<DropContract>,
|
||||
walletAddress: RequiredParam<WalletAddress>,
|
||||
tokenId?: BigNumberish,
|
||||
) {
|
||||
const sdk = useSDK();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const { erc1155, erc721, erc20 } = getErcs(contract);
|
||||
return useQueryWithNetwork<ClaimCondition | null>(
|
||||
cacheKeys.extensions.claimConditions.useActiveClaimConditionForWallet(
|
||||
contractAddress,
|
||||
walletAddress || "_NO_WALLET_",
|
||||
tokenId,
|
||||
),
|
||||
async () => {
|
||||
// if we do not have a walletAddress just do the same logic as basic useClaimCondition
|
||||
if (!walletAddress) {
|
||||
if (erc1155) {
|
||||
requiredParamInvariant(
|
||||
tokenId,
|
||||
"tokenId is required for ERC1155 claim conditions",
|
||||
);
|
||||
return erc1155.claimConditions.getActive(tokenId);
|
||||
}
|
||||
if (erc721) {
|
||||
return erc721.claimConditions.getActive();
|
||||
}
|
||||
if (erc20) {
|
||||
return erc20.claimConditions.getActive();
|
||||
}
|
||||
throw new Error("Contract must be ERC721, ERC1155 or ERC20");
|
||||
}
|
||||
invariant(sdk, "sdk is required");
|
||||
let activeGeneralClaimCondition: ClaimCondition | null = null;
|
||||
let claimerProofForWallet: SnapshotEntryWithProof | null = null;
|
||||
|
||||
if (erc1155) {
|
||||
requiredParamInvariant(tokenId, "tokenId is required for ERC1155");
|
||||
const [cc, cp] = await Promise.all([
|
||||
erc1155.claimConditions.getActive(tokenId),
|
||||
erc1155.claimConditions.getClaimerProofs(tokenId, walletAddress),
|
||||
]);
|
||||
activeGeneralClaimCondition = cc;
|
||||
claimerProofForWallet = cp;
|
||||
}
|
||||
if (erc721) {
|
||||
const [cc, cp] = await Promise.all([
|
||||
erc721.claimConditions.getActive(),
|
||||
erc721.claimConditions.getClaimerProofs(walletAddress),
|
||||
]);
|
||||
activeGeneralClaimCondition = cc;
|
||||
claimerProofForWallet = cp;
|
||||
}
|
||||
if (erc20) {
|
||||
const [cc, cp] = await Promise.all([
|
||||
erc20.claimConditions.getActive(),
|
||||
erc20.claimConditions.getClaimerProofs(walletAddress),
|
||||
]);
|
||||
activeGeneralClaimCondition = cc;
|
||||
claimerProofForWallet = cp;
|
||||
}
|
||||
// if there is no active claim condition nothing matters, return null
|
||||
if (!activeGeneralClaimCondition) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// if there is no claimer proof then just fall back to the active general claim condition
|
||||
if (!claimerProofForWallet) {
|
||||
return activeGeneralClaimCondition;
|
||||
}
|
||||
|
||||
const { maxClaimable, currencyAddress, price } = claimerProofForWallet;
|
||||
|
||||
const currencyWithOverride =
|
||||
currencyAddress || activeGeneralClaimCondition.currencyAddress;
|
||||
|
||||
const currencyMetadata = await fetchCurrencyMetadata(
|
||||
sdk.getProvider(),
|
||||
currencyWithOverride,
|
||||
);
|
||||
|
||||
const normalizedPrize = price
|
||||
? price === "unlimited"
|
||||
? constants.MaxUint256
|
||||
: utils.parseUnits(price, currencyMetadata.decimals)
|
||||
: null;
|
||||
|
||||
const priceWithOverride =
|
||||
normalizedPrize || activeGeneralClaimCondition.price;
|
||||
|
||||
const maxClaimableWithOverride =
|
||||
// have to transform this the same way that claim conditions do it in SDK
|
||||
convertToReadableQuantity(maxClaimable, currencyMetadata.decimals) ||
|
||||
activeGeneralClaimCondition.maxClaimablePerWallet;
|
||||
|
||||
const currencyValueWithOverride = await fetchCurrencyValue(
|
||||
sdk.getProvider(),
|
||||
currencyWithOverride,
|
||||
priceWithOverride,
|
||||
);
|
||||
return {
|
||||
// inherit the entire claim condition
|
||||
...activeGeneralClaimCondition,
|
||||
// overwrite all keys that could be changed based on overwrites
|
||||
maxClaimablePerWallet: maxClaimableWithOverride,
|
||||
price: priceWithOverride,
|
||||
currency: currencyWithOverride,
|
||||
currencyAddress: currencyWithOverride,
|
||||
currencyMetadata: currencyValueWithOverride,
|
||||
};
|
||||
},
|
||||
{
|
||||
// Checks that happen here:
|
||||
// 1. if the contract is based on ERC1155 contract => tokenId cannot be `undefined`
|
||||
// 2. if the contract is NOT based on ERC1155 => we have to have either an ERC721 or ERC20 contract
|
||||
enabled: erc1155 ? tokenId !== undefined : !!erc721 || !!erc20,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** **********************/
|
||||
/** WRITE HOOKS **/
|
||||
/** **********************/
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
ContractEvent,
|
||||
ContractForPrebuiltContractType,
|
||||
ContractType,
|
||||
EventQueryFilter,
|
||||
EventQueryOptions,
|
||||
PrebuiltContractType,
|
||||
SUPPORTED_CHAIN_ID,
|
||||
ThirdwebSDK,
|
||||
@@ -238,7 +238,7 @@ export function useContract(
|
||||
await queryClient.fetchQuery(
|
||||
compilerMetadata.cacheKey(contractAddress, activeChainId),
|
||||
() => compilerMetadata.fetchQuery(contractAddress, sdk),
|
||||
{ cacheTime: Infinity, staleTime: Infinity },
|
||||
{ cacheTime: Infinity, staleTime: Infinity, retry: 0 },
|
||||
)
|
||||
)?.abi;
|
||||
}
|
||||
@@ -258,6 +258,8 @@ export function useContract(
|
||||
cacheTime: Infinity,
|
||||
staleTime: Infinity,
|
||||
enabled: !!contractAddress && !!sdk && !!activeChainId,
|
||||
// never retry
|
||||
retry: 0,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -346,7 +348,7 @@ export function useContractMetadataUpdate(
|
||||
export function useContractEvents(
|
||||
contract: RequiredParam<ValidContractInstance>,
|
||||
eventName?: string,
|
||||
options: { queryFilter?: EventQueryFilter; subscribe?: boolean } = {
|
||||
options: { queryFilter?: EventQueryOptions; subscribe?: boolean } = {
|
||||
subscribe: true,
|
||||
},
|
||||
) {
|
||||
|
||||
@@ -106,7 +106,7 @@ export function useUnclaimedNFTSupply(contract: RequiredParam<DropContract>) {
|
||||
invariant(erc721, "No ERC721 Contract instance provided");
|
||||
return erc721.totalUnclaimedSupply();
|
||||
}
|
||||
invariant(false, "Contract is not an instance of ERC721")
|
||||
invariant(false, "Contract is not an instance of ERC721");
|
||||
},
|
||||
{ enabled: !!erc721 },
|
||||
);
|
||||
@@ -129,7 +129,7 @@ export function useClaimedNFTSupply(contract: RequiredParam<DropContract>) {
|
||||
if (erc721) {
|
||||
return erc721.totalClaimedSupply();
|
||||
}
|
||||
invariant(false, "Contract is not an instance of ERC721")
|
||||
invariant(false, "Contract is not an instance of ERC721");
|
||||
},
|
||||
{ enabled: !!erc721 },
|
||||
);
|
||||
|
||||
@@ -24,7 +24,9 @@ export function useUser() {
|
||||
authConfig,
|
||||
"Please specify an authConfig in the ThirdwebProvider",
|
||||
);
|
||||
const res = await fetch(`${authConfig.authUrl}/user`);
|
||||
const res = await fetch(`${authConfig.authUrl}/user`, {
|
||||
credentials: "include",
|
||||
});
|
||||
return (await res.json()) as ThirdwebAuthUser;
|
||||
},
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useContract } from "../async/contracts";
|
||||
* import { useContract } from '@thirdweb-dev/react'
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { contract } = useNFTCollection("<YOUR-CONTRACT-ADDRESS>", "nft-collection")
|
||||
* const { contract, isLoading, error } = useContract("<YOUR-CONTRACT-ADDRESS>", "nft-collection")
|
||||
*
|
||||
* // Now you can use the nftCollection contract in the rest of the component
|
||||
*
|
||||
|
||||
@@ -287,6 +287,16 @@ export const cacheKeys = {
|
||||
? ["claimConditions", "getAll", { tokenId }, options]
|
||||
: ["claimConditions", "getAll", options],
|
||||
),
|
||||
getClaimerProofs: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
tokenId?: BigNumberish,
|
||||
) =>
|
||||
createContractCacheKey(
|
||||
contractAddress,
|
||||
tokenId
|
||||
? ["claimConditions", "getClaimerProofs", { tokenId }]
|
||||
: ["claimConditions", "getClaimerProofs"],
|
||||
),
|
||||
getClaimIneligibilityReasons: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
params: { walletAddress?: WalletAddress; quantity: string | number },
|
||||
@@ -303,6 +313,23 @@ export const cacheKeys = {
|
||||
]
|
||||
: ["claimConditions", "getIneligibilityReasons", params],
|
||||
),
|
||||
// combinations of queries cache keys
|
||||
useActiveClaimConditionForWallet: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
walletAddress: WalletAddress,
|
||||
tokenId?: BigNumberish,
|
||||
) =>
|
||||
createContractCacheKey(
|
||||
contractAddress,
|
||||
tokenId
|
||||
? [
|
||||
"claimConditions",
|
||||
"useActiveClaimConditionForWallet",
|
||||
{ tokenId, walletAddress },
|
||||
,
|
||||
]
|
||||
: ["claimConditions", "getIneligibilityReasons", { walletAddress }],
|
||||
),
|
||||
},
|
||||
|
||||
// primary sale contracts
|
||||
|
||||
@@ -24,7 +24,9 @@ export function useUser() {
|
||||
authConfig,
|
||||
"Please specify an authConfig in the ThirdwebProvider",
|
||||
);
|
||||
const res = await fetch(`${authConfig.authUrl}/user`);
|
||||
const res = await fetch(`${authConfig.authUrl}/user`, {
|
||||
credentials: "include",
|
||||
});
|
||||
return (await res.json()) as ThirdwebAuthUser;
|
||||
},
|
||||
{
|
||||
|
||||
@@ -4,17 +4,22 @@ import {
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { QueryAllParams } from "@thirdweb-dev/sdk";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function nftGetAllQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
queryParams?: QueryAllParams,
|
||||
) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, ["getAll"] as const),
|
||||
queryKey: createSOLProgramQueryKey(program, [
|
||||
"getAll",
|
||||
queryParams,
|
||||
] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.getAll();
|
||||
return program.getAll(queryParams);
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
@@ -40,6 +45,9 @@ export function nftGetAllQuery(
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useNFTs(program: RequiredParam<NFTCollection | NFTDrop>) {
|
||||
return useQuery(nftGetAllQuery(program));
|
||||
export function useNFTs(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
queryParams?: QueryAllParams,
|
||||
) {
|
||||
return useQuery(nftGetAllQuery(program, queryParams));
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ export function nftRoyaltyQuery(
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useRoyaltySettings(program: RequiredParam<NFTCollection | NFTDrop>) {
|
||||
export function useRoyaltySettings(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
return useQuery(nftRoyaltyQuery(program));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { createSOLProgramQueryKey } from "../../../core/query-utils/query-key";
|
||||
import {
|
||||
requiredParamInvariant,
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export function nftTotalSupplyQuery(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
return {
|
||||
queryKey: createSOLProgramQueryKey(program, ["supply"] as const),
|
||||
|
||||
queryFn: async () => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return program.totalSupply();
|
||||
},
|
||||
enabled: !!program,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the totaly supply of NFTs on the program
|
||||
* @param program - The NFT program to get the total supply of
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { useProgram, useTotalSupply } from "@thirdweb-dev/react/solana";
|
||||
*
|
||||
* export default function Component() {
|
||||
* const { program } = useProgram("{{program_address}}");
|
||||
* const { data: supply, isLoading } = useTotalSupply(program);
|
||||
*
|
||||
* return (
|
||||
* <pre>{JSON.stringify(supply)}</pre>
|
||||
* )
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @public
|
||||
*/
|
||||
export function useTotalSupply(
|
||||
program: RequiredParam<NFTCollection | NFTDrop>,
|
||||
) {
|
||||
return useQuery(nftTotalSupplyQuery(program));
|
||||
}
|
||||
@@ -4,7 +4,11 @@ import {
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { CreatorInput, NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import type {
|
||||
NFTCollection,
|
||||
NFTDrop,
|
||||
UpdateCreatorInput,
|
||||
} from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
/**
|
||||
* Update the creators for an NFT program
|
||||
@@ -35,9 +39,9 @@ export function useUpdateCreators(
|
||||
) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (creators: CreatorInput[]) => {
|
||||
async ({ creators, updateAll }: UpdateCreatorInput) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.updateCreators(creators);
|
||||
return await program.updateCreators(creators, updateAll);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
|
||||
@@ -4,7 +4,11 @@ import {
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { NFTCollection, NFTDrop } from "@thirdweb-dev/sdk/solana";
|
||||
import type {
|
||||
NFTCollection,
|
||||
NFTDrop,
|
||||
UpdateRoyaltySettingsInput,
|
||||
} from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
/**
|
||||
* Update the royalty for an NFT program
|
||||
@@ -35,9 +39,9 @@ export function useUpdateRoyaltySettings(
|
||||
) {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation(
|
||||
async (sellerFeeBasisPoints: number) => {
|
||||
async ({ sellerFeeBasisPoints, updateAll }: UpdateRoyaltySettingsInput) => {
|
||||
requiredParamInvariant(program, "program is required");
|
||||
return await program.updateRoyalty(sellerFeeBasisPoints);
|
||||
return await program.updateRoyalty(sellerFeeBasisPoints, updateAll);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
|
||||
@@ -4,7 +4,8 @@ import {
|
||||
RequiredParam,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import type { Amount, Token } from "@thirdweb-dev/sdk/solana";
|
||||
import type { Amount } from "@thirdweb-dev/sdk";
|
||||
import type { Token } from "@thirdweb-dev/sdk/solana";
|
||||
|
||||
export type TransferTokenMutationParams = {
|
||||
amount: Amount;
|
||||
|
||||
@@ -18,6 +18,7 @@ export * from "./hooks/nft/useRoyaltySettings";
|
||||
export * from "./hooks/nft/useUpdateRoyaltySettings";
|
||||
export * from "./hooks/nft/useCreators";
|
||||
export * from "./hooks/nft/useUpdateCreators";
|
||||
export * from "./hooks/nft/useTotalSupply";
|
||||
|
||||
// NFT Collection
|
||||
export * from "./hooks/nft/collection/useMintNFT";
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,5 +1,123 @@
|
||||
# @thirdweb-dev/sdk
|
||||
|
||||
## 3.6.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#451](https://github.com/thirdweb-dev/js/pull/451) [`3731459`](https://github.com/thirdweb-dev/js/commit/3731459d33f1ded7ebb69124809449b901b3ad3d) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Less strict prebuilt checks to support OSRF variants
|
||||
|
||||
- [#450](https://github.com/thirdweb-dev/js/pull/450) [`cac6c30`](https://github.com/thirdweb-dev/js/commit/cac6c30bca5e17df81d746ef81316af47d5e252e) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix setting allowance or approvals gaslessly
|
||||
|
||||
- [#448](https://github.com/thirdweb-dev/js/pull/448) [`7a37e56`](https://github.com/thirdweb-dev/js/commit/7a37e564fd5d5a9df84c8da44ecaf6c42f67a0e2) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - allow `useContract` to fail faster to enable the import case
|
||||
|
||||
## 3.6.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#443](https://github.com/thirdweb-dev/js/pull/443) [`8c6cdaa`](https://github.com/thirdweb-dev/js/commit/8c6cdaa2887fb2cc40d3ee6991233d195d103805) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix signature minting from OpenSea Royalty Filter NFT collection contracts
|
||||
|
||||
## 3.6.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#440](https://github.com/thirdweb-dev/js/pull/440) [`efc56fa`](https://github.com/thirdweb-dev/js/commit/efc56fa5802490ac8ef50037658d046afd89e9a1) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - providers are now re-used if the constructor options are identical leading to better batching, also introduced an additional max batch size param (250 by default)
|
||||
|
||||
## 3.6.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#438](https://github.com/thirdweb-dev/js/pull/438) [`f451da6`](https://github.com/thirdweb-dev/js/commit/f451da6395689a5f89800ee63f34b6175b61f703) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix SigMint detection for OSRF NFT Collection contracts
|
||||
|
||||
- [#416](https://github.com/thirdweb-dev/js/pull/416) [`af3acc6`](https://github.com/thirdweb-dev/js/commit/af3acc6b10751b840e56aef6400da5eea6040df2) Thanks [@adam-maj](https://github.com/adam-maj)! - Add support for AWS KMS
|
||||
|
||||
- [#424](https://github.com/thirdweb-dev/js/pull/424) [`1bfb91d`](https://github.com/thirdweb-dev/js/commit/1bfb91dbf3a39160c987a425813ac5dbb84703ad) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Improve error parsing for other wallets
|
||||
|
||||
- [#436](https://github.com/thirdweb-dev/js/pull/436) [`ee47840`](https://github.com/thirdweb-dev/js/commit/ee478407673b0416e0c1cfe2be11bd6963395348) Thanks [@jnsdls](https://github.com/jnsdls)! - fix #429
|
||||
|
||||
- [#434](https://github.com/thirdweb-dev/js/pull/434) [`def4251`](https://github.com/thirdweb-dev/js/commit/def42511ff5a20d83f9094164dafb87e412571b5) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SOL] Remove workaround to fetch NFT owners
|
||||
|
||||
- [#429](https://github.com/thirdweb-dev/js/pull/429) [`034a257`](https://github.com/thirdweb-dev/js/commit/034a257442314c67729f7bafcbe3740cff33fa32) Thanks [@jakeloo](https://github.com/jakeloo)! - Extract more minimal proxy impl address
|
||||
|
||||
- [#418](https://github.com/thirdweb-dev/js/pull/418) [`eca4776`](https://github.com/thirdweb-dev/js/commit/eca47763cd89cc3b7aa57b542971837987540b55) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Increase gas limit for opening packs
|
||||
|
||||
- [#420](https://github.com/thirdweb-dev/js/pull/420) [`639e535`](https://github.com/thirdweb-dev/js/commit/639e535ed55280ad9d081001aab3f5af72bb3e45) Thanks [@jnsdls](https://github.com/jnsdls)! - update deps
|
||||
|
||||
- Updated dependencies [[`f451da6`](https://github.com/thirdweb-dev/js/commit/f451da6395689a5f89800ee63f34b6175b61f703)]:
|
||||
- @thirdweb-dev/contracts-js@1.2.2
|
||||
|
||||
## 3.6.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#408](https://github.com/thirdweb-dev/js/pull/408) [`48797c7`](https://github.com/thirdweb-dev/js/commit/48797c7cf0695965e33eb6bf602be4652f7085a8) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - add `Gasless` as a possible extension to feature-detect
|
||||
|
||||
- [#402](https://github.com/thirdweb-dev/js/pull/402) [`83dcaf7`](https://github.com/thirdweb-dev/js/commit/83dcaf70584af8c5cdf0427f9fc1ba82d89f0887) Thanks [@adam-maj](https://github.com/adam-maj)! - Expose sdk.fromWallet and wallet classes
|
||||
|
||||
- [#412](https://github.com/thirdweb-dev/js/pull/412) [`f03be39`](https://github.com/thirdweb-dev/js/commit/f03be398e0d7b75c9c5b4fb643f35903e89a17e7) Thanks [@easonchai](https://github.com/easonchai)! - Correctly handle contracts using the SignatureMintERC1155 ContractKit extension
|
||||
|
||||
- [#283](https://github.com/thirdweb-dev/js/pull/283) [`2eaa67a`](https://github.com/thirdweb-dev/js/commit/2eaa67acbe21464e7715d0b696afdc024460a44d) Thanks [@adam-maj](https://github.com/adam-maj)! - AppURI detection now enabled
|
||||
|
||||
- [#414](https://github.com/thirdweb-dev/js/pull/414) [`47f8945`](https://github.com/thirdweb-dev/js/commit/47f8945325447874b1ace0359919c1d54fd55436) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Improve error parsing
|
||||
|
||||
## 3.6.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#405](https://github.com/thirdweb-dev/js/pull/405) [`ccb7db4`](https://github.com/thirdweb-dev/js/commit/ccb7db48739b8dddcb2c032b3b6e3e5200485715) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Add updateAll param to creators and royalty update hooks for Solana
|
||||
|
||||
- [#404](https://github.com/thirdweb-dev/js/pull/404) [`9151aa7`](https://github.com/thirdweb-dev/js/commit/9151aa7dc80754a7aa4fd3f6ce0207bccbb6451f) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - expose `getDefaultTrustedForwarders` helper function
|
||||
|
||||
- [#305](https://github.com/thirdweb-dev/js/pull/305) [`5a01c53`](https://github.com/thirdweb-dev/js/commit/5a01c537e30bd7ef562aad1012413990de6faedf) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Update to Metaplex 0.17
|
||||
|
||||
## 3.6.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#398](https://github.com/thirdweb-dev/js/pull/398) [`15514f1`](https://github.com/thirdweb-dev/js/commit/15514f190a844d809ae5b1edb580aab46a682485) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - add `defaultValue` to constructorParams schema for releases
|
||||
|
||||
- [#388](https://github.com/thirdweb-dev/js/pull/388) [`7c0744a`](https://github.com/thirdweb-dev/js/commit/7c0744a006e78987ad8b271b2c64f4bac7759510) Thanks [@adam-maj](https://github.com/adam-maj)! - Add support for total supply and pagination on get all
|
||||
|
||||
- [#395](https://github.com/thirdweb-dev/js/pull/395) [`f8bceec`](https://github.com/thirdweb-dev/js/commit/f8bceec10c60b30dc3d6f45926e2a9e018202578) Thanks [@jnsdls](https://github.com/jnsdls)! - [Solana] - fix claim condition reset to native token from custom
|
||||
|
||||
- [#399](https://github.com/thirdweb-dev/js/pull/399) [`887af24`](https://github.com/thirdweb-dev/js/commit/887af24450e316c2ea390cd49c0563cebe793c0f) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - fix custom error handling for null-ish error values
|
||||
|
||||
- [#390](https://github.com/thirdweb-dev/js/pull/390) [`96bd92e`](https://github.com/thirdweb-dev/js/commit/96bd92e724ec7d880d23348071b26ab8c21dd868) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SDK] Expose `getAllDetectedFeatures(ABI)` helper function
|
||||
|
||||
## 3.6.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#364](https://github.com/thirdweb-dev/js/pull/364) [`7cb8e59`](https://github.com/thirdweb-dev/js/commit/7cb8e59be48dc923316eb36ab43a1bef7364f6b1) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Enable new Drop contracts
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#382](https://github.com/thirdweb-dev/js/pull/382) [`0ed77d2`](https://github.com/thirdweb-dev/js/commit/0ed77d2c9e7526444ef660aab82a950865234aa6) Thanks [@jnsdls](https://github.com/jnsdls)! - Add `constructorParams` to `ExtraPublishMetadataSchemaInput` schema to support better deploys from releases.
|
||||
|
||||
- [#385](https://github.com/thirdweb-dev/js/pull/385) [`04a47e8`](https://github.com/thirdweb-dev/js/commit/04a47e8971d28da2532ebd9db824eeb459c17bd4) Thanks [@adam-maj](https://github.com/adam-maj)! - Add retroactive royalty and creator setting
|
||||
|
||||
## 3.5.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#380](https://github.com/thirdweb-dev/js/pull/380) [`3eba69a`](https://github.com/thirdweb-dev/js/commit/3eba69afd78b7aa472a9c00c9d4220bb69ad1d3e) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose sdk.wallet.getChainId()
|
||||
|
||||
- [#376](https://github.com/thirdweb-dev/js/pull/376) [`4af785c`](https://github.com/thirdweb-dev/js/commit/4af785c37c831ecd7087c1c9eb9095922cac0855) Thanks [@adam-maj](https://github.com/adam-maj)! - Update tiered-drop with tokens claimed
|
||||
|
||||
- [#373](https://github.com/thirdweb-dev/js/pull/373) [`6f818f3`](https://github.com/thirdweb-dev/js/commit/6f818f393eb9023b53a3358d62d60ec23a9246bd) Thanks [@adam-maj](https://github.com/adam-maj)! - Update tiered-drop contract version
|
||||
|
||||
- [#377](https://github.com/thirdweb-dev/js/pull/377) [`b79dc18`](https://github.com/thirdweb-dev/js/commit/b79dc18f7ab5155bbf4af02dc1a953546160bad0) Thanks [@adam-maj](https://github.com/adam-maj)! - Add event filters
|
||||
|
||||
- Updated dependencies [[`4af785c`](https://github.com/thirdweb-dev/js/commit/4af785c37c831ecd7087c1c9eb9095922cac0855), [`6f818f3`](https://github.com/thirdweb-dev/js/commit/6f818f393eb9023b53a3358d62d60ec23a9246bd)]:
|
||||
- @thirdweb-dev/contracts-js@1.2.1
|
||||
|
||||
## 3.5.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#368](https://github.com/thirdweb-dev/js/pull/368) [`4e7b293`](https://github.com/thirdweb-dev/js/commit/4e7b293c543244de79c150ca8c37d941221fc9a3) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix handling of old allowlist proof format
|
||||
|
||||
- [#365](https://github.com/thirdweb-dev/js/pull/365) [`c9c0e4f`](https://github.com/thirdweb-dev/js/commit/c9c0e4ff39b054af746f3aec75fcbd0a3ef7239d) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - now React Native compatible
|
||||
|
||||
## 3.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-sdk-evm-wallets.cjs.js",
|
||||
"module": "dist/thirdweb-dev-sdk-evm-wallets.esm.js"
|
||||
}
|
||||
+33
-16
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/sdk",
|
||||
"version": "3.5.0",
|
||||
"version": "3.6.7",
|
||||
"description": "The main thirdweb SDK.",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
|
||||
"license": "Apache-2.0",
|
||||
@@ -19,6 +19,10 @@
|
||||
"module": "./solana/dist/thirdweb-dev-sdk-solana.esm.js",
|
||||
"default": "./solana/dist/thirdweb-dev-sdk-solana.cjs.js"
|
||||
},
|
||||
"./evm/wallets": {
|
||||
"module": "./evm/wallets/dist/thirdweb-dev-sdk-evm-wallets.esm.js",
|
||||
"default": "./evm/wallets/dist/thirdweb-dev-sdk-evm-wallets.cjs.js"
|
||||
},
|
||||
"./solana/server": {
|
||||
"module": "./solana/server/dist/thirdweb-dev-sdk-solana-server.esm.js",
|
||||
"default": "./solana/server/dist/thirdweb-dev-sdk-solana-server.cjs.js"
|
||||
@@ -28,6 +32,7 @@
|
||||
"files": [
|
||||
"dist/",
|
||||
"evm/",
|
||||
"wallets/",
|
||||
"solana/",
|
||||
"server/"
|
||||
],
|
||||
@@ -35,6 +40,7 @@
|
||||
"entrypoints": [
|
||||
"index.ts",
|
||||
"evm/index.ts",
|
||||
"evm/wallets/index.ts",
|
||||
"solana/index.ts",
|
||||
"solana/server/index.ts"
|
||||
],
|
||||
@@ -57,7 +63,7 @@
|
||||
"test:evm:all": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/evm/.mocharc.json' --timeout 30000 --parallel './test/evm/**/*.test.ts'",
|
||||
"test:evm": "make test-evm",
|
||||
"test:evm:single": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/evm/.mocharc.json' --timeout 30000",
|
||||
"node:solana:start": "DEBUG='amman:(info|error|debug)' amman start",
|
||||
"node:solana:start": "DEBUG='amman:(info|error|debug)' amman start --forceClone",
|
||||
"node:solana:stop": "amman stop",
|
||||
"test:solana:all": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/solana/.mocharc.json' --timeout 30000 --parallel './test/solana/**/*.test.ts'",
|
||||
"test:solana": "make test-sol",
|
||||
@@ -65,18 +71,19 @@
|
||||
"push": "yalc push"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@metaplex-foundation/amman": "0.10.0",
|
||||
"@metaplex-foundation/amman-client": "0.2.1",
|
||||
"@aws-sdk/client-secrets-manager": "^3.216.0",
|
||||
"@metaplex-foundation/amman": "^0.12.0",
|
||||
"@metaplex-foundation/amman-client": "^0.2.1",
|
||||
"@microsoft/api-documenter": "^7.19.4",
|
||||
"@microsoft/api-extractor": "^7.29.2",
|
||||
"@microsoft/tsdoc": "^0.14.1",
|
||||
"@nomiclabs/hardhat-ethers": "2.0.5",
|
||||
"@nomiclabs/hardhat-ethers": "^2.0.5",
|
||||
"@preconstruct/cli": "^2.2.1",
|
||||
"@swc-node/register": "^1.5.1",
|
||||
"@swc/core": "^1.2.177",
|
||||
"@types/chai": "^4.3.3",
|
||||
"@types/deep-equal-in-any-order": "^1.0.1",
|
||||
"@types/mocha": "^9.1.1",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/uuid": "^8.3.3",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
||||
@@ -89,28 +96,38 @@
|
||||
"eslint-plugin-inclusive-language": "^2.2.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-tsdoc": "^0.2.16",
|
||||
"ethers": "^5.7.0",
|
||||
"ethers": "^5.7.2",
|
||||
"ethers-aws-kms-signer": "^1.3.2",
|
||||
"hardhat": "^2.9.3",
|
||||
"mocha": "^10.0.0",
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"ethers": "^5"
|
||||
"@aws-sdk/client-secrets-manager": "^3.215.0",
|
||||
"ethers": "^5",
|
||||
"ethers-aws-kms-signer": "^1.3.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@aws-sdk/client-secrets-manager": {
|
||||
"optional": true
|
||||
},
|
||||
"ethers-aws-kms-signer": {
|
||||
"optional": true
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@metaplex-foundation/js": "0.15.0",
|
||||
"@metaplex-foundation/mpl-token-metadata": "2.2.2",
|
||||
"@project-serum/anchor": "0.25.0",
|
||||
"@solana/spl-token": "0.2.0",
|
||||
"@solana/web3.js": "1.62.0",
|
||||
"@metaplex-foundation/js": "^0.17.6",
|
||||
"@metaplex-foundation/mpl-token-metadata": "^2.3.3",
|
||||
"@project-serum/anchor": "^0.25.0",
|
||||
"@solana/spl-token": "^0.3.5",
|
||||
"@solana/web3.js": "^1.62.0",
|
||||
"@thirdweb-dev/contracts-js": "*",
|
||||
"@thirdweb-dev/storage": "*",
|
||||
"bn.js": "^5.2.1",
|
||||
"bs58": "^5.0.0",
|
||||
"cbor-x": "^1.4.1",
|
||||
"cross-fetch": "^3.1.5",
|
||||
"eventemitter3": "^4.0.7",
|
||||
"eventemitter3": "^5.0.0",
|
||||
"fast-deep-equal": "^3.1.3",
|
||||
"merkletreejs": "^0.2.24",
|
||||
"tiny-invariant": "^1.2.0",
|
||||
@@ -129,4 +146,4 @@
|
||||
"url": "https://github.com/thirdweb-dev/js/issues"
|
||||
},
|
||||
"author": "thirdweb eng <[email protected]>"
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,25 @@
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const DEFAULT_QUERY_ALL_COUNT = 100;
|
||||
|
||||
export const QueryAllParamsSchema = z
|
||||
.object({
|
||||
start: z.number().default(0),
|
||||
count: z.number().default(DEFAULT_QUERY_ALL_COUNT),
|
||||
})
|
||||
.default({
|
||||
start: 0,
|
||||
count: DEFAULT_QUERY_ALL_COUNT,
|
||||
});
|
||||
|
||||
/**
|
||||
* Pagination Parameters
|
||||
* @public
|
||||
*/
|
||||
export interface QueryAllParams {
|
||||
/**
|
||||
* the index to start from (default: 0)
|
||||
*/
|
||||
start?: number;
|
||||
/**
|
||||
* how many items to return (default: 100)
|
||||
*/
|
||||
count?: number;
|
||||
}
|
||||
export type QueryAllParams = Exclude<
|
||||
z.input<typeof QueryAllParamsSchema>,
|
||||
undefined
|
||||
>;
|
||||
|
||||
@@ -2,8 +2,14 @@ import BN from "bn.js";
|
||||
import { BigNumber } from "ethers";
|
||||
import { z } from "zod";
|
||||
|
||||
const isBrowser = () => typeof window !== "undefined";
|
||||
const FileOrBufferUnionSchema = isBrowser()
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const isBrowser = () => typeof window !== "undefined";
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const FileOrBufferUnionSchema = isBrowser()
|
||||
? (z.instanceof(File) as z.ZodType<InstanceType<typeof File>>)
|
||||
: (z.instanceof(Buffer) as z.ZodTypeAny); // @fixme, this is a hack to make browser happy for now
|
||||
|
||||
@@ -96,6 +102,11 @@ export const AmountSchema = z
|
||||
])
|
||||
.transform((arg) => (typeof arg === "number" ? arg.toString() : arg));
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export type Amount = z.input<typeof AmountSchema>;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
|
||||
@@ -31,8 +31,8 @@ import {
|
||||
SnapshotFormatVersion,
|
||||
} from "./sharded-merkle-tree";
|
||||
import { createSnapshot } from "./snapshots";
|
||||
import { IClaimCondition } from "@thirdweb-dev/contracts-js/dist/declarations/src/Drop";
|
||||
import { IDropClaimCondition_V2 } from "@thirdweb-dev/contracts-js/dist/declarations/src/IDropERC20_V2";
|
||||
import { IClaimCondition } from "@thirdweb-dev/contracts-js/src/IDrop";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import {
|
||||
BigNumber,
|
||||
@@ -50,6 +50,7 @@ import {
|
||||
* @returns - `overrides` and `proofs` as an object.
|
||||
*/
|
||||
export async function prepareClaim(
|
||||
addressToClaim: string,
|
||||
quantity: BigNumberish,
|
||||
activeClaimCondition: ClaimCondition,
|
||||
merkleMetadataFetcher: () => Promise<Record<string, string>>,
|
||||
@@ -59,7 +60,6 @@ export async function prepareClaim(
|
||||
checkERC20Allowance: boolean,
|
||||
snapshotFormatVersion: SnapshotFormatVersion,
|
||||
): Promise<ClaimVerification> {
|
||||
const addressToClaim = await contractWrapper.getSignerAddress();
|
||||
let maxClaimable = convertQuantityToBigNumber(
|
||||
activeClaimCondition.maxClaimablePerWallet,
|
||||
tokenDecimals,
|
||||
@@ -92,14 +92,16 @@ export async function prepareClaim(
|
||||
tokenDecimals,
|
||||
);
|
||||
priceInProof =
|
||||
snapshotEntry.price === undefined ||
|
||||
snapshotEntry.price === "unlimited"
|
||||
? ethers.constants.MaxUint256
|
||||
: await normalizePriceValue(
|
||||
contractWrapper.getProvider(),
|
||||
snapshotEntry.price,
|
||||
snapshotEntry.currencyAddress,
|
||||
snapshotEntry.currencyAddress || ethers.constants.AddressZero,
|
||||
);
|
||||
currencyAddressInProof = snapshotEntry.currencyAddress;
|
||||
currencyAddressInProof =
|
||||
snapshotEntry.currencyAddress || ethers.constants.AddressZero;
|
||||
} else {
|
||||
// if no snapshot entry, and it's a v1 format (exclusive allowlist) then address can't claim
|
||||
if (snapshotFormatVersion === SnapshotFormatVersion.V1) {
|
||||
@@ -152,8 +154,10 @@ export async function prepareClaim(
|
||||
overrides,
|
||||
proofs,
|
||||
maxClaimable,
|
||||
price: priceInProof,
|
||||
currencyAddress: currencyAddressInProof,
|
||||
price: pricePerToken,
|
||||
currencyAddress: currencyAddress,
|
||||
priceInProof,
|
||||
currencyAddressInProof,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -282,62 +286,6 @@ export async function updateExistingClaimConditions(
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the proof for the current signer for a particular wallet.
|
||||
*
|
||||
* @param addressToClaim
|
||||
* @param merkleRoot - The merkle root of the condition to check.
|
||||
* @param tokenDecimals
|
||||
* @param merkleMetadata
|
||||
* @param storage
|
||||
* @param provider
|
||||
* @param snapshotFormatVersion
|
||||
* @returns - The proof for the current signer for the specified condition.
|
||||
*/
|
||||
export async function getClaimerProofs(
|
||||
addressToClaim: string,
|
||||
merkleRoot: string,
|
||||
tokenDecimals: number,
|
||||
merkleMetadata: Record<string, string>,
|
||||
storage: ThirdwebStorage,
|
||||
provider: ethers.providers.Provider,
|
||||
snapshotFormatVersion: SnapshotFormatVersion,
|
||||
): Promise<
|
||||
| {
|
||||
proof: string[];
|
||||
maxClaimable: BigNumber;
|
||||
price: BigNumber;
|
||||
currencyAddress: string;
|
||||
}
|
||||
| undefined
|
||||
> {
|
||||
const claim = await fetchSnapshotEntryForAddress(
|
||||
addressToClaim,
|
||||
merkleRoot,
|
||||
merkleMetadata,
|
||||
provider,
|
||||
storage,
|
||||
snapshotFormatVersion,
|
||||
);
|
||||
if (!claim) {
|
||||
return undefined;
|
||||
}
|
||||
const price =
|
||||
claim.price === "unlimited"
|
||||
? ethers.constants.MaxUint256
|
||||
: await normalizePriceValue(provider, claim.price, claim.currencyAddress);
|
||||
const maxClaimable =
|
||||
claim.maxClaimable === "unlimited"
|
||||
? ethers.constants.MaxUint256
|
||||
: ethers.utils.parseUnits(claim.maxClaimable, tokenDecimals);
|
||||
return {
|
||||
proof: claim.proof,
|
||||
maxClaimable,
|
||||
price,
|
||||
currencyAddress: claim.currencyAddress,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Decorates claim conditions with merkle roots from snapshots if present
|
||||
@@ -572,6 +520,10 @@ export async function transformResultToClaimCondition(
|
||||
pm.supplyClaimed,
|
||||
tokenDecimals,
|
||||
);
|
||||
let resolvedMetadata;
|
||||
if (pm.metadata) {
|
||||
resolvedMetadata = await storage.downloadJSON(pm.metadata);
|
||||
}
|
||||
return ClaimConditionOutputSchema.parse({
|
||||
startTime: pm.startTimestamp,
|
||||
maxClaimableSupply,
|
||||
@@ -587,7 +539,7 @@ export async function transformResultToClaimCondition(
|
||||
snapshot: shouldDownloadSnapshot
|
||||
? await fetchSnapshot(pm.merkleRoot, merkleMetadata, storage)
|
||||
: undefined,
|
||||
metadata: pm.metadata,
|
||||
metadata: resolvedMetadata,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { AmountSchema } from "../../core/schema/shared";
|
||||
import {
|
||||
getNativeTokenByChainId,
|
||||
NATIVE_TOKEN_ADDRESS,
|
||||
} from "../constants/currency";
|
||||
import { ContractWrapper } from "../core/classes/contract-wrapper";
|
||||
import { AmountSchema } from "../schema/shared";
|
||||
import { Amount, Currency, CurrencyValue, Price } from "../types/currency";
|
||||
import { BaseERC20 } from "../types/eips";
|
||||
import type { IERC20, IERC20Metadata } from "@thirdweb-dev/contracts-js";
|
||||
@@ -33,6 +33,14 @@ export function cleanCurrencyAddress(currencyAddress: string): string {
|
||||
return currencyAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param provider
|
||||
* @param inputPrice
|
||||
* @param currencyAddress
|
||||
* @returns
|
||||
* @internal
|
||||
*/
|
||||
export async function normalizePriceValue(
|
||||
provider: providers.Provider,
|
||||
inputPrice: Price,
|
||||
@@ -42,6 +50,13 @@ export async function normalizePriceValue(
|
||||
return utils.parseUnits(AmountSchema.parse(inputPrice), metadata.decimals);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param provider
|
||||
* @param asset
|
||||
* @returns
|
||||
* @internal
|
||||
*/
|
||||
export async function fetchCurrencyMetadata(
|
||||
provider: providers.Provider,
|
||||
asset: string,
|
||||
@@ -73,6 +88,14 @@ export async function fetchCurrencyMetadata(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param providerOrSigner
|
||||
* @param asset
|
||||
* @param price
|
||||
* @returns
|
||||
* @internal
|
||||
*/
|
||||
export async function fetchCurrencyValue(
|
||||
providerOrSigner: providers.Provider,
|
||||
asset: string,
|
||||
@@ -101,7 +124,7 @@ export async function setErc20Allowance(
|
||||
signer || provider,
|
||||
currencyAddress,
|
||||
ERC20Abi,
|
||||
{},
|
||||
contractToApprove.options,
|
||||
);
|
||||
|
||||
const owner = await contractToApprove.getSignerAddress();
|
||||
@@ -128,7 +151,7 @@ export async function approveErc20Allowance(
|
||||
signer || provider,
|
||||
currencyAddress,
|
||||
ERC20Abi,
|
||||
{},
|
||||
contractToApprove.options,
|
||||
);
|
||||
const owner = await contractToApprove.getSignerAddress();
|
||||
const spender = contractToApprove.readContract.address;
|
||||
|
||||
@@ -394,20 +394,16 @@ export async function convertToTWError(
|
||||
contractInterface: ethers.utils.Interface,
|
||||
): Promise<TransactionError> {
|
||||
let raw: string;
|
||||
if (error.data) {
|
||||
if (typeof error === "object") {
|
||||
// metamask errors comes as objects, apply parsing on data object
|
||||
// TODO test errors from other wallets
|
||||
raw = JSON.stringify(error.data);
|
||||
} else if (error instanceof Error) {
|
||||
// regular ethers.js error
|
||||
raw = error.message;
|
||||
raw = JSON.stringify(error);
|
||||
} else {
|
||||
// not sure what this is, just throw it back
|
||||
raw = error.toString();
|
||||
}
|
||||
const reason =
|
||||
error.reason ||
|
||||
parseMessageParts(/.*?"message[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
|
||||
parseMessageParts(/.*?"message[^a-zA-Z0-9]*([^"\\]*).*?/, raw) ||
|
||||
parseMessageParts(/.*?"reason[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
|
||||
const data = parseMessageParts(/.*?"data[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
|
||||
const rpcUrl = parseMessageParts(/.*?"url[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
|
||||
let from = parseMessageParts(/.*?"from[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
|
||||
@@ -459,9 +455,12 @@ function parseMessageParts(regex: RegExp, raw: string): string {
|
||||
* @param message
|
||||
*/
|
||||
export function includesErrorMessage(err: any, message: string): boolean {
|
||||
if (!err) {
|
||||
return false;
|
||||
}
|
||||
return (
|
||||
(err && err.toString().includes(message)) ||
|
||||
(err.message && err.message.toString().includes(message)) ||
|
||||
(err.error && err.error.toString().includes(message))
|
||||
(err && err.message && err.message.toString().includes(message)) ||
|
||||
(err && err.error && err.error.toString().includes(message))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ import {
|
||||
} from "../constants/contract-features";
|
||||
import { ContractWrapper } from "../core/classes/contract-wrapper";
|
||||
import { DetectableFeature } from "../core/interfaces/DetectableFeature";
|
||||
import { decode } from "../lib/cbor-decode.js";
|
||||
import {
|
||||
Abi,
|
||||
AbiEvent,
|
||||
AbiFunction,
|
||||
AbiSchema,
|
||||
@@ -23,7 +25,6 @@ import {
|
||||
import { ExtensionNotImplementedError } from "./error";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import bs58 from "bs58";
|
||||
import { decode } from "cbor-x";
|
||||
import { BaseContract, BigNumber, ethers } from "ethers";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -32,26 +33,57 @@ import { z } from "zod";
|
||||
* @param abi
|
||||
* @param feature
|
||||
*/
|
||||
function matchesAbiInterface(
|
||||
abi: z.input<typeof AbiSchema>,
|
||||
feature: Feature,
|
||||
): boolean {
|
||||
function matchesAbiInterface(abi: Abi, feature: Feature): boolean {
|
||||
// returns true if all the functions in `interfaceToMatch` are found in `contract` (removing any duplicates)
|
||||
const contractFn = [
|
||||
...new Set(extractFunctionsFromAbi(abi).map((f) => f.name)),
|
||||
];
|
||||
const interfaceFn = [
|
||||
...new Set(
|
||||
feature.abis
|
||||
.flatMap((i: any) => extractFunctionsFromAbi(i))
|
||||
.map((f: AbiFunction) => f.name),
|
||||
),
|
||||
];
|
||||
return hasMatchingAbi(abi, feature.abis);
|
||||
}
|
||||
|
||||
return (
|
||||
contractFn.filter((k) => interfaceFn.includes(k)).length ===
|
||||
interfaceFn.length
|
||||
/**
|
||||
* @internal
|
||||
* @param contractWrapper
|
||||
* @param abi
|
||||
* @returns
|
||||
*/
|
||||
export function matchesPrebuiltAbi<T extends BaseContract>(
|
||||
contractWrapper: ContractWrapper<BaseContract>,
|
||||
abi: Abi,
|
||||
): contractWrapper is ContractWrapper<T> {
|
||||
return hasMatchingAbi(contractWrapper.abi as Abi, [abi]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param contractAbi
|
||||
* @param featureAbis
|
||||
* @returns
|
||||
*/
|
||||
export function hasMatchingAbi(contractAbi: Abi, featureAbis: readonly Abi[]) {
|
||||
const contractFn = extractFunctionsFromAbi(contractAbi);
|
||||
const interfaceFn = featureAbis.flatMap((i: any) =>
|
||||
extractFunctionsFromAbi(i),
|
||||
);
|
||||
// match every function and their arguments
|
||||
const intersection = contractFn.filter((fn) => {
|
||||
const match = interfaceFn.find(
|
||||
(iFn) =>
|
||||
iFn.name === fn.name &&
|
||||
iFn.inputs.length === fn.inputs.length &&
|
||||
iFn.inputs.every((i, index) => {
|
||||
if (i.type === "tuple" || i.type === "tuple[]") {
|
||||
// check that all properties in the tuple are the same type
|
||||
return (
|
||||
i.type === fn.inputs[index].type &&
|
||||
i.components?.every((c, cIndex) => {
|
||||
return c.type === fn.inputs[index].components?.[cIndex]?.type;
|
||||
})
|
||||
);
|
||||
}
|
||||
return i.type === fn.inputs[index].type;
|
||||
}),
|
||||
);
|
||||
return match !== undefined;
|
||||
});
|
||||
return intersection.length === interfaceFn.length;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,7 +177,7 @@ export function extractFunctionParamsFromAbi(
|
||||
* @param metadata
|
||||
*/
|
||||
export function extractFunctionsFromAbi(
|
||||
abi: z.input<typeof AbiSchema>,
|
||||
abi: Abi,
|
||||
metadata?: Record<string, any>,
|
||||
): AbiFunction[] {
|
||||
const functions = (abi || []).filter((el) => el.type === "function");
|
||||
@@ -178,7 +210,7 @@ export function extractFunctionsFromAbi(
|
||||
* @param metadata
|
||||
*/
|
||||
export function extractEventsFromAbi(
|
||||
abi: z.input<typeof AbiSchema>,
|
||||
abi: Abi,
|
||||
metadata?: Record<string, any>,
|
||||
): AbiEvent[] {
|
||||
const events = (abi || []).filter((el) => el.type === "event");
|
||||
@@ -234,6 +266,42 @@ function toJSType(
|
||||
return jsType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param bytecode
|
||||
*/
|
||||
export function extractMinimalProxyImplementationAddress(
|
||||
bytecode: string,
|
||||
): string | undefined {
|
||||
// EIP-1167 clone minimal proxy - https://eips.ethereum.org/EIPS/eip-1167
|
||||
if (bytecode.startsWith("0x363d3d373d3d3d363d73")) {
|
||||
const implementationAddress = bytecode.slice(22, 62);
|
||||
return `0x${implementationAddress}`;
|
||||
}
|
||||
|
||||
// Minimal Proxy with receive() from 0xSplits - https://github.com/0xSplits/splits-contracts/blob/c7b741926ec9746182d0d1e2c4c2046102e5d337/contracts/libraries/Clones.sol
|
||||
if (bytecode.startsWith("0x36603057343d5230")) {
|
||||
// +40 = size of addr
|
||||
const implementationAddress = bytecode.slice(122, 122 + 40);
|
||||
return `0x${implementationAddress}`;
|
||||
}
|
||||
|
||||
// 0age's minimal proxy - https://medium.com/coinmonks/the-more-minimal-proxy-5756ae08ee48
|
||||
if (bytecode.startsWith("0x3d3d3d3d363d3d37363d73")) {
|
||||
// +40 = size of addr
|
||||
const implementationAddress = bytecode.slice(24, 24 + 40);
|
||||
return `0x${implementationAddress}`;
|
||||
}
|
||||
|
||||
// vyper's minimal proxy (uniswap v1) - https://etherscan.io/address/0x09cabec1ead1c0ba254b09efb3ee13841712be14#code
|
||||
if (bytecode.startsWith("0x366000600037611000600036600073")) {
|
||||
const implementationAddress = bytecode.slice(32, 32 + 40);
|
||||
return `0x${implementationAddress}`;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param address
|
||||
@@ -250,14 +318,20 @@ export async function resolveContractUriFromAddress(
|
||||
`Contract at ${address} does not exist on chain '${chain.name}' (chainId: ${chain.chainId})`,
|
||||
);
|
||||
}
|
||||
// EIP-1167 clone proxy - https://eips.ethereum.org/EIPS/eip-1167
|
||||
if (bytecode.startsWith("0x363d3d373d3d3d363d")) {
|
||||
const implementationAddress = bytecode.slice(22, 62);
|
||||
return await resolveContractUriFromAddress(
|
||||
`0x${implementationAddress}`,
|
||||
provider,
|
||||
);
|
||||
|
||||
try {
|
||||
const implementationAddress =
|
||||
extractMinimalProxyImplementationAddress(bytecode);
|
||||
if (implementationAddress) {
|
||||
return await resolveContractUriFromAddress(
|
||||
implementationAddress,
|
||||
provider,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// EIP-1967 proxy storage slots - https://eips.ethereum.org/EIPS/eip-1967
|
||||
try {
|
||||
const proxyStorage = await provider.getStorageAt(
|
||||
@@ -368,6 +442,11 @@ export async function fetchContractMetadata(
|
||||
storage: ThirdwebStorage,
|
||||
): Promise<PublishedMetadata> {
|
||||
const metadata = await storage.downloadJSON(compilerMetadataUri);
|
||||
if (!metadata || !metadata.output) {
|
||||
throw new Error(
|
||||
`Could not resolve metadata for contract at ${compilerMetadataUri}`,
|
||||
);
|
||||
}
|
||||
const abi = AbiSchema.parse(metadata.output.abi);
|
||||
const compilationTarget = metadata.settings.compilationTarget;
|
||||
const targets = Object.keys(compilationTarget);
|
||||
@@ -405,7 +484,9 @@ export async function fetchSourceFilesFromMetadata(
|
||||
Object.entries(publishedMetadata.metadata.sources).map(
|
||||
async ([path, info]) => {
|
||||
const urls = (info as any).urls as string[];
|
||||
const ipfsLink = urls.find((url) => url.includes("ipfs"));
|
||||
const ipfsLink = urls
|
||||
? urls.find((url) => url.includes("ipfs"))
|
||||
: undefined;
|
||||
if (ipfsLink) {
|
||||
const ipfsHash = ipfsLink.split("ipfs/")[1];
|
||||
// 5 sec timeout for sources that haven't been uploaded to ipfs
|
||||
@@ -423,7 +504,9 @@ export async function fetchSourceFilesFromMetadata(
|
||||
} else {
|
||||
return {
|
||||
filename: path,
|
||||
source: "Could not find source for this contract",
|
||||
source:
|
||||
(info as any).content ||
|
||||
"Could not find source for this contract",
|
||||
};
|
||||
}
|
||||
},
|
||||
@@ -489,7 +572,7 @@ export async function fetchExtendedReleaseMetadata(
|
||||
* @returns the nested struct of all features and whether they're detected in the abi
|
||||
*/
|
||||
export function detectFeatures(
|
||||
abi: z.input<typeof AbiSchema>,
|
||||
abi: Abi,
|
||||
features: Record<string, Feature> = SUPPORTED_FEATURES,
|
||||
): Record<string, FeatureWithEnabled> {
|
||||
const results: Record<string, FeatureWithEnabled> = {};
|
||||
@@ -506,6 +589,48 @@ export function detectFeatures(
|
||||
return results;
|
||||
}
|
||||
|
||||
function extractFeatures(
|
||||
input: Record<string, FeatureWithEnabled>,
|
||||
enabledExtensions: FeatureWithEnabled[],
|
||||
) {
|
||||
if (!input) {
|
||||
return;
|
||||
}
|
||||
for (const extensionKey in input) {
|
||||
const extension = input[extensionKey];
|
||||
// if extension is enabled, then add it to enabledFeatures
|
||||
if (extension.enabled) {
|
||||
enabledExtensions.push(extension);
|
||||
}
|
||||
// recurse
|
||||
extractFeatures(extension.features, enabledExtensions);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the detected features in the abi
|
||||
* @param abi - parsed array of abi entries
|
||||
* @returns array of all detected extensions with full information on each feature
|
||||
* @public
|
||||
*/
|
||||
export function getAllDetectedFeatures(abi: Abi): FeatureWithEnabled[] {
|
||||
const features: FeatureWithEnabled[] = [];
|
||||
extractFeatures(detectFeatures(abi), features);
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the detected features names in the abi
|
||||
* @param abi - parsed array of abi entries
|
||||
* @returns array of all detected features names
|
||||
* @public
|
||||
*/
|
||||
export function getAllDetectedFeatureNames(abi: Abi): string[] {
|
||||
const features: FeatureWithEnabled[] = [];
|
||||
extractFeatures(detectFeatures(abi), features);
|
||||
return features.map((f) => f.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the given ABI supports a given feature
|
||||
* @internal
|
||||
|
||||
@@ -3,3 +3,10 @@ export * from "./snapshots";
|
||||
export * from "./role";
|
||||
export * from "./feature-detection";
|
||||
export * from "./version-checker";
|
||||
// export helpful util
|
||||
export {
|
||||
fetchCurrencyValue,
|
||||
fetchCurrencyMetadata,
|
||||
normalizePriceValue,
|
||||
} from "./currency";
|
||||
export { convertToReadableQuantity } from "./claim-conditions";
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import { MAX_BPS } from "../../core/schema/shared";
|
||||
import {
|
||||
InterfaceId_IERC1155,
|
||||
InterfaceId_IERC721,
|
||||
} from "../constants/contract";
|
||||
import { SignerOrProvider } from "../core";
|
||||
import { ContractWrapper } from "../core/classes/contract-wrapper";
|
||||
import { MAX_BPS } from "../schema/shared";
|
||||
import {
|
||||
NewAuctionListing,
|
||||
NewDirectListing,
|
||||
@@ -76,33 +75,38 @@ export async function isTokenApprovedForTransfer(
|
||||
/**
|
||||
* Checks if the marketplace is approved to make transfers on the assetContract
|
||||
* If not, it tries to set the approval.
|
||||
* @param signerOrProvider
|
||||
* @param contractWrapper
|
||||
* @param marketplaceAddress
|
||||
* @param assetContract
|
||||
* @param tokenId
|
||||
* @param from
|
||||
*/
|
||||
export async function handleTokenApproval(
|
||||
signerOrProvider: SignerOrProvider,
|
||||
contractWrapper: ContractWrapper<any>,
|
||||
marketplaceAddress: string,
|
||||
assetContract: string,
|
||||
tokenId: BigNumberish,
|
||||
from: string,
|
||||
): Promise<void> {
|
||||
const erc165 = new Contract(
|
||||
const erc165 = new ContractWrapper<IERC165>(
|
||||
contractWrapper.getSignerOrProvider(),
|
||||
assetContract,
|
||||
ERC165Abi,
|
||||
signerOrProvider,
|
||||
) as IERC165;
|
||||
const isERC721 = await erc165.supportsInterface(InterfaceId_IERC721);
|
||||
const isERC1155 = await erc165.supportsInterface(InterfaceId_IERC1155);
|
||||
contractWrapper.options,
|
||||
);
|
||||
const isERC721 = await erc165.readContract.supportsInterface(
|
||||
InterfaceId_IERC721,
|
||||
);
|
||||
const isERC1155 = await erc165.readContract.supportsInterface(
|
||||
InterfaceId_IERC1155,
|
||||
);
|
||||
// check for token approval
|
||||
if (isERC721) {
|
||||
const asset = new ContractWrapper<IERC721>(
|
||||
signerOrProvider,
|
||||
contractWrapper.getSignerOrProvider(),
|
||||
assetContract,
|
||||
ERC721Abi,
|
||||
{},
|
||||
contractWrapper.options,
|
||||
);
|
||||
const approved = await asset.readContract.isApprovedForAll(
|
||||
from,
|
||||
@@ -122,10 +126,10 @@ export async function handleTokenApproval(
|
||||
}
|
||||
} else if (isERC1155) {
|
||||
const asset = new ContractWrapper<IERC1155>(
|
||||
signerOrProvider,
|
||||
contractWrapper.getSignerOrProvider(),
|
||||
assetContract,
|
||||
ERC1155Abi,
|
||||
{},
|
||||
contractWrapper.options,
|
||||
);
|
||||
|
||||
const approved = await asset.readContract.isApprovedForAll(
|
||||
|
||||
@@ -101,8 +101,11 @@ export class ShardedMerkleTree {
|
||||
[
|
||||
entry.address,
|
||||
convertQuantityToBigNumber(entry.maxClaimable, tokenDecimals),
|
||||
convertQuantityToBigNumber(entry.price, currencyDecimals),
|
||||
entry.currencyAddress,
|
||||
convertQuantityToBigNumber(
|
||||
entry.price || "unlimited",
|
||||
currencyDecimals,
|
||||
),
|
||||
entry.currencyAddress || ethers.constants.AddressZero,
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -111,11 +114,14 @@ export class ShardedMerkleTree {
|
||||
static async fetchAndCacheDecimals(
|
||||
cache: Record<string, number>,
|
||||
provider: ethers.providers.Provider,
|
||||
currencyAddress: string,
|
||||
currencyAddress?: string,
|
||||
): Promise<number> {
|
||||
if (!currencyAddress) {
|
||||
return 18;
|
||||
}
|
||||
// cache decimals for each currency to avoid refetching for every address
|
||||
let currencyDecimals = cache[currencyAddress];
|
||||
if (!currencyDecimals) {
|
||||
if (currencyDecimals === undefined) {
|
||||
const currencyMetadata = await fetchCurrencyMetadata(
|
||||
provider,
|
||||
currencyAddress,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ChainId, SUPPORTED_CHAIN_ID } from "./chains";
|
||||
import { PrebuiltContractType } from "../core/types";
|
||||
import { ChainId, SUPPORTED_CHAIN_ID, SUPPORTED_CHAIN_IDS } from "./chains";
|
||||
import { constants } from "ethers";
|
||||
|
||||
/**
|
||||
@@ -142,6 +143,118 @@ export const CONTRACT_ADDRESSES: Record<
|
||||
},
|
||||
};
|
||||
|
||||
type DropContract = Extract<
|
||||
PrebuiltContractType,
|
||||
"nft-drop" | "token-drop" | "edition-drop" | "signature-drop"
|
||||
>;
|
||||
export const APPROVED_IMPLEMENTATIONS: Record<
|
||||
SUPPORTED_CHAIN_ID,
|
||||
Record<DropContract, string>
|
||||
> = {
|
||||
[ChainId.Mainnet]: {
|
||||
"nft-drop": "0x60fF9952e0084A6DEac44203838cDC91ABeC8736",
|
||||
"edition-drop": "0x74af262d0671F378F97a1EDC3d0970Dbe8A1C550",
|
||||
"token-drop": "0xE1eE43D23f247b6A9aF81fcE2766E76709482728",
|
||||
"signature-drop": "0x6fD690EB509BdE4C50028C5D9C0dE3750C2Fad6A",
|
||||
},
|
||||
[ChainId.Polygon]: {
|
||||
"nft-drop": "0xB96508050Ba0925256184103560EBADA912Fcc69",
|
||||
"edition-drop": "0x74af262d0671F378F97a1EDC3d0970Dbe8A1C550",
|
||||
"token-drop": "0x5A8eA4Adad8289746D073947BA06D69A62499aaf",
|
||||
"signature-drop": "0xBE2fDc35410E268e41Bec62DBb01AEb43245c7d5",
|
||||
},
|
||||
[ChainId.Fantom]: {
|
||||
"nft-drop": "0x2A396b2D90BAcEF19cDa973586B2633d22710fC2",
|
||||
"edition-drop": "0x06395FCF9AC6ED827f9dD6e776809cEF1Be0d21B",
|
||||
"token-drop": "0x0148b28a38efaaC31b6aa0a6D9FEb70FE7C91FFa",
|
||||
"signature-drop": "0xe135Ef65C2B2213C3fD56d0Bd6500A2cA147aC10",
|
||||
},
|
||||
[ChainId.Avalanche]: {
|
||||
"nft-drop": "0x9cF91118C8ee2913F0588e0F10e36B3d63F68bF6",
|
||||
"edition-drop": "0x135fC9D26E5eC51260ece1DF4ED424E2f55c7766",
|
||||
"token-drop": "0xca0B071899E575BA86495D46c5066971b6f3A901",
|
||||
"signature-drop": "0x1d47526C3292B0130ef0afD5F02c1DA052A017B3",
|
||||
},
|
||||
[ChainId.Optimism]: {
|
||||
"nft-drop": "0xFBd7D24d80ee005671E731a7287DEB6073264dD1",
|
||||
"edition-drop": "0xe135Ef65C2B2213C3fD56d0Bd6500A2cA147aC10",
|
||||
"token-drop": "0x902Dd246e66d8C3CE652375a723F2a52b43b9AAE",
|
||||
"signature-drop": "0x8a4cd3549e548bbEEb38C16E041FFf040a5acabD",
|
||||
},
|
||||
[ChainId.Arbitrum]: {
|
||||
"nft-drop": "0xC4903c1Ff5367b9ac2c349B63DC2409421AaEE2a",
|
||||
"edition-drop": "0xCcddcec1831646Beff2753249f1B9C580327E89F",
|
||||
"token-drop": "0x1b5947e1a2d5a29D0df20931DeAB0B87818209B9",
|
||||
"signature-drop": "0x2dF9851af45dd41C8584ac55D983C604da985Bc7",
|
||||
},
|
||||
[ChainId.BinanceSmartChainMainnet]: {
|
||||
"nft-drop": "0x902Dd246e66d8C3CE652375a723F2a52b43b9AAE",
|
||||
"edition-drop": "0x2A396b2D90BAcEF19cDa973586B2633d22710fC2",
|
||||
"token-drop": "0xe135Ef65C2B2213C3fD56d0Bd6500A2cA147aC10",
|
||||
"signature-drop": "0xFBd7D24d80ee005671E731a7287DEB6073264dD1",
|
||||
},
|
||||
[ChainId.Goerli]: {
|
||||
"nft-drop": "0xD11c97DD5F5546B5bBd630D7D1d7327481B0b92C",
|
||||
"edition-drop": "0x5A8eA4Adad8289746D073947BA06D69A62499aaf",
|
||||
"token-drop": "0x5680933221B752EB443654a014f88B101F868d50",
|
||||
"signature-drop": "0x1b5947e1a2d5a29D0df20931DeAB0B87818209B9",
|
||||
},
|
||||
[ChainId.Mumbai]: {
|
||||
"nft-drop": "0xC4903c1Ff5367b9ac2c349B63DC2409421AaEE2a",
|
||||
"edition-drop": "0xCcddcec1831646Beff2753249f1B9C580327E89F",
|
||||
"token-drop": "0x1b5947e1a2d5a29D0df20931DeAB0B87818209B9",
|
||||
"signature-drop": "0x2dF9851af45dd41C8584ac55D983C604da985Bc7",
|
||||
},
|
||||
[ChainId.FantomTestnet]: {
|
||||
"nft-drop": "0x8a4cd3549e548bbEEb38C16E041FFf040a5acabD",
|
||||
"edition-drop": "0x902Dd246e66d8C3CE652375a723F2a52b43b9AAE",
|
||||
"token-drop": "0xFBd7D24d80ee005671E731a7287DEB6073264dD1",
|
||||
"signature-drop": "0x5A8eA4Adad8289746D073947BA06D69A62499aaf",
|
||||
},
|
||||
[ChainId.AvalancheFujiTestnet]: {
|
||||
"nft-drop": "0xD11c97DD5F5546B5bBd630D7D1d7327481B0b92C",
|
||||
"edition-drop": "0xE1eE43D23f247b6A9aF81fcE2766E76709482728",
|
||||
"token-drop": "0x6fD690EB509BdE4C50028C5D9C0dE3750C2Fad6A",
|
||||
"signature-drop": "0xCcddcec1831646Beff2753249f1B9C580327E89F",
|
||||
},
|
||||
[ChainId.OptimismGoerli]: {
|
||||
"nft-drop": "0xCcddcec1831646Beff2753249f1B9C580327E89F",
|
||||
"edition-drop": "0x6fD690EB509BdE4C50028C5D9C0dE3750C2Fad6A",
|
||||
"token-drop": "0xD11c97DD5F5546B5bBd630D7D1d7327481B0b92C",
|
||||
"signature-drop": "0x1b5947e1a2d5a29D0df20931DeAB0B87818209B9",
|
||||
},
|
||||
[ChainId.ArbitrumGoerli]: {
|
||||
"nft-drop": "0x9CfE807a5b124b962064Fa8F7FD823Cc701255b6",
|
||||
"edition-drop": "0x9cF91118C8ee2913F0588e0F10e36B3d63F68bF6",
|
||||
"token-drop": "0x1d47526C3292B0130ef0afD5F02c1DA052A017B3",
|
||||
"signature-drop": "0xE1eE43D23f247b6A9aF81fcE2766E76709482728",
|
||||
},
|
||||
[ChainId.BinanceSmartChainTestnet]: {
|
||||
"nft-drop": "",
|
||||
"edition-drop": "",
|
||||
"token-drop": "",
|
||||
"signature-drop": "", // TODO
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param chainId
|
||||
* @param contractType
|
||||
*/
|
||||
export function getApprovedImplementation(
|
||||
chainId: SUPPORTED_CHAIN_ID, // TODO use SupportedChainId once we deploy to all chains
|
||||
contractType: PrebuiltContractType,
|
||||
): string | null {
|
||||
if (chainId in APPROVED_IMPLEMENTATIONS) {
|
||||
const approvedImpls = APPROVED_IMPLEMENTATIONS[chainId];
|
||||
if (contractType in approvedImpls) {
|
||||
return approvedImpls[contractType as keyof typeof approvedImpls];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@@ -177,3 +290,24 @@ export function getContractPublisherAddress() {
|
||||
return ContractPublisher_address;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param chainId - chain id
|
||||
* @returns the array of trusted forwarders for the given chain id
|
||||
* @internal
|
||||
*/
|
||||
export function getDefaultTrustedForwarders(
|
||||
chainId: SUPPORTED_CHAIN_ID,
|
||||
): string[] {
|
||||
const chainEnum = SUPPORTED_CHAIN_IDS.find((c) => c === chainId);
|
||||
const biconomyForwarder = chainEnum
|
||||
? CONTRACT_ADDRESSES[chainEnum].biconomyForwarder
|
||||
: constants.AddressZero;
|
||||
const openzeppelinForwarder = chainEnum
|
||||
? CONTRACT_ADDRESSES[chainEnum].openzeppelinForwarder
|
||||
: constants.AddressZero;
|
||||
return biconomyForwarder !== constants.AddressZero
|
||||
? [openzeppelinForwarder, biconomyForwarder]
|
||||
: [openzeppelinForwarder];
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ export enum ChainId {
|
||||
Goerli = 5,
|
||||
Polygon = 137,
|
||||
Mumbai = 80001,
|
||||
Harmony = 1666600000,
|
||||
Localhost = 1337,
|
||||
Hardhat = 31337,
|
||||
Fantom = 250,
|
||||
|
||||
@@ -3,35 +3,45 @@ import {
|
||||
FEATURE_TOKEN_BATCH_MINTABLE,
|
||||
FEATURE_TOKEN_BURNABLE,
|
||||
FEATURE_TOKEN_MINTABLE,
|
||||
FEATURE_TOKEN_CLAIMABLE_WITH_CONDITIONS,
|
||||
FEATURE_TOKEN_SIGNATURE_MINTABLE,
|
||||
FEATURE_TOKEN_CLAIM_CONDITIONS_V1,
|
||||
FEATURE_TOKEN_CLAIM_CONDITIONS_V2,
|
||||
FEATURE_TOKEN_CLAIM_PHASES_V2,
|
||||
FEATURE_TOKEN_CLAIM_PHASES_V1,
|
||||
} from "./erc20-features";
|
||||
import {
|
||||
FEATURE_NFT,
|
||||
FEATURE_NFT_BATCH_MINTABLE,
|
||||
FEATURE_NFT_BURNABLE,
|
||||
FEATURE_NFT_CLAIMABLE,
|
||||
FEATURE_NFT_CLAIM_CUSTOM,
|
||||
FEATURE_NFT_LAZY_MINTABLE,
|
||||
FEATURE_NFT_ENUMERABLE,
|
||||
FEATURE_NFT_MINTABLE,
|
||||
FEATURE_NFT_REVEALABLE,
|
||||
FEATURE_NFT_SIGNATURE_MINTABLE,
|
||||
FEATURE_NFT_SUPPLY,
|
||||
FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V1,
|
||||
FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V2,
|
||||
FEATURE_NFT_CLAIM_CONDITIONS_V1,
|
||||
FEATURE_NFT_CLAIM_CONDITIONS_V2,
|
||||
FEATURE_NFT_CLAIM_PHASES_V2,
|
||||
FEATURE_NFT_TIERED_DROP,
|
||||
FEATURE_NFT_CLAIM_PHASES_V1,
|
||||
FEATURE_NFT_SIGNATURE_MINTABLE_V1,
|
||||
FEATURE_NFT_SIGNATURE_MINTABLE_V2,
|
||||
} from "./erc721-features";
|
||||
import {
|
||||
FEATURE_EDITION,
|
||||
FEATURE_EDITION_BATCH_MINTABLE,
|
||||
FEATURE_EDITION_BURNABLE,
|
||||
FEATURE_EDITION_CLAIMABLE,
|
||||
FEATURE_EDITION_CLAIMABLE_WITH_CONDITIONS,
|
||||
FEATURE_EDITION_CLAIM_CUSTOM,
|
||||
FEATURE_EDITION_CLAIM_CONDITIONS_V1,
|
||||
FEATURE_EDITION_CLAIM_CONDITIONS_V2,
|
||||
FEATURE_EDITION_CLAIM_PHASES_V2,
|
||||
FEATURE_EDITION_ENUMERABLE,
|
||||
FEATURE_EDITION_LAZY_MINTABLE,
|
||||
FEATURE_EDITION_LAZY_MINTABLE_V1,
|
||||
FEATURE_EDITION_LAZY_MINTABLE_V2,
|
||||
FEATURE_EDITION_MINTABLE,
|
||||
FEATURE_EDITION_REVEALABLE,
|
||||
FEATURE_EDITION_SIGNATURE_MINTABLE,
|
||||
FEATURE_EDITION_CLAIM_PHASES_V1,
|
||||
} from "./erc1155-features";
|
||||
import {
|
||||
FEATURE_METADATA,
|
||||
@@ -42,6 +52,7 @@ import {
|
||||
FEATURE_PRIMARY_SALE,
|
||||
FEATURE_ROYALTY,
|
||||
FEATURE_APPURI,
|
||||
FEATURE_GASLESS,
|
||||
} from "./thirdweb-features";
|
||||
|
||||
/**
|
||||
@@ -52,7 +63,10 @@ export type Feature =
|
||||
| typeof FEATURE_TOKEN_MINTABLE
|
||||
| typeof FEATURE_TOKEN_BATCH_MINTABLE
|
||||
| typeof FEATURE_TOKEN_BURNABLE
|
||||
| typeof FEATURE_TOKEN_CLAIMABLE_WITH_CONDITIONS
|
||||
| typeof FEATURE_TOKEN_CLAIM_CONDITIONS_V1
|
||||
| typeof FEATURE_TOKEN_CLAIM_CONDITIONS_V2
|
||||
| typeof FEATURE_TOKEN_CLAIM_PHASES_V1
|
||||
| typeof FEATURE_TOKEN_CLAIM_PHASES_V2
|
||||
| typeof FEATURE_TOKEN_SIGNATURE_MINTABLE
|
||||
| typeof FEATURE_NFT
|
||||
| typeof FEATURE_NFT_SUPPLY
|
||||
@@ -60,19 +74,26 @@ export type Feature =
|
||||
| typeof FEATURE_NFT_MINTABLE
|
||||
| typeof FEATURE_NFT_BATCH_MINTABLE
|
||||
| typeof FEATURE_NFT_LAZY_MINTABLE
|
||||
| typeof FEATURE_NFT_CLAIMABLE
|
||||
| typeof FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V1
|
||||
| typeof FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V2
|
||||
| typeof FEATURE_NFT_CLAIM_CUSTOM
|
||||
| typeof FEATURE_NFT_CLAIM_CONDITIONS_V1
|
||||
| typeof FEATURE_NFT_CLAIM_CONDITIONS_V2
|
||||
| typeof FEATURE_NFT_CLAIM_PHASES_V1
|
||||
| typeof FEATURE_NFT_CLAIM_PHASES_V2
|
||||
| typeof FEATURE_NFT_REVEALABLE
|
||||
| typeof FEATURE_NFT_SIGNATURE_MINTABLE
|
||||
| typeof FEATURE_NFT_SIGNATURE_MINTABLE_V1
|
||||
| typeof FEATURE_NFT_SIGNATURE_MINTABLE_V2
|
||||
| typeof FEATURE_NFT_BURNABLE
|
||||
| typeof FEATURE_NFT_TIERED_DROP
|
||||
| typeof FEATURE_EDITION
|
||||
| typeof FEATURE_EDITION_ENUMERABLE
|
||||
| typeof FEATURE_EDITION_MINTABLE
|
||||
| typeof FEATURE_EDITION_CLAIMABLE
|
||||
| typeof FEATURE_EDITION_CLAIMABLE_WITH_CONDITIONS
|
||||
| typeof FEATURE_EDITION_LAZY_MINTABLE
|
||||
| typeof FEATURE_EDITION_CLAIM_CUSTOM
|
||||
| typeof FEATURE_EDITION_CLAIM_CONDITIONS_V1
|
||||
| typeof FEATURE_EDITION_CLAIM_CONDITIONS_V2
|
||||
| typeof FEATURE_EDITION_CLAIM_PHASES_V1
|
||||
| typeof FEATURE_EDITION_CLAIM_PHASES_V2
|
||||
| typeof FEATURE_EDITION_LAZY_MINTABLE_V1
|
||||
| typeof FEATURE_EDITION_LAZY_MINTABLE_V2
|
||||
| typeof FEATURE_EDITION_REVEALABLE
|
||||
| typeof FEATURE_EDITION_BATCH_MINTABLE
|
||||
| typeof FEATURE_EDITION_BURNABLE
|
||||
@@ -84,7 +105,8 @@ export type Feature =
|
||||
| typeof FEATURE_PERMISSIONS_ENUMERABLE
|
||||
| typeof FEATURE_METADATA
|
||||
| typeof FEATURE_APPURI
|
||||
| typeof FEATURE_OWNER;
|
||||
| typeof FEATURE_OWNER
|
||||
| typeof FEATURE_GASLESS;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@@ -112,4 +134,5 @@ export const SUPPORTED_FEATURES: Record<string, Feature> = {
|
||||
[FEATURE_METADATA.name]: FEATURE_METADATA,
|
||||
[FEATURE_APPURI.name]: FEATURE_APPURI,
|
||||
[FEATURE_OWNER.name]: FEATURE_OWNER,
|
||||
[FEATURE_GASLESS.name]: FEATURE_GASLESS,
|
||||
};
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import DelayedRevealAbi from "@thirdweb-dev/contracts-js/dist/abis/DelayedReveal.json";
|
||||
import DropERC1155_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/DropERC1155_V2.json";
|
||||
import IBurnableERC1155Abi from "@thirdweb-dev/contracts-js/dist/abis/IBurnableERC1155.json";
|
||||
import IClaimableERC1155 from "@thirdweb-dev/contracts-js/dist/abis/IClaimableERC1155.json";
|
||||
import DelayedRevealAbi from "@thirdweb-dev/contracts-js/dist/abis/IDelayedReveal.json";
|
||||
import IDropMultiPhase1155 from "@thirdweb-dev/contracts-js/dist/abis/IDrop1155.json";
|
||||
import IDropSinglePhase1155 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase1155.json";
|
||||
import IDropSinglePhase1155_V1 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase1155_V1.json";
|
||||
import Erc1155Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC1155.json";
|
||||
import Erc1155EnumerableAbi from "@thirdweb-dev/contracts-js/dist/abis/IERC1155Enumerable.json";
|
||||
import ILazyMintAbi from "@thirdweb-dev/contracts-js/dist/abis/ILazyMint.json";
|
||||
@@ -20,8 +23,19 @@ export const FEATURE_EDITION_BURNABLE = {
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_EDITION_CLAIMABLE_WITH_CONDITIONS = {
|
||||
name: "ERC1155ClaimableWithConditions",
|
||||
export const FEATURE_EDITION_CLAIM_CONDITIONS_V1 = {
|
||||
name: "ERC1155ClaimConditionsV1",
|
||||
namespace: "edition.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc1155claimable",
|
||||
contracts: "DropSinglePhase1155",
|
||||
},
|
||||
abis: [Erc1155Abi, ILazyMintAbi, IDropSinglePhase1155_V1],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_EDITION_CLAIM_CONDITIONS_V2 = {
|
||||
name: "ERC1155ClaimConditionsV2",
|
||||
namespace: "edition.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc1155claimable",
|
||||
@@ -31,8 +45,30 @@ export const FEATURE_EDITION_CLAIMABLE_WITH_CONDITIONS = {
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_EDITION_CLAIMABLE = {
|
||||
name: "ERC1155Claimable",
|
||||
export const FEATURE_EDITION_CLAIM_PHASES_V2 = {
|
||||
name: "ERC1155ClaimPhasesV2",
|
||||
namespace: "edition.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc1155claimable",
|
||||
contracts: "Drop1155",
|
||||
},
|
||||
abis: [Erc1155Abi, ILazyMintAbi, IDropMultiPhase1155],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_EDITION_CLAIM_PHASES_V1 = {
|
||||
name: "ERC1155ClaimPhasesV1",
|
||||
namespace: "edition.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc1155claimable",
|
||||
contracts: "Drop1155",
|
||||
},
|
||||
abis: [DropERC1155_V2Abi],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_EDITION_CLAIM_CUSTOM = {
|
||||
name: "ERC1155ClaimCustom",
|
||||
namespace: "edition.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc1155claimable",
|
||||
@@ -42,21 +78,6 @@ export const FEATURE_EDITION_CLAIMABLE = {
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_EDITION_LAZY_MINTABLE = {
|
||||
name: "ERC1155LazyMintable",
|
||||
namespace: "edition.drop",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc1155droppable",
|
||||
contracts: "LazyMint",
|
||||
},
|
||||
abis: [Erc1155Abi, ILazyMintAbi],
|
||||
features: {
|
||||
[FEATURE_EDITION_CLAIMABLE.name]: FEATURE_EDITION_CLAIMABLE,
|
||||
[FEATURE_EDITION_CLAIMABLE_WITH_CONDITIONS.name]:
|
||||
FEATURE_EDITION_CLAIMABLE_WITH_CONDITIONS,
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_EDITION_REVEALABLE = {
|
||||
name: "ERC1155Revealable",
|
||||
namespace: "edition.drop.revealer",
|
||||
@@ -68,6 +89,38 @@ export const FEATURE_EDITION_REVEALABLE = {
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_EDITION_LAZY_MINTABLE_V2 = {
|
||||
name: "ERC1155LazyMintableV2",
|
||||
namespace: "edition.drop",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc1155droppable",
|
||||
contracts: "LazyMint",
|
||||
},
|
||||
abis: [Erc1155Abi, ILazyMintAbi],
|
||||
features: {
|
||||
[FEATURE_EDITION_REVEALABLE.name]: FEATURE_EDITION_REVEALABLE,
|
||||
[FEATURE_EDITION_CLAIM_CUSTOM.name]: FEATURE_EDITION_CLAIM_CUSTOM,
|
||||
[FEATURE_EDITION_CLAIM_CONDITIONS_V1.name]:
|
||||
FEATURE_EDITION_CLAIM_CONDITIONS_V1,
|
||||
[FEATURE_EDITION_CLAIM_CONDITIONS_V2.name]:
|
||||
FEATURE_EDITION_CLAIM_CONDITIONS_V2,
|
||||
[FEATURE_EDITION_CLAIM_PHASES_V2.name]: FEATURE_EDITION_CLAIM_PHASES_V2,
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_EDITION_LAZY_MINTABLE_V1 = {
|
||||
name: "ERC1155LazyMintableV1",
|
||||
namespace: "edition.drop",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc1155droppable",
|
||||
contracts: "LazyMint",
|
||||
},
|
||||
abis: [DropERC1155_V2Abi],
|
||||
features: {
|
||||
[FEATURE_EDITION_CLAIM_PHASES_V1.name]: FEATURE_EDITION_CLAIM_PHASES_V1,
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_EDITION_SIGNATURE_MINTABLE = {
|
||||
name: "ERC1155SignatureMintable",
|
||||
namespace: "edition.signature",
|
||||
@@ -126,7 +179,8 @@ export const FEATURE_EDITION = {
|
||||
[FEATURE_EDITION_BURNABLE.name]: FEATURE_EDITION_BURNABLE,
|
||||
[FEATURE_EDITION_ENUMERABLE.name]: FEATURE_EDITION_ENUMERABLE,
|
||||
[FEATURE_EDITION_MINTABLE.name]: FEATURE_EDITION_MINTABLE,
|
||||
[FEATURE_EDITION_LAZY_MINTABLE.name]: FEATURE_EDITION_LAZY_MINTABLE,
|
||||
[FEATURE_EDITION_LAZY_MINTABLE_V1.name]: FEATURE_EDITION_LAZY_MINTABLE_V1,
|
||||
[FEATURE_EDITION_LAZY_MINTABLE_V2.name]: FEATURE_EDITION_LAZY_MINTABLE_V2,
|
||||
[FEATURE_EDITION_REVEALABLE.name]: FEATURE_EDITION_REVEALABLE,
|
||||
[FEATURE_EDITION_SIGNATURE_MINTABLE.name]:
|
||||
FEATURE_EDITION_SIGNATURE_MINTABLE,
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
import DropERC20_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/DropERC20_V2.json";
|
||||
import IBurnableERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IBurnableERC20.json";
|
||||
import IDrop from "@thirdweb-dev/contracts-js/dist/abis/IDrop.json";
|
||||
import IDropSinglePhase from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase.json";
|
||||
import IDropSinglePhaseV1 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase_V1.json";
|
||||
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
|
||||
import IMintableERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IMintableERC20.json";
|
||||
import MulticallAbi from "@thirdweb-dev/contracts-js/dist/abis/IMulticall.json";
|
||||
import ISignatureMintERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC20.json";
|
||||
|
||||
export const FEATURE_TOKEN_CLAIMABLE_WITH_CONDITIONS = {
|
||||
name: "ERC20ClaimableWithConditions",
|
||||
export const FEATURE_TOKEN_CLAIM_CONDITIONS_V1 = {
|
||||
name: "ERC20ClaimConditionsV1",
|
||||
namespace: "token.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc20dclaimable",
|
||||
contracts: "DropSinglePhase_V1",
|
||||
},
|
||||
abis: [ERC20Abi, IDropSinglePhaseV1],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_TOKEN_CLAIM_CONDITIONS_V2 = {
|
||||
name: "ERC20ClaimConditionsV2",
|
||||
namespace: "token.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc20dclaimable",
|
||||
@@ -16,6 +30,28 @@ export const FEATURE_TOKEN_CLAIMABLE_WITH_CONDITIONS = {
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_TOKEN_CLAIM_PHASES_V2 = {
|
||||
name: "ERC20ClaimPhasesV2",
|
||||
namespace: "token.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc20dclaimable",
|
||||
contracts: "Drop",
|
||||
},
|
||||
abis: [ERC20Abi, IDrop],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_TOKEN_CLAIM_PHASES_V1 = {
|
||||
name: "ERC20ClaimPhasesV1",
|
||||
namespace: "token.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc20dclaimable",
|
||||
contracts: "Drop",
|
||||
},
|
||||
abis: [DropERC20_V2Abi],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_TOKEN_BURNABLE = {
|
||||
name: "ERC20Burnable",
|
||||
namespace: "token.burn",
|
||||
@@ -73,8 +109,10 @@ export const FEATURE_TOKEN = {
|
||||
features: {
|
||||
[FEATURE_TOKEN_BURNABLE.name]: FEATURE_TOKEN_BURNABLE,
|
||||
[FEATURE_TOKEN_MINTABLE.name]: FEATURE_TOKEN_MINTABLE,
|
||||
[FEATURE_TOKEN_CLAIMABLE_WITH_CONDITIONS.name]:
|
||||
FEATURE_TOKEN_CLAIMABLE_WITH_CONDITIONS,
|
||||
[FEATURE_TOKEN_CLAIM_CONDITIONS_V1.name]: FEATURE_TOKEN_CLAIM_CONDITIONS_V1,
|
||||
[FEATURE_TOKEN_CLAIM_CONDITIONS_V2.name]: FEATURE_TOKEN_CLAIM_CONDITIONS_V2,
|
||||
[FEATURE_TOKEN_CLAIM_PHASES_V1.name]: FEATURE_TOKEN_CLAIM_PHASES_V1,
|
||||
[FEATURE_TOKEN_CLAIM_PHASES_V2.name]: FEATURE_TOKEN_CLAIM_PHASES_V2,
|
||||
[FEATURE_TOKEN_SIGNATURE_MINTABLE.name]: FEATURE_TOKEN_SIGNATURE_MINTABLE,
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import DropERC721_V3Abi from "@thirdweb-dev/contracts-js/dist/abis/DropERC721_V3.json";
|
||||
import IBurnableERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/IBurnableERC721.json";
|
||||
import IClaimableERC721 from "@thirdweb-dev/contracts-js/dist/abis/IClaimableERC721.json";
|
||||
import DelayedRevealAbi from "@thirdweb-dev/contracts-js/dist/abis/IDelayedReveal.json";
|
||||
import IDrop from "@thirdweb-dev/contracts-js/dist/abis/IDrop.json";
|
||||
import IDropSinglePhase from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase.json";
|
||||
import IDropSinglePhaseV1 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase_V1.json";
|
||||
import Erc721Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC721.json";
|
||||
@@ -9,8 +11,9 @@ import Erc721SupplyAbi from "@thirdweb-dev/contracts-js/dist/abis/IERC721Supply.
|
||||
import ILazyMintAbi from "@thirdweb-dev/contracts-js/dist/abis/ILazyMint.json";
|
||||
import IMintableERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/IMintableERC721.json";
|
||||
import MulticallAbi from "@thirdweb-dev/contracts-js/dist/abis/IMulticall.json";
|
||||
import SignatureMintERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC721.json";
|
||||
import SignatureMintERC721_V1Abi from "@thirdweb-dev/contracts-js/dist/abis/ISignatureMintERC721_V1.json";
|
||||
import TieredDropAbi from "@thirdweb-dev/contracts-js/dist/abis/LazyMintWithTier.json";
|
||||
import SignatureMintERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/SignatureMintERC721.json";
|
||||
|
||||
export const FEATURE_NFT_BURNABLE = {
|
||||
name: "ERC721Burnable",
|
||||
@@ -45,19 +48,8 @@ export const FEATURE_NFT_TIERED_DROP = {
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V2 = {
|
||||
name: "ERC721ClaimableWithConditionsV2",
|
||||
namespace: "nft.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc721claimable",
|
||||
contracts: "DropSinglePhase",
|
||||
},
|
||||
abis: [Erc721Abi, ILazyMintAbi, IDropSinglePhase],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V1 = {
|
||||
name: "ERC721ClaimableWithConditionsV1",
|
||||
export const FEATURE_NFT_CLAIM_CONDITIONS_V1 = {
|
||||
name: "ERC721ClaimConditionsV1",
|
||||
namespace: "nft.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc721claimable",
|
||||
@@ -67,8 +59,41 @@ export const FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V1 = {
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_NFT_CLAIMABLE = {
|
||||
name: "ERC721Claimable",
|
||||
export const FEATURE_NFT_CLAIM_CONDITIONS_V2 = {
|
||||
name: "ERC721ClaimConditionsV2",
|
||||
namespace: "nft.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc721claimable",
|
||||
contracts: "DropSinglePhase",
|
||||
},
|
||||
abis: [Erc721Abi, ILazyMintAbi, IDropSinglePhase],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_NFT_CLAIM_PHASES_V1 = {
|
||||
name: "ERC721ClaimPhasesV1",
|
||||
namespace: "nft.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc721claimable",
|
||||
contracts: "Drop",
|
||||
},
|
||||
abis: [DropERC721_V3Abi],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_NFT_CLAIM_PHASES_V2 = {
|
||||
name: "ERC721ClaimPhasesV2",
|
||||
namespace: "nft.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc721claimable",
|
||||
contracts: "Drop",
|
||||
},
|
||||
abis: [Erc721Abi, ILazyMintAbi, IDrop],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_NFT_CLAIM_CUSTOM = {
|
||||
name: "ERC721ClaimCustom",
|
||||
namespace: "nft.drop.claim",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc721claimable",
|
||||
@@ -88,11 +113,11 @@ export const FEATURE_NFT_LAZY_MINTABLE = {
|
||||
abis: [Erc721Abi, ILazyMintAbi],
|
||||
features: {
|
||||
[FEATURE_NFT_REVEALABLE.name]: FEATURE_NFT_REVEALABLE,
|
||||
[FEATURE_NFT_CLAIMABLE.name]: FEATURE_NFT_CLAIMABLE,
|
||||
[FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V2.name]:
|
||||
FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V2,
|
||||
[FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V1.name]:
|
||||
FEATURE_NFT_CLAIMABLE_WITH_CONDITIONS_V1,
|
||||
[FEATURE_NFT_CLAIM_CUSTOM.name]: FEATURE_NFT_CLAIM_CUSTOM,
|
||||
[FEATURE_NFT_CLAIM_CONDITIONS_V1.name]: FEATURE_NFT_CLAIM_CONDITIONS_V1,
|
||||
[FEATURE_NFT_CLAIM_CONDITIONS_V2.name]: FEATURE_NFT_CLAIM_CONDITIONS_V2,
|
||||
[FEATURE_NFT_CLAIM_PHASES_V1.name]: FEATURE_NFT_CLAIM_PHASES_V1,
|
||||
[FEATURE_NFT_CLAIM_PHASES_V2.name]: FEATURE_NFT_CLAIM_PHASES_V2,
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -120,8 +145,8 @@ export const FEATURE_NFT_MINTABLE = {
|
||||
},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_NFT_SIGNATURE_MINTABLE = {
|
||||
name: "ERC721SignatureMint",
|
||||
export const FEATURE_NFT_SIGNATURE_MINTABLE_V2 = {
|
||||
name: "ERC721SignatureMintV2",
|
||||
namespace: "nft.signature",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc721signaturemint",
|
||||
@@ -131,6 +156,17 @@ export const FEATURE_NFT_SIGNATURE_MINTABLE = {
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_NFT_SIGNATURE_MINTABLE_V1 = {
|
||||
name: "ERC721SignatureMintV1",
|
||||
namespace: "nft.signature",
|
||||
docLinks: {
|
||||
sdk: "sdk.erc721signaturemint",
|
||||
contracts: "ISignatureMintERC721",
|
||||
},
|
||||
abis: [SignatureMintERC721_V1Abi],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_NFT_ENUMERABLE = {
|
||||
name: "ERC721Enumerable",
|
||||
namespace: "nft.query.owned",
|
||||
@@ -168,7 +204,8 @@ export const FEATURE_NFT = {
|
||||
[FEATURE_NFT_SUPPLY.name]: FEATURE_NFT_SUPPLY,
|
||||
[FEATURE_NFT_MINTABLE.name]: FEATURE_NFT_MINTABLE,
|
||||
[FEATURE_NFT_LAZY_MINTABLE.name]: FEATURE_NFT_LAZY_MINTABLE,
|
||||
[FEATURE_NFT_SIGNATURE_MINTABLE.name]: FEATURE_NFT_SIGNATURE_MINTABLE,
|
||||
[FEATURE_NFT_SIGNATURE_MINTABLE_V1.name]: FEATURE_NFT_SIGNATURE_MINTABLE_V1,
|
||||
[FEATURE_NFT_SIGNATURE_MINTABLE_V2.name]: FEATURE_NFT_SIGNATURE_MINTABLE_V2,
|
||||
[FEATURE_NFT_TIERED_DROP.name]: FEATURE_NFT_TIERED_DROP,
|
||||
},
|
||||
} as const;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import IERC2771ContextAbi from "@thirdweb-dev/contracts-js/dist/abis/ERC2771Context.json";
|
||||
import IAppURI from "@thirdweb-dev/contracts-js/dist/abis/IAppURI.json";
|
||||
import IContractMetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/IContractMetadata.json";
|
||||
import IPermissionsAbi from "@thirdweb-dev/contracts-js/dist/abis/IPermissions.json";
|
||||
@@ -96,3 +97,15 @@ export const FEATURE_OWNER = {
|
||||
abis: [IOwnableAbi],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_GASLESS = {
|
||||
name: "Gasless",
|
||||
namespace: "gasless",
|
||||
docLinks: {
|
||||
sdk: "sdk.gaslesstransaction",
|
||||
// TODO add the correct name for this once it's added to portal
|
||||
contracts: "",
|
||||
},
|
||||
abis: [IERC2771ContextAbi],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
@@ -123,6 +123,11 @@ export function getProviderForNetwork(network: ChainOrRpc | SignerOrProvider) {
|
||||
}
|
||||
}
|
||||
|
||||
const READONLY_PROVIDER_MAP: Map<
|
||||
string,
|
||||
StaticJsonRpcBatchProvider | providers.JsonRpcBatchProvider
|
||||
> = new Map();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param network - the chain name or rpc url
|
||||
@@ -136,11 +141,19 @@ export function getReadOnlyProvider(network: string, chainId?: number) {
|
||||
if (match) {
|
||||
switch (match[1]) {
|
||||
case "http":
|
||||
return chainId
|
||||
const seralizedOpts = `${network}-${chainId || -1}`;
|
||||
const existingProvider = READONLY_PROVIDER_MAP.get(seralizedOpts);
|
||||
if (existingProvider) {
|
||||
return existingProvider;
|
||||
}
|
||||
|
||||
const newProvider = chainId
|
||||
? // if we know the chainId we should use the StaticJsonRpcBatchProvider
|
||||
new StaticJsonRpcBatchProvider(network, chainId)
|
||||
: // otherwise fall back to the built in json rpc batch provider
|
||||
new providers.JsonRpcBatchProvider(network, chainId);
|
||||
READONLY_PROVIDER_MAP.set(seralizedOpts, newProvider);
|
||||
return newProvider;
|
||||
|
||||
case "ws":
|
||||
return new providers.WebSocketProvider(network, chainId);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user