Compare commits
36
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0f0125acf2 | ||
|
|
894cbefc63 | ||
|
|
73dc026ff9 | ||
|
|
af32007b9f | ||
|
|
5fba324ac1 | ||
|
|
bff433e121 | ||
|
|
68c8e3c4d7 | ||
|
|
4e8ff58208 | ||
|
|
d0d5a3c23d | ||
|
|
9eaa21d09a | ||
|
|
557429b5cf | ||
|
|
96d2dfd25d | ||
|
|
5862c558fb | ||
|
|
e913e0daa9 | ||
|
|
f7a74a3b7c | ||
|
|
73883f56d0 | ||
|
|
e47085af92 | ||
|
|
f525e2cc23 | ||
|
|
af85389dc0 | ||
|
|
ccb4ce8d00 | ||
|
|
4cdd0bd634 | ||
|
|
ea95c5f609 | ||
|
|
699a2b16fb | ||
|
|
a8267f912d | ||
|
|
c673e39f23 | ||
|
|
08d04fe4dc | ||
|
|
cbf5508bd5 | ||
|
|
3731459d33 | ||
|
|
64f24f1bb1 | ||
|
|
cac6c30bca | ||
|
|
e7740a59db | ||
|
|
7a37e564fd | ||
|
|
e173636f4b | ||
|
|
8c6cdaa288 | ||
|
|
ad9b3febff | ||
|
|
94f49b1294 |
@@ -13,7 +13,7 @@ concurrency:
|
||||
jobs:
|
||||
build:
|
||||
name: Build and Test
|
||||
# timeout-minutes: 15
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-32
|
||||
# To use Remote Caching, uncomment the next lines and follow the steps below.
|
||||
env:
|
||||
|
||||
@@ -12,7 +12,7 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
integration-tests:
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-32
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
@@ -13,8 +13,7 @@ concurrency:
|
||||
jobs:
|
||||
lint:
|
||||
name: Lint
|
||||
# timeout-minutes: 15
|
||||
# try out buildjet to speed up build and test
|
||||
timeout-minutes: 15
|
||||
runs-on: ubuntu-latest
|
||||
# To use Remote Caching, uncomment the next lines and follow the steps below.
|
||||
env:
|
||||
|
||||
@@ -41,6 +41,7 @@ jobs:
|
||||
|
||||
deploy:
|
||||
runs-on: ubuntu-latest-32
|
||||
timeout-minutes: 30
|
||||
needs: deploy-check
|
||||
if: needs.deploy-check.outputs.triggered == 'true'
|
||||
steps:
|
||||
|
||||
@@ -14,6 +14,7 @@ concurrency:
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
timeout-minutes: 30
|
||||
runs-on: ubuntu-latest-32
|
||||
steps:
|
||||
- name: Checkout branch
|
||||
|
||||
@@ -5,6 +5,7 @@ on: [pull_request]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest-32
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@
|
||||
"@changesets/cli": "^2.24.3",
|
||||
"@manypkg/cli": "^0.19.1",
|
||||
"@manypkg/get-packages": "^1.1.3",
|
||||
"@trivago/prettier-plugin-sort-imports": "^3.3.0",
|
||||
"@trivago/prettier-plugin-sort-imports": "^4.0.0",
|
||||
"eslint": "^8.21.0",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"prettier": "^2.7.1",
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 2.0.40
|
||||
|
||||
## 2.0.39
|
||||
|
||||
## 2.0.38
|
||||
|
||||
## 2.0.37
|
||||
|
||||
## 2.0.36
|
||||
|
||||
## 2.0.35
|
||||
|
||||
## 2.0.34
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "2.0.35",
|
||||
"version": "2.0.40",
|
||||
"exports": {
|
||||
"./next": {
|
||||
"module": "./next/dist/thirdweb-dev-auth-next.esm.js",
|
||||
|
||||
@@ -1,5 +1,56 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.9.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#483](https://github.com/thirdweb-dev/js/pull/483) [`4e8ff58`](https://github.com/thirdweb-dev/js/commit/4e8ff582084c3d201314e6c5dff5b79f15eb6292) Thanks [@jnsdls](https://github.com/jnsdls)! - `thirdweb create` with usage of `forge` should now function correctly in windows CMD shell
|
||||
|
||||
- Updated dependencies [[`5fba324`](https://github.com/thirdweb-dev/js/commit/5fba324ac17ab02bc8f13d82a232bc5c6970c8e5), [`894cbef`](https://github.com/thirdweb-dev/js/commit/894cbefc6361f23fc528a6c6819f5c71793d46e4), [`557429b`](https://github.com/thirdweb-dev/js/commit/557429b5cfb3af2983ee01cf7d12d41ee0557593), [`73dc026`](https://github.com/thirdweb-dev/js/commit/73dc026ff9d0ac9099bd5a9a9cab8fdbfc0ae723), [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857), [`68c8e3c`](https://github.com/thirdweb-dev/js/commit/68c8e3c4d79f5d56dc4414241bcca0d88285fcca), [`bff433e`](https://github.com/thirdweb-dev/js/commit/bff433e12150dc029e33a578219c8437a510da99)]:
|
||||
- @thirdweb-dev/sdk@3.6.10
|
||||
|
||||
## 0.9.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`e913e0d`](https://github.com/thirdweb-dev/js/commit/e913e0daa9ece9a6274f7ffa4e66bdcbf32e6ada), [`5862c55`](https://github.com/thirdweb-dev/js/commit/5862c558fb48604b5aca4defd1ccc06fc3536358), [`73883f5`](https://github.com/thirdweb-dev/js/commit/73883f56d0ed0a35ace8b98b96caa782443be22e), [`f7a74a3`](https://github.com/thirdweb-dev/js/commit/f7a74a3b7c489ada5b1ec435632a326334a33c9b)]:
|
||||
- @thirdweb-dev/sdk@3.6.9
|
||||
|
||||
## 0.9.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#454](https://github.com/thirdweb-dev/js/pull/454) [`c673e39`](https://github.com/thirdweb-dev/js/commit/c673e39f23ef082097d73d62910580e8fad400a0) Thanks [@jnsdls](https://github.com/jnsdls)! - upgraded dependencies
|
||||
|
||||
- [#461](https://github.com/thirdweb-dev/js/pull/461) [`af85389`](https://github.com/thirdweb-dev/js/commit/af85389dc07fb163b8f9d70093eb1b691e47561a) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Fix deprecated links
|
||||
|
||||
- Updated dependencies [[`c673e39`](https://github.com/thirdweb-dev/js/commit/c673e39f23ef082097d73d62910580e8fad400a0), [`ea95c5f`](https://github.com/thirdweb-dev/js/commit/ea95c5f609e306e333ee0f73f7920503358ca848), [`699a2b1`](https://github.com/thirdweb-dev/js/commit/699a2b16fb991c474ec57db8f178e2601d631f39), [`4cdd0bd`](https://github.com/thirdweb-dev/js/commit/4cdd0bd6348494a256d7c6a2bdf8f7b5c20f6877), [`a8267f9`](https://github.com/thirdweb-dev/js/commit/a8267f912df84c58d3fe3f47b90bd474f73c84ca)]:
|
||||
- @thirdweb-dev/sdk@3.6.8
|
||||
|
||||
## 0.9.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#441](https://github.com/thirdweb-dev/js/pull/441) [`64f24f1`](https://github.com/thirdweb-dev/js/commit/64f24f1bb167c3d0cb3beca51fd300eaec21cc27) Thanks [@adam-maj](https://github.com/adam-maj)! - CLI autoupdates on run
|
||||
|
||||
- [#447](https://github.com/thirdweb-dev/js/pull/447) [`e7740a5`](https://github.com/thirdweb-dev/js/commit/e7740a59db022a3396194ac66cd195d8ae754d57) Thanks [@adam-maj](https://github.com/adam-maj)! - Detect whether forge is installed
|
||||
|
||||
- Updated dependencies [[`3731459`](https://github.com/thirdweb-dev/js/commit/3731459d33f1ded7ebb69124809449b901b3ad3d), [`cac6c30`](https://github.com/thirdweb-dev/js/commit/cac6c30bca5e17df81d746ef81316af47d5e252e), [`7a37e56`](https://github.com/thirdweb-dev/js/commit/7a37e564fd5d5a9df84c8da44ecaf6c42f67a0e2)]:
|
||||
- @thirdweb-dev/sdk@3.6.7
|
||||
|
||||
## 0.9.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`8c6cdaa`](https://github.com/thirdweb-dev/js/commit/8c6cdaa2887fb2cc40d3ee6991233d195d103805)]:
|
||||
- @thirdweb-dev/sdk@3.6.6
|
||||
|
||||
## 0.9.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#444](https://github.com/thirdweb-dev/js/pull/444) [`94f49b1`](https://github.com/thirdweb-dev/js/commit/94f49b1294bc0208171b16ed413cbb44644af017) Thanks [@adam-maj](https://github.com/adam-maj)! - Add changeset
|
||||
|
||||
## 0.9.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -62,7 +62,7 @@ Deploying released contracts give deployers access to automatic SDKs to integrat
|
||||
npx thirdweb@latest detect
|
||||
```
|
||||
|
||||
As you're developing your contracts, you may want to implement [Extensions](https://portal.thirdweb.com/extensions) to unlock functionality on the SDKs (ie. nft minting with automatic upload to IPFS) and the dashboard (ie. generated UI to manage permissions). This command will show what extensions were detected on your contract, unlocking the corresponding functionality on the SDKs and dashboard.
|
||||
As you're developing your contracts, you may want to implement [Extensions](https://portal.thirdweb.com/contractkit) to unlock functionality on the SDKs (ie. nft minting with automatic upload to IPFS) and the dashboard (ie. generated UI to manage permissions). This command will show what extensions were detected on your contract, unlocking the corresponding functionality on the SDKs and dashboard.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.9.3",
|
||||
"version": "0.9.9",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -18,12 +18,12 @@
|
||||
"@types/prompts": "^2.0.14",
|
||||
"@types/rimraf": "^3.0.0",
|
||||
"@types/tar": "^6.1.2",
|
||||
"@types/update-notifier": "^5.1.0",
|
||||
"@types/update-notifier": "^6.0.1",
|
||||
"@types/validate-npm-package-name": "^4.0.0",
|
||||
"hardhat": "^2.9.3",
|
||||
"jest": "^28",
|
||||
"jest": "^29",
|
||||
"prettier": "^2.7.1",
|
||||
"ts-jest": "^28.0.8",
|
||||
"ts-jest": "^29.0.3",
|
||||
"ts-node": "^10.7.0",
|
||||
"tsup": "^6.2.3",
|
||||
"typescript": "^4.7.4"
|
||||
@@ -32,6 +32,7 @@
|
||||
"@thirdweb-dev/sdk": "*",
|
||||
"async-retry": "^1.3.3",
|
||||
"commander": "^9.1.0",
|
||||
"detect-package-manager": "^2.0.1",
|
||||
"enquirer": "^2.3.6",
|
||||
"ethers": "^5.7.2",
|
||||
"got": "11.8.5",
|
||||
|
||||
+148
-20
@@ -2,37 +2,37 @@
|
||||
import { detectExtensions } from "../common/feature-detector";
|
||||
import { processProject } from "../common/processor";
|
||||
import { cliVersion, pkg } from "../constants/urls";
|
||||
import { info, logger } from "../core/helpers/logger";
|
||||
import { info, logger, spinner } from "../core/helpers/logger";
|
||||
import { twCreate } from "../create/command";
|
||||
import { deploy } from "../deploy";
|
||||
import { findPackageInstallation } from "../helpers/detect-local-packages";
|
||||
import { upload } from "../storage/command";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import chalk from "chalk";
|
||||
import { exec, spawn } from "child_process";
|
||||
import { Command } from "commander";
|
||||
import open from "open";
|
||||
import prompts from "prompts";
|
||||
|
||||
const main = async () => {
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
const skipIntro = process.env.THIRDWEB_CLI_SKIP_INTRO === "true";
|
||||
|
||||
const program = new Command();
|
||||
|
||||
//yes this has to look like this, eliminates whitespace
|
||||
console.info(`
|
||||
$$\\ $$\\ $$\\ $$\\ $$\\
|
||||
$$ | $$ | \\__| $$ | $$ |
|
||||
$$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$$\\
|
||||
\\_$$ _| $$ __$$\\ $$ |$$ __$$\\ $$ __$$ |$$ | $$ | $$ |$$ __$$\\ $$ __$$\\
|
||||
$$ | $$ | $$ |$$ |$$ | \\__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
|
||||
$$ |$$\\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
|
||||
\\$$$$ |$$ | $$ |$$ |$$ | \\$$$$$$$ |\\$$$$$\\$$$$ |\\$$$$$$$\\ $$$$$$$ |
|
||||
\\____/ \\__| \\__|\\__|\\__| \\_______| \\_____\\____/ \\_______|\\_______/ `);
|
||||
console.info(`\n 💎 thirdweb-cli v${cliVersion} 💎\n`);
|
||||
import("update-notifier").then(({ default: updateNotifier }) => {
|
||||
updateNotifier({
|
||||
pkg,
|
||||
shouldNotifyInNpmScript: true,
|
||||
// check every time while we're still building the CLI
|
||||
updateCheckInterval: 0,
|
||||
}).notify();
|
||||
});
|
||||
// yes this has to look like this, eliminates whitespace
|
||||
if (!skipIntro) {
|
||||
console.info(`
|
||||
$$\\ $$\\ $$\\ $$\\ $$\\
|
||||
$$ | $$ | \\__| $$ | $$ |
|
||||
$$$$$$\\ $$$$$$$\\ $$\\ $$$$$$\\ $$$$$$$ |$$\\ $$\\ $$\\ $$$$$$\\ $$$$$$$\\
|
||||
\\_$$ _| $$ __$$\\ $$ |$$ __$$\\ $$ __$$ |$$ | $$ | $$ |$$ __$$\\ $$ __$$\\
|
||||
$$ | $$ | $$ |$$ |$$ | \\__|$$ / $$ |$$ | $$ | $$ |$$$$$$$$ |$$ | $$ |
|
||||
$$ |$$\\ $$ | $$ |$$ |$$ | $$ | $$ |$$ | $$ | $$ |$$ ____|$$ | $$ |
|
||||
\\$$$$ |$$ | $$ |$$ |$$ | \\$$$$$$$ |\\$$$$$\\$$$$ |\\$$$$$$$\\ $$$$$$$ |
|
||||
\\____/ \\__| \\__|\\__|\\__| \\_______| \\_____\\____/ \\_______|\\_______/ `);
|
||||
console.info(`\n 💎 thirdweb-cli v${cliVersion} 💎\n`);
|
||||
}
|
||||
|
||||
program
|
||||
.name("thirdweb-cli")
|
||||
@@ -198,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();
|
||||
};
|
||||
|
||||
|
||||
@@ -72,13 +72,13 @@ export async function detectExtensions(options: any) {
|
||||
const enabledFeatures: Feature[] = features.enabledFeatures.map(
|
||||
(feature) => ({
|
||||
name: feature.name,
|
||||
reference: `https://portal.thirdweb.com/extensions/${feature.name.toLowerCase()}`,
|
||||
reference: `https://portal.thirdweb.com/interfaces/${feature.name.toLowerCase()}`,
|
||||
}),
|
||||
);
|
||||
const suggestedFeatures: Feature[] = features.suggestedFeatures.map(
|
||||
(feature) => ({
|
||||
name: feature.name,
|
||||
reference: `https://portal.thirdweb.com/extensions/${feature.name.toLowerCase()}`,
|
||||
reference: `https://portal.thirdweb.com/interfaces/${feature.name.toLowerCase()}`,
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -259,16 +259,16 @@ export async function twCreate(
|
||||
framework = res.framework.trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!framework) {
|
||||
console.log("Please specify a framework");
|
||||
process.exit(1);
|
||||
}
|
||||
if (!framework) {
|
||||
console.log("Please specify a framework");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
if (!language) {
|
||||
// Default = JavaScript
|
||||
language = "javascript";
|
||||
if (!language) {
|
||||
// Default = JavaScript
|
||||
language = "javascript";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
@@ -218,5 +219,19 @@ export async function createContractProject({
|
||||
console.log();
|
||||
console.log(chalk.cyan(" cd"), cdpath);
|
||||
console.log();
|
||||
|
||||
if (framework === "forge") {
|
||||
const isInstalled = await hasForge();
|
||||
|
||||
if (!isInstalled) {
|
||||
console.log(
|
||||
`\n${chalk.yellowBright(
|
||||
`warning`,
|
||||
)} You don't have forge installed on this machine, and will need it to run this project! \n\nYou can install forge by following these instructions:\n${chalk.blueBright(
|
||||
`https://book.getfoundry.sh/getting-started/installation`,
|
||||
)}\n`,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
import { exec } from "child_process";
|
||||
|
||||
export async function hasForge() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
return await new Promise((resolve, reject) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
exec("forge --version", (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
resolve(false);
|
||||
}
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
/* eslint-disable import/no-extraneous-dependencies */
|
||||
import { runCommand } from "./run-command";
|
||||
import { rm, writeFile } from "node:fs/promises";
|
||||
|
||||
/**
|
||||
* Spawn a package manager installation with either Yarn or NPM.
|
||||
@@ -8,12 +9,12 @@ import { runCommand } from "./run-command";
|
||||
*/
|
||||
export async function submodules(): Promise<void> {
|
||||
// Remove script folder because it clashes with contract templates (and not needed with deploy)
|
||||
await runCommand("rm", ["-rf", "script"]);
|
||||
await rm("script", { recursive: true, force: true });
|
||||
|
||||
// Reset and recursively add forge submodules
|
||||
await runCommand("rm", ["-rf", ".gitmodules"]);
|
||||
await runCommand("rm", ["-rf", "lib"]);
|
||||
await runCommand("touch", [".gitmodules"]);
|
||||
await rm(".gitmodules", { recursive: true, force: true });
|
||||
await rm("lib", { recursive: true, force: true });
|
||||
await writeFile(".gitmodules", "");
|
||||
await runCommand("git", [
|
||||
"submodule",
|
||||
"add",
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
import { exec } from "child_process";
|
||||
|
||||
type PackageManager = "npm" | "yarn" | "pnpm";
|
||||
|
||||
interface Installation {
|
||||
packageManager: PackageManager;
|
||||
isGlobal: boolean;
|
||||
}
|
||||
|
||||
export async function findPackageInstallation(): Promise<
|
||||
Installation | undefined
|
||||
> {
|
||||
const isLocal = await isInstalledLocally();
|
||||
if (isLocal) {
|
||||
const packageManager = await import("detect-package-manager").then(
|
||||
({ detect }) => {
|
||||
return detect();
|
||||
},
|
||||
);
|
||||
|
||||
return { packageManager, isGlobal: false };
|
||||
}
|
||||
|
||||
const isGlobalNpm = await isInstalledGloballyWithNpm();
|
||||
if (isGlobalNpm) {
|
||||
return { packageManager: "npm", isGlobal: true };
|
||||
}
|
||||
|
||||
const isGlobalYarn = await isInstalledGloballyWithYarn();
|
||||
if (isGlobalYarn) {
|
||||
return { packageManager: "yarn", isGlobal: true };
|
||||
}
|
||||
|
||||
const isGlobalPnpm = await isInstalledGloballyWithPnpm();
|
||||
if (isGlobalPnpm) {
|
||||
return { packageManager: "pnpm", isGlobal: true };
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// For LOCAL packages, npm ls picks up things installed by yarn and pnpm too
|
||||
async function isInstalledLocally(): Promise<boolean> {
|
||||
const packages = await detectPackages("npm ls --depth=0");
|
||||
return containsThirdweb(packages || []);
|
||||
}
|
||||
|
||||
// But for GLOBAL packages, we need to use a separate command for each one
|
||||
async function isInstalledGloballyWithNpm(): Promise<boolean> {
|
||||
const packages = await detectPackages("npm ls -g --depth=0");
|
||||
return containsThirdweb(packages || []);
|
||||
}
|
||||
|
||||
async function isInstalledGloballyWithYarn(): Promise<boolean> {
|
||||
const packages = await detectPackages("yarn --cwd `yarn global dir` list");
|
||||
return containsThirdweb(packages || []);
|
||||
}
|
||||
|
||||
async function isInstalledGloballyWithPnpm(): Promise<boolean> {
|
||||
const packages: string[] = await new Promise((resolve) => {
|
||||
exec(`pnpm list -g --depth=0`, (err, stdout) => {
|
||||
var pkgs: string[] = [];
|
||||
pkgs = stdout.split("dependencies:")[1]?.trim().split("\n") || [];
|
||||
pkgs = pkgs.map((pkg) => pkg.replace(" ", "@"));
|
||||
resolve(pkgs);
|
||||
});
|
||||
});
|
||||
return containsThirdweb(packages || []);
|
||||
}
|
||||
|
||||
function containsThirdweb(packages: string[]) {
|
||||
return packages.some((pkg) => pkg.match(/^thirdweb/));
|
||||
}
|
||||
|
||||
async function detectPackages(cmd: string): Promise<string[]> {
|
||||
return new Promise((resolve) => {
|
||||
exec(cmd, (err, stdout) => {
|
||||
var packages: string[] = [];
|
||||
packages = stdout.split("\n");
|
||||
// We're one short on '-' to support both yarn and npm
|
||||
packages = packages.filter(function (item) {
|
||||
if (item.match(/^├─.+/g) !== null) {
|
||||
return true;
|
||||
}
|
||||
if (item.match(/^└─.+/g) !== null) {
|
||||
return true;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
packages = packages
|
||||
.map(function (item) {
|
||||
if (item.match(/^├─.+/g) !== null) {
|
||||
return item.replace(/(^├──\s|^├─\s)/g, "");
|
||||
}
|
||||
if (item.match(/^└─.+/g) !== null) {
|
||||
return item.replace(/(^└──\s|^├─\s)/g, "");
|
||||
}
|
||||
})
|
||||
.filter((item) => !!item) as string[];
|
||||
resolve(packages);
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -1,5 +1,15 @@
|
||||
# @thirdweb-dev/contracts-js
|
||||
|
||||
## 1.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#463](https://github.com/thirdweb-dev/js/pull/463) [`557429b`](https://github.com/thirdweb-dev/js/commit/557429b5cfb3af2983ee01cf7d12d41ee0557593) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - PackVRF contract
|
||||
|
||||
- [#311](https://github.com/thirdweb-dev/js/pull/311) [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Update to v3.3.0 of contracts package
|
||||
|
||||
- [#311](https://github.com/thirdweb-dev/js/pull/311) [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Update to 3.1.10 of contracts package
|
||||
|
||||
## 1.2.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryLogic__factory.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryLogic__factory.esm.js"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryRouter__factory.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryRouter__factory.esm.js"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryStorage__factory.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js-factories-TWMultichainRegistryStorage__factory.esm.js"
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-contracts-js-factories-TWRegistryLegacy__factory.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js-factories-TWRegistryLegacy__factory.esm.js"
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/contracts-js",
|
||||
"version": "1.2.2",
|
||||
"version": "1.2.3",
|
||||
"main": "dist/thirdweb-dev-contracts-js.cjs.js",
|
||||
"module": "dist/thirdweb-dev-contracts-js.esm.js",
|
||||
"license": "Apache-2.0",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/contracts-js",
|
||||
"dependencies": {
|
||||
"@thirdweb-dev/contracts": "3.2.8-0"
|
||||
"@thirdweb-dev/contracts": "3.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/preset-env": "^7.18.10",
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 3.6.10
|
||||
|
||||
## 3.6.9
|
||||
|
||||
## 3.6.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#454](https://github.com/thirdweb-dev/js/pull/454) [`c673e39`](https://github.com/thirdweb-dev/js/commit/c673e39f23ef082097d73d62910580e8fad400a0) Thanks [@jnsdls](https://github.com/jnsdls)! - upgraded dependencies
|
||||
|
||||
- [#422](https://github.com/thirdweb-dev/js/pull/422) [`08d04fe`](https://github.com/thirdweb-dev/js/commit/08d04fe4dc74ba0d12625d7d4004c23f7dc330a2) Thanks [@yehia67](https://github.com/yehia67)! - Add `btnTitle` prop to the `ConnectWallet` component. Now you can set customized string or child component to the connect button.
|
||||
|
||||
## 3.6.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#448](https://github.com/thirdweb-dev/js/pull/448) [`7a37e56`](https://github.com/thirdweb-dev/js/commit/7a37e564fd5d5a9df84c8da44ecaf6c42f67a0e2) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - allow `useContract` to fail faster to enable the import case
|
||||
|
||||
## 3.6.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#443](https://github.com/thirdweb-dev/js/pull/443) [`8c6cdaa`](https://github.com/thirdweb-dev/js/commit/8c6cdaa2887fb2cc40d3ee6991233d195d103805) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix magic link connector not connecting to the right chain
|
||||
|
||||
## 3.6.5
|
||||
|
||||
## 3.6.4
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.6.5",
|
||||
"version": "3.6.10",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -97,19 +97,19 @@
|
||||
"dependencies": {
|
||||
"@emotion/react": "^11.10.0",
|
||||
"@emotion/styled": "^11.10.0",
|
||||
"@gnosis.pm/safe-core-sdk": "^3.1.1",
|
||||
"@gnosis.pm/safe-ethers-adapters": "0.1.0-alpha.11",
|
||||
"@gnosis.pm/safe-ethers-lib": "^1.6.1",
|
||||
"@react-icons/all-files": "^4.1.0",
|
||||
"@safe-global/safe-core-sdk": "^3.2.0",
|
||||
"@safe-global/safe-ethers-adapters": "0.1.0-alpha.13",
|
||||
"@safe-global/safe-ethers-lib": "^1.7.0",
|
||||
"@solana/wallet-adapter-phantom": "^0.9.17",
|
||||
"@tanstack/react-query": "^4.0.10",
|
||||
"@zag-js/menu": "^0.1.16",
|
||||
"@zag-js/react": "^0.1.18",
|
||||
"@zag-js/menu": "^0.3.0",
|
||||
"@zag-js/react": "^0.3.1",
|
||||
"buffer": "^6.0.3",
|
||||
"color": "^4.2.3",
|
||||
"copy-to-clipboard": "^3.3.2",
|
||||
"detect-browser": "^5.3.0",
|
||||
"magic-sdk": "^8.1.1",
|
||||
"magic-sdk": "^10.1.0",
|
||||
"mime": "^3.0.0",
|
||||
"react-cool-dimensions": "^2.0.7",
|
||||
"tiny-invariant": "^1.2.0",
|
||||
|
||||
@@ -63,6 +63,7 @@ interface ConnectWalletProps extends ThemeProviderProps {
|
||||
loginOptional?: boolean;
|
||||
};
|
||||
className?: string;
|
||||
btnTitle?: JSX.Element | string;
|
||||
}
|
||||
|
||||
let connecting = false;
|
||||
@@ -120,6 +121,7 @@ const chainIdToCurrencyMap: Record<
|
||||
export const ConnectWallet: React.FC<ConnectWalletProps> = ({
|
||||
auth,
|
||||
className,
|
||||
btnTitle,
|
||||
...themeProps
|
||||
}) => {
|
||||
const id = useId();
|
||||
@@ -248,7 +250,9 @@ export const ConnectWallet: React.FC<ConnectWalletProps> = ({
|
||||
</span>
|
||||
)
|
||||
) : (
|
||||
<span style={{ whiteSpace: "nowrap" }}>Connect Wallet</span>
|
||||
<span style={{ whiteSpace: "nowrap" }}>
|
||||
{btnTitle || "Connect Wallet"}
|
||||
</span>
|
||||
)}
|
||||
</Button>
|
||||
|
||||
|
||||
@@ -98,9 +98,9 @@ export class GnosisSafeConnector extends Connector {
|
||||
invariant(serverUrl, "Chain not supported");
|
||||
|
||||
const [safeEthersAdapters, safeCoreSdk, safeEthersLib] = await Promise.all([
|
||||
import("@gnosis.pm/safe-ethers-adapters"),
|
||||
import("@gnosis.pm/safe-core-sdk"),
|
||||
import("@gnosis.pm/safe-ethers-lib"),
|
||||
import("@safe-global/safe-ethers-adapters"),
|
||||
import("@safe-global/safe-core-sdk"),
|
||||
import("@safe-global/safe-ethers-lib"),
|
||||
]);
|
||||
|
||||
const ethAdapter = new safeEthersLib.default({
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
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,68 @@
|
||||
# @thirdweb-dev/sdk
|
||||
|
||||
## 3.6.10
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#498](https://github.com/thirdweb-dev/js/pull/498) [`5fba324`](https://github.com/thirdweb-dev/js/commit/5fba324ac17ab02bc8f13d82a232bc5c6970c8e5) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix claim condition detection on legacy contracts
|
||||
|
||||
- [#502](https://github.com/thirdweb-dev/js/pull/502) [`894cbef`](https://github.com/thirdweb-dev/js/commit/894cbefc6361f23fc528a6c6819f5c71793d46e4) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add intermediate event for contract deploy transactions before confirmation
|
||||
|
||||
- [#463](https://github.com/thirdweb-dev/js/pull/463) [`557429b`](https://github.com/thirdweb-dev/js/commit/557429b5cfb3af2983ee01cf7d12d41ee0557593) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - PackVRF integration
|
||||
|
||||
- [#500](https://github.com/thirdweb-dev/js/pull/500) [`73dc026`](https://github.com/thirdweb-dev/js/commit/73dc026ff9d0ac9099bd5a9a9cab8fdbfc0ae723) Thanks [@retocrooman](https://github.com/retocrooman)! - Getting the domain separator is not a required function. If an error occurs there, the permit it self will not be possible. Therefore, error handling should be performed appropriately.
|
||||
|
||||
- [#311](https://github.com/thirdweb-dev/js/pull/311) [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Add support for multi chain registry
|
||||
|
||||
- [#491](https://github.com/thirdweb-dev/js/pull/491) [`68c8e3c`](https://github.com/thirdweb-dev/js/commit/68c8e3c4d79f5d56dc4414241bcca0d88285fcca) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Use multichain registry to resolve contracts that cannot be resolved via IPFS
|
||||
|
||||
- [#494](https://github.com/thirdweb-dev/js/pull/494) [`bff433e`](https://github.com/thirdweb-dev/js/commit/bff433e12150dc029e33a578219c8437a510da99) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix deploy transaction listener for all deploy types `sdk.deployer.addDeployListener()`
|
||||
|
||||
- Updated dependencies [[`557429b`](https://github.com/thirdweb-dev/js/commit/557429b5cfb3af2983ee01cf7d12d41ee0557593), [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857), [`9eaa21d`](https://github.com/thirdweb-dev/js/commit/9eaa21d09ab9c700aea61a2a25f8ca9859d20857)]:
|
||||
- @thirdweb-dev/contracts-js@1.2.3
|
||||
|
||||
## 3.6.9
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#465](https://github.com/thirdweb-dev/js/pull/465) [`e913e0d`](https://github.com/thirdweb-dev/js/commit/e913e0daa9ece9a6274f7ffa4e66bdcbf32e6ada) Thanks [@adam-maj](https://github.com/adam-maj)! - Fix passing options to factory
|
||||
|
||||
- [`5862c55`](https://github.com/thirdweb-dev/js/commit/5862c558fb48604b5aca4defd1ccc06fc3536358) Thanks [@kumaryash90](https://github.com/kumaryash90)! - update forwarder address
|
||||
|
||||
- [#466](https://github.com/thirdweb-dev/js/pull/466) [`73883f5`](https://github.com/thirdweb-dev/js/commit/73883f56d0ed0a35ace8b98b96caa782443be22e) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - workaround for signing typed data with magic.link signers
|
||||
|
||||
- [#468](https://github.com/thirdweb-dev/js/pull/468) [`f7a74a3`](https://github.com/thirdweb-dev/js/commit/f7a74a3b7c489ada5b1ec435632a326334a33c9b) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Expose `sdk.wallet.signTypedData()`
|
||||
|
||||
## 3.6.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#454](https://github.com/thirdweb-dev/js/pull/454) [`c673e39`](https://github.com/thirdweb-dev/js/commit/c673e39f23ef082097d73d62910580e8fad400a0) Thanks [@jnsdls](https://github.com/jnsdls)! - upgraded dependencies
|
||||
|
||||
- [#421](https://github.com/thirdweb-dev/js/pull/421) [`ea95c5f`](https://github.com/thirdweb-dev/js/commit/ea95c5f609e306e333ee0f73f7920503358ca848) Thanks [@yehia67](https://github.com/yehia67)! - Add new utilities to parse/format currencies. `toEther` & `toWei` as default 18 decimal and `toUnits` & `toDisplayValue` in case of different numbers of decimals.
|
||||
|
||||
- [#456](https://github.com/thirdweb-dev/js/pull/456) [`699a2b1`](https://github.com/thirdweb-dev/js/commit/699a2b16fb991c474ec57db8f178e2601d631f39) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SOL] Fix claiming drops with custom currencies
|
||||
|
||||
- [#458](https://github.com/thirdweb-dev/js/pull/458) [`4cdd0bd`](https://github.com/thirdweb-dev/js/commit/4cdd0bd6348494a256d7c6a2bdf8f7b5c20f6877) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fixes for latest wallet package integration
|
||||
|
||||
- [#453](https://github.com/thirdweb-dev/js/pull/453) [`a8267f9`](https://github.com/thirdweb-dev/js/commit/a8267f912df84c58d3fe3f47b90bd474f73c84ca) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - [SOL] Drop fixes for large batch uploads
|
||||
|
||||
## 3.6.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#451](https://github.com/thirdweb-dev/js/pull/451) [`3731459`](https://github.com/thirdweb-dev/js/commit/3731459d33f1ded7ebb69124809449b901b3ad3d) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Less strict prebuilt checks to support OSRF variants
|
||||
|
||||
- [#450](https://github.com/thirdweb-dev/js/pull/450) [`cac6c30`](https://github.com/thirdweb-dev/js/commit/cac6c30bca5e17df81d746ef81316af47d5e252e) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix setting allowance or approvals gaslessly
|
||||
|
||||
- [#448](https://github.com/thirdweb-dev/js/pull/448) [`7a37e56`](https://github.com/thirdweb-dev/js/commit/7a37e564fd5d5a9df84c8da44ecaf6c42f67a0e2) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - allow `useContract` to fail faster to enable the import case
|
||||
|
||||
## 3.6.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#443](https://github.com/thirdweb-dev/js/pull/443) [`8c6cdaa`](https://github.com/thirdweb-dev/js/commit/8c6cdaa2887fb2cc40d3ee6991233d195d103805) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fix signature minting from OpenSea Royalty Filter NFT collection contracts
|
||||
|
||||
## 3.6.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/sdk",
|
||||
"version": "3.6.5",
|
||||
"version": "3.6.10",
|
||||
"description": "The main thirdweb SDK.",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
|
||||
"license": "Apache-2.0",
|
||||
@@ -62,7 +62,7 @@
|
||||
"build": "tsc && preconstruct build",
|
||||
"test:evm:all": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/evm/.mocharc.json' --timeout 30000 --parallel './test/evm/**/*.test.ts'",
|
||||
"test:evm": "make test-evm",
|
||||
"test:evm:single": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/evm/.mocharc.json' --timeout 30000",
|
||||
"test:evm:single": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/evm/.mocharc.json' --timeout 90000",
|
||||
"node:solana:start": "DEBUG='amman:(info|error|debug)' amman start --forceClone",
|
||||
"node:solana:stop": "amman stop",
|
||||
"test:solana:all": "SWC_NODE_PROJECT=./tsconfig.test.json mocha --config './test/solana/.mocharc.json' --timeout 30000 --parallel './test/solana/**/*.test.ts'",
|
||||
@@ -85,7 +85,7 @@
|
||||
"@types/deep-equal-in-any-order": "^1.0.1",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/uuid": "^8.3.3",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.0",
|
||||
"@typescript-eslint/parser": "^5.33.0",
|
||||
"chai": "^4.3.6",
|
||||
@@ -146,4 +146,4 @@
|
||||
"url": "https://github.com/thirdweb-dev/js/issues"
|
||||
},
|
||||
"author": "thirdweb eng <[email protected]>"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
export const DEFAULT_API_KEY =
|
||||
"c6634ad2d97b74baf15ff556016830c251050e6c36b9da508ce3ec80095d3dc1";
|
||||
|
||||
export function getRpcUrl(network: string) {
|
||||
return `https://${network}.rpc.thirdweb.com/${DEFAULT_API_KEY}`;
|
||||
export function getRpcUrl(network: string, apikey = DEFAULT_API_KEY) {
|
||||
return `https://${network}.rpc.thirdweb.com/${apikey}`;
|
||||
}
|
||||
|
||||
@@ -124,7 +124,7 @@ export async function setErc20Allowance(
|
||||
signer || provider,
|
||||
currencyAddress,
|
||||
ERC20Abi,
|
||||
{},
|
||||
contractToApprove.options,
|
||||
);
|
||||
|
||||
const owner = await contractToApprove.getSignerAddress();
|
||||
@@ -151,7 +151,7 @@ export async function approveErc20Allowance(
|
||||
signer || provider,
|
||||
currencyAddress,
|
||||
ERC20Abi,
|
||||
{},
|
||||
contractToApprove.options,
|
||||
);
|
||||
const owner = await contractToApprove.getSignerAddress();
|
||||
const spender = contractToApprove.readContract.address;
|
||||
@@ -192,3 +192,19 @@ export async function normalizeAmount(
|
||||
const decimals = await contractWrapper.readContract.decimals();
|
||||
return utils.parseUnits(AmountSchema.parse(amount), decimals);
|
||||
}
|
||||
|
||||
export function toEther(amount: BigNumberish): string {
|
||||
return utils.formatEther(amount);
|
||||
}
|
||||
|
||||
export function toWei(amount: Amount): BigNumber {
|
||||
return utils.parseEther(AmountSchema.parse(amount));
|
||||
}
|
||||
|
||||
export function toUnits(amount: Amount, decimals: BigNumberish): BigNumber {
|
||||
return utils.parseUnits(AmountSchema.parse(amount), decimals);
|
||||
}
|
||||
|
||||
export function toDisplayValue(amount: BigNumberish, decimals: BigNumberish): string {
|
||||
return utils.formatUnits(amount, decimals);
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@ export class TransactionError extends Error {
|
||||
raw: string,
|
||||
functionInfo: FunctionInfo | undefined,
|
||||
) {
|
||||
let builtErrorMsg = "Contract transaction failed\n\n";
|
||||
let builtErrorMsg = "\n| Contract transaction failed |\n\n";
|
||||
builtErrorMsg += `Message: ${reason}`;
|
||||
builtErrorMsg += "\n\n| Transaction info |\n";
|
||||
builtErrorMsg += withSpaces("from", from);
|
||||
@@ -320,9 +320,6 @@ export class TransactionError extends Error {
|
||||
// ignore if can't parse URL
|
||||
}
|
||||
builtErrorMsg += "\n\n";
|
||||
builtErrorMsg +=
|
||||
"Need help with this error? Join our community: https://discord.gg/thirdweb";
|
||||
builtErrorMsg += "\n\n\n\n";
|
||||
builtErrorMsg += "| Raw error |";
|
||||
builtErrorMsg += "\n\n";
|
||||
builtErrorMsg += raw;
|
||||
@@ -401,9 +398,19 @@ export async function convertToTWError(
|
||||
// not sure what this is, just throw it back
|
||||
raw = error.toString();
|
||||
}
|
||||
const reason =
|
||||
let reason =
|
||||
parseMessageParts(/.*?"message[^a-zA-Z0-9]*([^"\\]*).*?/, raw) ||
|
||||
parseMessageParts(/.*?"reason[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
|
||||
if (reason && reason.toLowerCase().includes("cannot estimate gas")) {
|
||||
// the error might be in the next reason block
|
||||
const nextReason = parseMessageParts(
|
||||
/.*?"reason[^a-zA-Z0-9]*([^"\\]*).*?/,
|
||||
raw.slice(raw.indexOf(reason) + reason.length),
|
||||
);
|
||||
if (nextReason) {
|
||||
reason = nextReason;
|
||||
}
|
||||
}
|
||||
const data = parseMessageParts(/.*?"data[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
|
||||
const rpcUrl = parseMessageParts(/.*?"url[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
|
||||
let from = parseMessageParts(/.*?"from[^a-zA-Z0-9]*([^"\\]*).*?/, raw);
|
||||
|
||||
@@ -13,16 +13,14 @@ import {
|
||||
AbiFunction,
|
||||
AbiSchema,
|
||||
AbiTypeSchema,
|
||||
ContractInfoSchema,
|
||||
ContractSource,
|
||||
FullPublishMetadata,
|
||||
FullPublishMetadataSchemaOutput,
|
||||
PreDeployMetadata,
|
||||
PreDeployMetadataFetched,
|
||||
PreDeployMetadataFetchedSchema,
|
||||
PublishedMetadata,
|
||||
} from "../schema/contracts/custom";
|
||||
import { ExtensionNotImplementedError } from "./error";
|
||||
import { fetchContractMetadata } from "./metadata-resolver";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import bs58 from "bs58";
|
||||
import { BaseContract, BigNumber, ethers } from "ethers";
|
||||
@@ -411,104 +409,6 @@ function isHexStrict(hex: string | number) {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param address
|
||||
* @param provider
|
||||
* @param storage
|
||||
*/
|
||||
export async function fetchContractMetadataFromAddress(
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) {
|
||||
const compilerMetadataUri = await resolveContractUriFromAddress(
|
||||
address,
|
||||
provider,
|
||||
);
|
||||
if (!compilerMetadataUri) {
|
||||
throw new Error(`Could not resolve metadata for contract at ${address}`);
|
||||
}
|
||||
return await fetchContractMetadata(compilerMetadataUri, storage);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param compilerMetadataUri
|
||||
* @param storage
|
||||
*/
|
||||
export async function fetchContractMetadata(
|
||||
compilerMetadataUri: string,
|
||||
storage: ThirdwebStorage,
|
||||
): Promise<PublishedMetadata> {
|
||||
const metadata = await storage.downloadJSON(compilerMetadataUri);
|
||||
const abi = AbiSchema.parse(metadata.output.abi);
|
||||
const compilationTarget = metadata.settings.compilationTarget;
|
||||
const targets = Object.keys(compilationTarget);
|
||||
const name = compilationTarget[targets[0]];
|
||||
const info = ContractInfoSchema.parse({
|
||||
title: metadata.output.devdoc.title,
|
||||
author: metadata.output.devdoc.author,
|
||||
details: metadata.output.devdoc.detail,
|
||||
notice: metadata.output.userdoc.notice,
|
||||
});
|
||||
const licenses: string[] = [
|
||||
...new Set(
|
||||
Object.entries(metadata.sources).map(([, src]) => (src as any).license),
|
||||
),
|
||||
];
|
||||
return {
|
||||
name,
|
||||
abi,
|
||||
metadata,
|
||||
info,
|
||||
licenses,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param publishedMetadata
|
||||
* @param storage
|
||||
*/
|
||||
export async function fetchSourceFilesFromMetadata(
|
||||
publishedMetadata: PublishedMetadata,
|
||||
storage: ThirdwebStorage,
|
||||
): Promise<ContractSource[]> {
|
||||
return await Promise.all(
|
||||
Object.entries(publishedMetadata.metadata.sources).map(
|
||||
async ([path, info]) => {
|
||||
const urls = (info as any).urls as string[];
|
||||
const ipfsLink = urls
|
||||
? urls.find((url) => url.includes("ipfs"))
|
||||
: undefined;
|
||||
if (ipfsLink) {
|
||||
const ipfsHash = ipfsLink.split("ipfs/")[1];
|
||||
// 5 sec timeout for sources that haven't been uploaded to ipfs
|
||||
const timeout = new Promise<string>((_r, rej) =>
|
||||
setTimeout(() => rej("timeout"), 5000),
|
||||
);
|
||||
const source = await Promise.race([
|
||||
(await storage.download(`ipfs://${ipfsHash}`)).text(),
|
||||
timeout,
|
||||
]);
|
||||
return {
|
||||
filename: path,
|
||||
source,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
filename: path,
|
||||
source:
|
||||
(info as any).content ||
|
||||
"Could not find source for this contract",
|
||||
};
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param publishMetadataUri
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export * from "./error";
|
||||
export * from "./snapshots";
|
||||
export * from "./role";
|
||||
export * from "./metadata-resolver";
|
||||
export * from "./feature-detection";
|
||||
export * from "./version-checker";
|
||||
// export helpful util
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
InterfaceId_IERC1155,
|
||||
InterfaceId_IERC721,
|
||||
} from "../constants/contract";
|
||||
import { SignerOrProvider } from "../core";
|
||||
import { ContractWrapper } from "../core/classes/contract-wrapper";
|
||||
import {
|
||||
NewAuctionListing,
|
||||
@@ -76,33 +75,38 @@ export async function isTokenApprovedForTransfer(
|
||||
/**
|
||||
* Checks if the marketplace is approved to make transfers on the assetContract
|
||||
* If not, it tries to set the approval.
|
||||
* @param signerOrProvider
|
||||
* @param contractWrapper
|
||||
* @param marketplaceAddress
|
||||
* @param assetContract
|
||||
* @param tokenId
|
||||
* @param from
|
||||
*/
|
||||
export async function handleTokenApproval(
|
||||
signerOrProvider: SignerOrProvider,
|
||||
contractWrapper: ContractWrapper<any>,
|
||||
marketplaceAddress: string,
|
||||
assetContract: string,
|
||||
tokenId: BigNumberish,
|
||||
from: string,
|
||||
): Promise<void> {
|
||||
const erc165 = new Contract(
|
||||
const erc165 = new ContractWrapper<IERC165>(
|
||||
contractWrapper.getSignerOrProvider(),
|
||||
assetContract,
|
||||
ERC165Abi,
|
||||
signerOrProvider,
|
||||
) as IERC165;
|
||||
const isERC721 = await erc165.supportsInterface(InterfaceId_IERC721);
|
||||
const isERC1155 = await erc165.supportsInterface(InterfaceId_IERC1155);
|
||||
contractWrapper.options,
|
||||
);
|
||||
const isERC721 = await erc165.readContract.supportsInterface(
|
||||
InterfaceId_IERC721,
|
||||
);
|
||||
const isERC1155 = await erc165.readContract.supportsInterface(
|
||||
InterfaceId_IERC1155,
|
||||
);
|
||||
// check for token approval
|
||||
if (isERC721) {
|
||||
const asset = new ContractWrapper<IERC721>(
|
||||
signerOrProvider,
|
||||
contractWrapper.getSignerOrProvider(),
|
||||
assetContract,
|
||||
ERC721Abi,
|
||||
{},
|
||||
contractWrapper.options,
|
||||
);
|
||||
const approved = await asset.readContract.isApprovedForAll(
|
||||
from,
|
||||
@@ -122,10 +126,10 @@ export async function handleTokenApproval(
|
||||
}
|
||||
} else if (isERC1155) {
|
||||
const asset = new ContractWrapper<IERC1155>(
|
||||
signerOrProvider,
|
||||
contractWrapper.getSignerOrProvider(),
|
||||
assetContract,
|
||||
ERC1155Abi,
|
||||
{},
|
||||
contractWrapper.options,
|
||||
);
|
||||
|
||||
const approved = await asset.readContract.isApprovedForAll(
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
import { ThirdwebSDK } from "../core";
|
||||
import {
|
||||
Abi,
|
||||
PublishedMetadata,
|
||||
AbiSchema,
|
||||
ContractInfoSchema,
|
||||
ContractSource,
|
||||
} from "../schema";
|
||||
import { resolveContractUriFromAddress } from "./feature-detection";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { providers } from "ethers";
|
||||
|
||||
// Internal static cache
|
||||
const metadataCache: Record<string, PublishedMetadata> = {};
|
||||
// polygonSDK to fetch metadata from the multichain registry
|
||||
const polygonSDK = new ThirdwebSDK("polygon");
|
||||
|
||||
function getCacheKey(address: string, chainId: number) {
|
||||
return `${address}-${chainId}`;
|
||||
}
|
||||
|
||||
function putInCache(
|
||||
address: string,
|
||||
chainId: number,
|
||||
metadata: PublishedMetadata,
|
||||
) {
|
||||
metadataCache[getCacheKey(address, chainId)] = metadata;
|
||||
}
|
||||
|
||||
function getFromCache(address: string, chainId: number) {
|
||||
return metadataCache[getCacheKey(address, chainId)];
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param address
|
||||
* @param provider
|
||||
* @param storage
|
||||
*/
|
||||
export async function fetchContractMetadataFromAddress(
|
||||
address: string,
|
||||
provider: providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) {
|
||||
const chainId = (await provider.getNetwork()).chainId;
|
||||
const cached = getFromCache(address, chainId);
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
let metadata: PublishedMetadata | undefined;
|
||||
try {
|
||||
const compilerMetadataUri = await resolveContractUriFromAddress(
|
||||
address,
|
||||
provider,
|
||||
);
|
||||
if (!compilerMetadataUri) {
|
||||
throw new Error(`Could not resolve metadata for contract at ${address}`);
|
||||
}
|
||||
metadata = await fetchContractMetadata(compilerMetadataUri, storage);
|
||||
} catch (e) {
|
||||
try {
|
||||
// try from multichain registry
|
||||
const importedUri =
|
||||
await polygonSDK.multiChainRegistry.getContractMetadataURI(
|
||||
chainId,
|
||||
address,
|
||||
);
|
||||
metadata = await fetchContractMetadata(importedUri, storage);
|
||||
} catch (err) {
|
||||
throw new Error(`Could not resolve metadata for contract at ${address}`);
|
||||
}
|
||||
}
|
||||
if (!metadata) {
|
||||
throw new Error(`Could not resolve metadata for contract at ${address}`);
|
||||
}
|
||||
putInCache(address, chainId, metadata);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param address
|
||||
* @param provider
|
||||
* @param storage
|
||||
* @returns
|
||||
*/
|
||||
export async function fetchAbiFromAddress(
|
||||
address: string,
|
||||
provider: providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
): Promise<Abi | undefined> {
|
||||
try {
|
||||
const metadata = await fetchContractMetadataFromAddress(
|
||||
address,
|
||||
provider,
|
||||
storage,
|
||||
);
|
||||
if (metadata && metadata.abi) {
|
||||
return metadata.abi;
|
||||
}
|
||||
} catch (e) {
|
||||
// ignore and return undefined
|
||||
// will fallback to embedded ABIs for prebuilts
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param compilerMetadataUri
|
||||
* @param storage
|
||||
*/
|
||||
export async function fetchContractMetadata(
|
||||
compilerMetadataUri: string,
|
||||
storage: ThirdwebStorage,
|
||||
): Promise<PublishedMetadata> {
|
||||
const metadata = await storage.downloadJSON(compilerMetadataUri);
|
||||
if (!metadata || !metadata.output) {
|
||||
throw new Error(
|
||||
`Could not resolve metadata for contract at ${compilerMetadataUri}`,
|
||||
);
|
||||
}
|
||||
const abi = AbiSchema.parse(metadata.output.abi);
|
||||
const compilationTarget = metadata.settings.compilationTarget;
|
||||
const targets = Object.keys(compilationTarget);
|
||||
const name = compilationTarget[targets[0]];
|
||||
const info = ContractInfoSchema.parse({
|
||||
title: metadata.output.devdoc.title,
|
||||
author: metadata.output.devdoc.author,
|
||||
details: metadata.output.devdoc.detail,
|
||||
notice: metadata.output.userdoc.notice,
|
||||
});
|
||||
const licenses: string[] = [
|
||||
...new Set(
|
||||
Object.entries(metadata.sources).map(([, src]) => (src as any).license),
|
||||
),
|
||||
];
|
||||
return {
|
||||
name,
|
||||
abi,
|
||||
metadata,
|
||||
info,
|
||||
licenses,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @param publishedMetadata
|
||||
* @param storage
|
||||
*/
|
||||
export async function fetchSourceFilesFromMetadata(
|
||||
publishedMetadata: PublishedMetadata,
|
||||
storage: ThirdwebStorage,
|
||||
): Promise<ContractSource[]> {
|
||||
return await Promise.all(
|
||||
Object.entries(publishedMetadata.metadata.sources).map(
|
||||
async ([path, info]) => {
|
||||
const urls = (info as any).urls as string[];
|
||||
const ipfsLink = urls
|
||||
? urls.find((url) => url.includes("ipfs"))
|
||||
: undefined;
|
||||
if (ipfsLink) {
|
||||
const ipfsHash = ipfsLink.split("ipfs/")[1];
|
||||
// 3 sec timeout for sources that haven't been uploaded to ipfs
|
||||
const timeout = new Promise<string>((_r, rej) =>
|
||||
setTimeout(() => rej("timeout"), 3000),
|
||||
);
|
||||
const source = await Promise.race([
|
||||
(await storage.download(`ipfs://${ipfsHash}`)).text(),
|
||||
timeout,
|
||||
]);
|
||||
return {
|
||||
filename: path,
|
||||
source,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
filename: path,
|
||||
source:
|
||||
(info as any).content ||
|
||||
"Could not find source for this contract",
|
||||
};
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -71,7 +71,14 @@ async function getDomainSeperator(signer: Signer, contractAddress: string) {
|
||||
try {
|
||||
return await contract.DOMAIN_SEPARATOR();
|
||||
} catch (err) {
|
||||
return await contract.getDomainSeperator();
|
||||
try {
|
||||
return await contract.getDomainSeperator();
|
||||
} catch (err2) {
|
||||
console.error(
|
||||
'Error getting domain separator',
|
||||
err2
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ export async function signTypedDataInternal(
|
||||
);
|
||||
|
||||
let signature = "";
|
||||
const signerAddress = (await signer.getAddress()).toLowerCase();
|
||||
|
||||
// an indirect way for accessing walletconnect's underlying provider
|
||||
if ((provider as any)?.provider?.isWalletConnect) {
|
||||
@@ -66,11 +67,19 @@ export async function signTypedDataInternal(
|
||||
} catch (err: any) {
|
||||
if (err?.message?.includes("Method eth_signTypedData_v4 not supported")) {
|
||||
signature = await provider.send("eth_signTypedData", [
|
||||
(await signer.getAddress()).toLowerCase(),
|
||||
signerAddress,
|
||||
JSON.stringify(payload),
|
||||
]);
|
||||
} else {
|
||||
throw err;
|
||||
// magic.link signer only supports this way
|
||||
try {
|
||||
await provider.send("eth_signTypedData_v4", [
|
||||
signerAddress,
|
||||
JSON.stringify(payload),
|
||||
]);
|
||||
} catch (finalErr: any) {
|
||||
throw finalErr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ export const OZ_DEFENDER_FORWARDER_ADDRESS =
|
||||
const TWRegistry_address = "0x7c487845f98938Bb955B1D5AD069d9a30e4131fd";
|
||||
const TWFactory_address = "0x5DBC7B840baa9daBcBe9D2492E45D7244B54A2A0";
|
||||
const ContractPublisher_address = "0x664244560eBa21Bf82d7150C791bE1AbcD5B4cd7"; // Polygon only
|
||||
const MultichainRegistry_address = "0xcdAD8FA86e18538aC207872E8ff3536501431B73"; // Polygon only
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@@ -92,7 +93,7 @@ export const CONTRACT_ADDRESSES: Record<
|
||||
twBYOCRegistry: "0x3E6eE864f850F5e5A98bc950B68E181Cf4010F23",
|
||||
},
|
||||
[ChainId.Arbitrum]: {
|
||||
openzeppelinForwarder: OZ_DEFENDER_FORWARDER_ADDRESS,
|
||||
openzeppelinForwarder: "0x8cbc8B5d71702032904750A66AEfE8B603eBC538",
|
||||
openzeppelinForwarderEOA: "0x4f247c69184ad61036EC2Bb3213b69F10FbEDe1F",
|
||||
biconomyForwarder: "0xfe0fa3C06d03bDC7fb49c892BbB39113B534fB57",
|
||||
twFactory: "0xd24b3de085CFd8c54b94feAD08a7962D343E6DE0",
|
||||
@@ -109,7 +110,7 @@ export const CONTRACT_ADDRESSES: Record<
|
||||
twBYOCRegistry: constants.AddressZero,
|
||||
},
|
||||
[ChainId.Optimism]: {
|
||||
openzeppelinForwarder: OZ_DEFENDER_FORWARDER_ADDRESS,
|
||||
openzeppelinForwarder: "0x8cbc8B5d71702032904750A66AEfE8B603eBC538",
|
||||
openzeppelinForwarderEOA: "0x7e80648EB2071E26937F9D42A513ccf4815fc702",
|
||||
biconomyForwarder: "0xefba8a2a82ec1fb1273806174f5e28fbb917cf95",
|
||||
twFactory: "0xd24b3de085CFd8c54b94feAD08a7962D343E6DE0",
|
||||
@@ -291,6 +292,19 @@ export function getContractPublisherAddress() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export function getMultichainRegistryAddress() {
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
if (process.env.multiChainRegistryAddress) {
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
return process.env.multiChainRegistryAddress as string;
|
||||
} else {
|
||||
return MultichainRegistry_address;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param chainId - chain id
|
||||
|
||||
@@ -53,6 +53,7 @@ import {
|
||||
FEATURE_ROYALTY,
|
||||
FEATURE_APPURI,
|
||||
FEATURE_GASLESS,
|
||||
FEATURE_PACK_VRF,
|
||||
} from "./thirdweb-features";
|
||||
|
||||
/**
|
||||
@@ -106,7 +107,8 @@ export type Feature =
|
||||
| typeof FEATURE_METADATA
|
||||
| typeof FEATURE_APPURI
|
||||
| typeof FEATURE_OWNER
|
||||
| typeof FEATURE_GASLESS;
|
||||
| typeof FEATURE_GASLESS
|
||||
| typeof FEATURE_PACK_VRF;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@@ -135,4 +137,5 @@ export const SUPPORTED_FEATURES: Record<string, Feature> = {
|
||||
[FEATURE_APPURI.name]: FEATURE_APPURI,
|
||||
[FEATURE_OWNER.name]: FEATURE_OWNER,
|
||||
[FEATURE_GASLESS.name]: FEATURE_GASLESS,
|
||||
[FEATURE_PACK_VRF.name]: FEATURE_PACK_VRF,
|
||||
};
|
||||
|
||||
@@ -176,3 +176,16 @@ export const NATIVE_TOKENS: Record<
|
||||
export function getNativeTokenByChainId(chainId: ChainId): NativeToken {
|
||||
return NATIVE_TOKENS[chainId as SUPPORTED_CHAIN_ID];
|
||||
}
|
||||
|
||||
export const LINK_TOKEN_ADDRESS: Record<number, string> = {
|
||||
[ChainId.Mainnet]: "0x514910771AF9Ca656af840dff83E8264EcF986CA",
|
||||
[ChainId.Goerli]: "0x326C977E6efc84E512bB9C30f76E30c160eD06FB",
|
||||
[ChainId.BinanceSmartChainMainnet]:
|
||||
"0x404460C6A5EdE2D891e8297795264fDe62ADBB75",
|
||||
[ChainId.Polygon]: "0xb0897686c545045aFc77CF20eC7A532E3120E0F1",
|
||||
[ChainId.Mumbai]: "0x326C977E6efc84E512bB9C30f76E30c160eD06FB",
|
||||
[ChainId.Avalanche]: "0x5947BB275c521040051D82396192181b413227A3",
|
||||
[ChainId.AvalancheFujiTestnet]: "0x0b9d5D9136855f6FEc3c0993feE6E9CE8a297846",
|
||||
[ChainId.Fantom]: "0x6F43FF82CCA38001B6699a8AC47A2d0E66939407",
|
||||
[ChainId.FantomTestnet]: "0xfaFedb041c0DD4fA2Dc0d87a6B0979Ee6FA7af5F",
|
||||
};
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import DropERC1155_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/DropERC1155_V2.json";
|
||||
import IBurnableERC1155Abi from "@thirdweb-dev/contracts-js/dist/abis/IBurnableERC1155.json";
|
||||
import IClaimableERC1155 from "@thirdweb-dev/contracts-js/dist/abis/IClaimableERC1155.json";
|
||||
import DelayedRevealAbi from "@thirdweb-dev/contracts-js/dist/abis/IDelayedReveal.json";
|
||||
import IDropMultiPhase1155 from "@thirdweb-dev/contracts-js/dist/abis/IDrop1155.json";
|
||||
import DropERC1155_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/IDropERC1155_V2.json";
|
||||
import IDropSinglePhase1155 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase1155.json";
|
||||
import IDropSinglePhase1155_V1 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase1155_V1.json";
|
||||
import Erc1155Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC1155.json";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import DropERC20_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/DropERC20_V2.json";
|
||||
import IBurnableERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IBurnableERC20.json";
|
||||
import IDrop from "@thirdweb-dev/contracts-js/dist/abis/IDrop.json";
|
||||
import DropERC20_V2Abi from "@thirdweb-dev/contracts-js/dist/abis/IDropERC20_V2.json";
|
||||
import IDropSinglePhase from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase.json";
|
||||
import IDropSinglePhaseV1 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase_V1.json";
|
||||
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import DropERC721_V3Abi from "@thirdweb-dev/contracts-js/dist/abis/DropERC721_V3.json";
|
||||
import IBurnableERC721Abi from "@thirdweb-dev/contracts-js/dist/abis/IBurnableERC721.json";
|
||||
import IClaimableERC721 from "@thirdweb-dev/contracts-js/dist/abis/IClaimableERC721.json";
|
||||
import DelayedRevealAbi from "@thirdweb-dev/contracts-js/dist/abis/IDelayedReveal.json";
|
||||
import IDrop from "@thirdweb-dev/contracts-js/dist/abis/IDrop.json";
|
||||
import DropERC721_V3Abi from "@thirdweb-dev/contracts-js/dist/abis/IDropERC721_V3.json";
|
||||
import IDropSinglePhase from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase.json";
|
||||
import IDropSinglePhaseV1 from "@thirdweb-dev/contracts-js/dist/abis/IDropSinglePhase_V1.json";
|
||||
import Erc721Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC721.json";
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import IERC2771ContextAbi from "@thirdweb-dev/contracts-js/dist/abis/ERC2771Context.json";
|
||||
import IAppURI from "@thirdweb-dev/contracts-js/dist/abis/IAppURI.json";
|
||||
import IContractMetadataAbi from "@thirdweb-dev/contracts-js/dist/abis/IContractMetadata.json";
|
||||
import IPackVRFAbi from "@thirdweb-dev/contracts-js/dist/abis/IPackVRFDirect.json";
|
||||
import IPermissionsAbi from "@thirdweb-dev/contracts-js/dist/abis/IPermissions.json";
|
||||
import IPermissionsEnumerableAbi from "@thirdweb-dev/contracts-js/dist/abis/IPermissionsEnumerable.json";
|
||||
import IThirdwebPlatformFeeAbi from "@thirdweb-dev/contracts-js/dist/abis/IPlatformFee.json";
|
||||
@@ -109,3 +110,14 @@ export const FEATURE_GASLESS = {
|
||||
abis: [IERC2771ContextAbi],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_PACK_VRF = {
|
||||
name: "PackVRF",
|
||||
namespace: "pack.vrf",
|
||||
docLinks: {
|
||||
sdk: "sdk.packvrf",
|
||||
contracts: "IPackVRFDirect",
|
||||
},
|
||||
abis: [IPackVRFAbi],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
@@ -168,3 +168,21 @@ export function getReadOnlyProvider(network: string, chainId?: number) {
|
||||
return ethers.getDefaultProvider(network);
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const ChainIdToName: Record<number, string> = {
|
||||
[ChainId.Polygon]: "polygon",
|
||||
[ChainId.Mumbai]: "mumbai",
|
||||
[ChainId.Goerli]: "goerli",
|
||||
[ChainId.Mainnet]: "mainnet",
|
||||
[ChainId.Optimism]: "optimism",
|
||||
[ChainId.OptimismGoerli]: "optimism-goerli",
|
||||
[ChainId.Arbitrum]: "arbitrum",
|
||||
[ChainId.ArbitrumGoerli]: "arbitrum-goerli",
|
||||
[ChainId.Fantom]: "fantom",
|
||||
[ChainId.FantomTestnet]: "fantom-testnet",
|
||||
[ChainId.Avalanche]: "avalanche",
|
||||
[ChainId.AvalancheFujiTestnet]: "avalanche-fuji",
|
||||
[ChainId.BinanceSmartChainMainnet]: "binance",
|
||||
[ChainId.BinanceSmartChainTestnet]: "binance-testnet",
|
||||
};
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import { getPrebuiltInfo } from "../common/legacy";
|
||||
import { fetchAbiFromAddress } from "../common/metadata-resolver";
|
||||
import { ALL_ROLES } from "../common/role";
|
||||
import { getSignerAndProvider } from "../core/classes/rpc-connection-handler";
|
||||
import type {
|
||||
@@ -18,10 +20,10 @@ import {
|
||||
TokenErc721ContractSchema,
|
||||
VoteContractSchema,
|
||||
} from "../schema";
|
||||
import { CustomContractSchema } from "../schema/contracts/custom";
|
||||
import { Abi, CustomContractSchema } from "../schema/contracts/custom";
|
||||
import { DropErc20ContractSchema } from "../schema/contracts/drop-erc20";
|
||||
import { MultiwrapContractSchema } from "../schema/contracts/multiwrap";
|
||||
import type { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { ethers } from "ethers";
|
||||
|
||||
type InitalizeParams = [
|
||||
@@ -41,7 +43,7 @@ export const EditionDropInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
await EditionDropInitializer.getAbi(address, provider),
|
||||
await EditionDropInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/edition-drop"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -55,13 +57,18 @@ export const EditionDropInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
const contractInfo = await assertContractType(
|
||||
address,
|
||||
provider,
|
||||
"edition-drop",
|
||||
);
|
||||
return contractInfo.version > 2
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
const contractInfo = await getContractInfo(address, provider);
|
||||
return !contractInfo || contractInfo.version > 2
|
||||
? (await import("@thirdweb-dev/contracts-js/dist/abis/DropERC1155.json"))
|
||||
.default
|
||||
: (
|
||||
@@ -82,7 +89,7 @@ export const EditionInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
EditionInitializer.getAbi(address, provider),
|
||||
EditionInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/edition"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -96,8 +103,16 @@ export const EditionInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
await assertContractType(address, provider, "edition");
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
return (
|
||||
await import("@thirdweb-dev/contracts-js/dist/abis/TokenERC1155.json")
|
||||
).default;
|
||||
@@ -114,7 +129,7 @@ export const MarketplaceInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
MarketplaceInitializer.getAbi(address, provider),
|
||||
MarketplaceInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/marketplace"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -128,8 +143,16 @@ export const MarketplaceInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
await assertContractType(address, provider, "marketplace");
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
return (
|
||||
await import("@thirdweb-dev/contracts-js/dist/abis/Marketplace.json")
|
||||
).default;
|
||||
@@ -146,7 +169,7 @@ export const MultiwrapInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
MultiwrapInitializer.getAbi(address, provider),
|
||||
MultiwrapInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/multiwrap"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -160,8 +183,16 @@ export const MultiwrapInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
await assertContractType(address, provider, "multiwrap");
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
return (await import("@thirdweb-dev/contracts-js/dist/abis/Multiwrap.json"))
|
||||
.default;
|
||||
},
|
||||
@@ -178,7 +209,7 @@ export const NFTCollectionInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
NFTCollectionInitializer.getAbi(address, provider),
|
||||
NFTCollectionInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/nft-collection"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -192,8 +223,16 @@ export const NFTCollectionInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
await assertContractType(address, provider, "nft-collection");
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
return (
|
||||
await import("@thirdweb-dev/contracts-js/dist/abis/TokenERC721.json")
|
||||
).default;
|
||||
@@ -210,7 +249,7 @@ export const NFTDropInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
NFTDropInitializer.getAbi(address, provider),
|
||||
NFTDropInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/nft-drop"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -224,13 +263,18 @@ export const NFTDropInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
const contractInfo = await assertContractType(
|
||||
address,
|
||||
provider,
|
||||
"nft-drop",
|
||||
);
|
||||
return contractInfo.version > 3
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
const contractInfo = await getContractInfo(address, provider);
|
||||
return !contractInfo || contractInfo.version > 3
|
||||
? (await import("@thirdweb-dev/contracts-js/dist/abis/DropERC721.json"))
|
||||
.default
|
||||
: (
|
||||
@@ -252,7 +296,7 @@ export const PackInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
PackInitializer.getAbi(address, provider),
|
||||
PackInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/pack"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -266,8 +310,16 @@ export const PackInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
await assertContractType(address, provider, "pack");
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
): Promise<Abi> => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
return (await import("@thirdweb-dev/contracts-js/dist/abis/Pack.json"))
|
||||
.default;
|
||||
},
|
||||
@@ -284,7 +336,7 @@ export const SignatureDropInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
SignatureDropInitializer.getAbi(address, provider),
|
||||
SignatureDropInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/signature-drop"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -298,13 +350,18 @@ export const SignatureDropInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
const contractInfo = await assertContractType(
|
||||
address,
|
||||
provider,
|
||||
"signature-drop",
|
||||
);
|
||||
return contractInfo.version > 4
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
const contractInfo = await getContractInfo(address, provider);
|
||||
return !contractInfo || contractInfo.version > 4
|
||||
? (
|
||||
await import(
|
||||
"@thirdweb-dev/contracts-js/dist/abis/SignatureDrop.json"
|
||||
@@ -329,7 +386,7 @@ export const SplitInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
SplitInitializer.getAbi(address, provider),
|
||||
SplitInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/split"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -343,8 +400,16 @@ export const SplitInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
await assertContractType(address, provider, "split");
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
return (await import("@thirdweb-dev/contracts-js/dist/abis/Split.json"))
|
||||
.default;
|
||||
},
|
||||
@@ -361,7 +426,7 @@ export const TokenDropInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
TokenDropInitializer.getAbi(address, provider),
|
||||
TokenDropInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/token-drop"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -375,13 +440,18 @@ export const TokenDropInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
const contractInfo = await assertContractType(
|
||||
address,
|
||||
provider,
|
||||
"token-drop",
|
||||
);
|
||||
return contractInfo.version > 2
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
const contractInfo = await getContractInfo(address, provider);
|
||||
return !contractInfo || contractInfo.version > 2
|
||||
? (await import("@thirdweb-dev/contracts-js/dist/abis/DropERC20.json"))
|
||||
.default
|
||||
: (await import("@thirdweb-dev/contracts-js/dist/abis/DropERC20_V2.json"))
|
||||
@@ -399,7 +469,7 @@ export const TokenInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
TokenInitializer.getAbi(address, provider),
|
||||
TokenInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/token"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -413,8 +483,16 @@ export const TokenInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
await assertContractType(address, provider, "token");
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
return (
|
||||
await import("@thirdweb-dev/contracts-js/dist/abis/TokenERC20.json")
|
||||
).default;
|
||||
@@ -432,7 +510,7 @@ export const VoteInitializer = {
|
||||
) => {
|
||||
const [, provider] = getSignerAndProvider(network, options);
|
||||
const [abi, contract, _network] = await Promise.all([
|
||||
VoteInitializer.getAbi(address, provider),
|
||||
VoteInitializer.getAbi(address, provider, storage),
|
||||
import("./prebuilt-implementations/vote"),
|
||||
provider.getNetwork(),
|
||||
]);
|
||||
@@ -446,23 +524,30 @@ export const VoteInitializer = {
|
||||
_network.chainId,
|
||||
);
|
||||
},
|
||||
getAbi: async (address: string, provider: ethers.providers.Provider) => {
|
||||
await assertContractType(address, provider, "vote");
|
||||
getAbi: async (
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
storage: ThirdwebStorage,
|
||||
) => {
|
||||
const abi = await fetchAbiFromAddress(address, provider, storage);
|
||||
if (abi) {
|
||||
return abi;
|
||||
}
|
||||
// Deprecated - only needed for backwards compatibility with non-released contracts - should remove in v4
|
||||
return (await import("@thirdweb-dev/contracts-js/dist/abis/VoteERC20.json"))
|
||||
.default;
|
||||
},
|
||||
};
|
||||
|
||||
async function assertContractType(
|
||||
async function getContractInfo(
|
||||
address: string,
|
||||
provider: ethers.providers.Provider,
|
||||
type: PrebuiltContractType,
|
||||
) {
|
||||
const contractInfo = await getPrebuiltInfo(address, provider);
|
||||
if (!contractInfo || contractInfo.type !== getContractName(type)) {
|
||||
throw new Error(`Contract is not a ${type}`);
|
||||
try {
|
||||
return await getPrebuiltInfo(address, provider);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
return contractInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -487,7 +572,7 @@ export const PREBUILT_CONTRACTS_MAP = {
|
||||
const SmartContract = {
|
||||
name: "SmartContract" as const,
|
||||
contractType: "custom" as const,
|
||||
schema: CustomContractSchema,
|
||||
schema: {},
|
||||
roles: ALL_ROLES,
|
||||
};
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ import {
|
||||
TransactionResultWithId,
|
||||
} from "../../core/types";
|
||||
import { PaperCheckout } from "../../integrations/thirdweb-checkout";
|
||||
import { Abi } from "../../schema/contracts/custom";
|
||||
import { DropErc1155ContractSchema } from "../../schema/contracts/drop-erc1155";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { PrebuiltEditionDrop } from "../../types/eips";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/DropERC1155.json";
|
||||
import { ThirdwebStorage, UploadProgressEvent } from "@thirdweb-dev/storage";
|
||||
import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
|
||||
|
||||
@@ -47,7 +47,7 @@ import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
|
||||
export class EditionDrop extends StandardErc1155<PrebuiltEditionDrop> {
|
||||
private static contractRoles = ["admin", "minter", "transfer"] as const;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public sales: ContractPrimarySale<PrebuiltEditionDrop>;
|
||||
public platformFees: ContractPlatformFee<PrebuiltEditionDrop>;
|
||||
public encoder: ContractEncoder<PrebuiltEditionDrop>;
|
||||
@@ -124,7 +124,7 @@ export class EditionDrop extends StandardErc1155<PrebuiltEditionDrop> {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<PrebuiltEditionDrop>(
|
||||
network,
|
||||
|
||||
@@ -20,11 +20,11 @@ import {
|
||||
TransactionResult,
|
||||
TransactionResultWithId,
|
||||
} from "../../core/types";
|
||||
import { Abi } from "../../schema/contracts/custom";
|
||||
import { TokenErc1155ContractSchema } from "../../schema/contracts/token-erc1155";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { EditionMetadataOrUri } from "../../schema/tokens/edition";
|
||||
import type { TokenERC1155 } from "@thirdweb-dev/contracts-js";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/TokenERC1155.json";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
|
||||
|
||||
@@ -45,7 +45,7 @@ import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
|
||||
export class Edition extends StandardErc1155<TokenERC1155> {
|
||||
static contractRoles = ["admin", "minter", "transfer"] as const;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public metadata: ContractMetadata<
|
||||
TokenERC1155,
|
||||
typeof TokenErc1155ContractSchema
|
||||
@@ -104,7 +104,7 @@ export class Edition extends StandardErc1155<TokenERC1155> {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<TokenERC1155>(
|
||||
network,
|
||||
|
||||
@@ -17,6 +17,7 @@ import { MarketplaceDirect } from "../../core/classes/marketplace-direct";
|
||||
import { UpdateableNetwork } from "../../core/interfaces/contract";
|
||||
import { NetworkOrSignerOrProvider, TransactionResult } from "../../core/types";
|
||||
import { ListingType } from "../../enums";
|
||||
import { Abi } from "../../schema/contracts/custom";
|
||||
import { MarketplaceContractSchema } from "../../schema/contracts/marketplace";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { Price } from "../../types/currency";
|
||||
@@ -24,7 +25,6 @@ import { AuctionListing, DirectListing, Offer } from "../../types/marketplace";
|
||||
import { MarketplaceFilter } from "../../types/marketplace/MarketPlaceFilter";
|
||||
import { UnmappedOffer } from "../../types/marketplace/UnmappedOffer";
|
||||
import type { Marketplace as MarketplaceContract } from "@thirdweb-dev/contracts-js";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/Marketplace.json";
|
||||
import { NewOfferEventObject } from "@thirdweb-dev/contracts-js/dist/declarations/src/Marketplace";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
|
||||
@@ -47,7 +47,7 @@ import invariant from "tiny-invariant";
|
||||
export class Marketplace implements UpdateableNetwork {
|
||||
static contractRoles = ["admin", "lister", "asset"] as const;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
private contractWrapper: ContractWrapper<MarketplaceContract>;
|
||||
private storage: ThirdwebStorage;
|
||||
|
||||
@@ -148,7 +148,7 @@ export class Marketplace implements UpdateableNetwork {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<MarketplaceContract>(
|
||||
network,
|
||||
|
||||
@@ -20,7 +20,7 @@ import {
|
||||
TransactionResult,
|
||||
TransactionResultWithId,
|
||||
} from "../../core/types";
|
||||
import { SDKOptions } from "../../schema";
|
||||
import { Abi, SDKOptions } from "../../schema";
|
||||
import { MultiwrapContractSchema } from "../../schema/contracts/multiwrap";
|
||||
import {
|
||||
ERC1155Wrappable,
|
||||
@@ -30,7 +30,6 @@ import {
|
||||
WrappedTokens,
|
||||
} from "../../types/multiwrap";
|
||||
import type { Multiwrap as MultiwrapContract } from "@thirdweb-dev/contracts-js";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/Multiwrap.json";
|
||||
import {
|
||||
ITokenBundle,
|
||||
TokensWrappedEvent,
|
||||
@@ -61,7 +60,7 @@ export class Multiwrap extends StandardErc721<MultiwrapContract> {
|
||||
"asset",
|
||||
] as const;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public encoder: ContractEncoder<MultiwrapContract>;
|
||||
public estimator: GasCostEstimator<MultiwrapContract>;
|
||||
public metadata: ContractMetadata<
|
||||
@@ -102,7 +101,7 @@ export class Multiwrap extends StandardErc721<MultiwrapContract> {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<MultiwrapContract>(
|
||||
network,
|
||||
|
||||
@@ -19,10 +19,10 @@ import type {
|
||||
TransactionResult,
|
||||
TransactionResultWithId,
|
||||
} from "../../core/types";
|
||||
import { Abi } from "../../schema/contracts/custom";
|
||||
import { TokenErc721ContractSchema } from "../../schema/contracts/token-erc721";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import type { TokenERC721 } from "@thirdweb-dev/contracts-js";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/TokenERC721.json";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { BigNumberish, CallOverrides, constants } from "ethers";
|
||||
|
||||
@@ -43,7 +43,7 @@ import { BigNumberish, CallOverrides, constants } from "ethers";
|
||||
export class NFTCollection extends StandardErc721<TokenERC721> {
|
||||
static contractRoles = ["admin", "minter", "transfer"] as const;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public metadata: ContractMetadata<
|
||||
TokenERC721,
|
||||
typeof TokenErc721ContractSchema
|
||||
@@ -107,7 +107,7 @@ export class NFTCollection extends StandardErc721<TokenERC721> {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<TokenERC721>(
|
||||
network,
|
||||
|
||||
@@ -27,11 +27,11 @@ import {
|
||||
TransactionResultWithId,
|
||||
} from "../../core/types";
|
||||
import { PaperCheckout } from "../../integrations/thirdweb-checkout";
|
||||
import { Abi } from "../../schema/contracts/custom";
|
||||
import { DropErc721ContractSchema } from "../../schema/contracts/drop-erc721";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { PrebuiltNFTDrop } from "../../types/eips";
|
||||
import { UploadProgressEvent } from "../../types/events";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/DropERC721.json";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
|
||||
|
||||
@@ -52,7 +52,7 @@ import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
|
||||
export class NFTDrop extends StandardErc721<PrebuiltNFTDrop> {
|
||||
static contractRoles = ["admin", "minter", "transfer"] as const;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public encoder: ContractEncoder<PrebuiltNFTDrop>;
|
||||
public estimator: GasCostEstimator<PrebuiltNFTDrop>;
|
||||
public metadata: ContractMetadata<
|
||||
@@ -161,7 +161,7 @@ export class NFTDrop extends StandardErc721<PrebuiltNFTDrop> {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<PrebuiltNFTDrop>(
|
||||
network,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { QueryAllParams } from "../../../core/schema/QueryParams";
|
||||
import { NFT } from "../../../core/schema/nft";
|
||||
import { assertEnabled, detectContractFeature } from "../../common";
|
||||
import {
|
||||
fetchCurrencyMetadata,
|
||||
hasERC20Allowance,
|
||||
@@ -8,6 +9,7 @@ import {
|
||||
import { isTokenApprovedForTransfer } from "../../common/marketplace";
|
||||
import { uploadOrExtractURI } from "../../common/nft";
|
||||
import { getRoleHash } from "../../common/role";
|
||||
import { FEATURE_PACK_VRF } from "../../constants/thirdweb-features";
|
||||
import { ContractEncoder } from "../../core/classes/contract-encoder";
|
||||
import { ContractEvents } from "../../core/classes/contract-events";
|
||||
import { ContractInterceptor } from "../../core/classes/contract-interceptor";
|
||||
@@ -19,10 +21,12 @@ import { ContractWrapper } from "../../core/classes/contract-wrapper";
|
||||
import { Erc1155 } from "../../core/classes/erc-1155";
|
||||
import { StandardErc1155 } from "../../core/classes/erc-1155-standard";
|
||||
import { GasCostEstimator } from "../../core/classes/gas-cost-estimator";
|
||||
import { PackVRF } from "../../core/classes/pack-vrf";
|
||||
import {
|
||||
NetworkOrSignerOrProvider,
|
||||
TransactionResultWithId,
|
||||
} from "../../core/types";
|
||||
import { Abi } from "../../schema";
|
||||
import { PackContractSchema } from "../../schema/contracts/packs";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import {
|
||||
@@ -32,8 +36,10 @@ import {
|
||||
PackRewardsOutput,
|
||||
PackRewardsOutputSchema,
|
||||
} from "../../schema/tokens/pack";
|
||||
import type { Pack as PackContract } from "@thirdweb-dev/contracts-js";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/Pack.json";
|
||||
import type {
|
||||
IPackVRFDirect,
|
||||
Pack as PackContract,
|
||||
} from "@thirdweb-dev/contracts-js";
|
||||
import { PackUpdatedEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/IPack";
|
||||
import {
|
||||
ITokenBundle,
|
||||
@@ -60,7 +66,7 @@ import { BigNumber, BigNumberish, CallOverrides, ethers } from "ethers";
|
||||
export class Pack extends StandardErc1155<PackContract> {
|
||||
static contractRoles = ["admin", "minter", "asset", "transfer"] as const;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public metadata: ContractMetadata<PackContract, typeof PackContractSchema>;
|
||||
public roles: ContractRoles<PackContract, typeof Pack.contractRoles[number]>;
|
||||
public encoder: ContractEncoder<PackContract>;
|
||||
@@ -92,12 +98,21 @@ export class Pack extends StandardErc1155<PackContract> {
|
||||
public erc1155: Erc1155<PackContract>;
|
||||
public owner: ContractOwner<PackContract>;
|
||||
|
||||
private _vrf?: PackVRF;
|
||||
|
||||
/**
|
||||
* If enabled in the contract, use the Chainlink VRF functionality to open packs
|
||||
*/
|
||||
get vrf(): PackVRF {
|
||||
return assertEnabled(this._vrf, FEATURE_PACK_VRF);
|
||||
}
|
||||
|
||||
constructor(
|
||||
network: NetworkOrSignerOrProvider,
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<PackContract>(
|
||||
network,
|
||||
@@ -131,6 +146,7 @@ export class Pack extends StandardErc1155<PackContract> {
|
||||
this.events = new ContractEvents(this.contractWrapper);
|
||||
this.interceptor = new ContractInterceptor(this.contractWrapper);
|
||||
this.owner = new ContractOwner(this.contractWrapper);
|
||||
this._vrf = this.detectVrf();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -138,6 +154,7 @@ export class Pack extends StandardErc1155<PackContract> {
|
||||
*/
|
||||
onNetworkUpdated(network: NetworkOrSignerOrProvider): void {
|
||||
this.contractWrapper.updateSignerOrProvider(network);
|
||||
this._vrf?.onNetworkUpdated(network);
|
||||
}
|
||||
|
||||
getAddress(): string {
|
||||
@@ -536,6 +553,11 @@ export class Pack extends StandardErc1155<PackContract> {
|
||||
tokenId: BigNumberish,
|
||||
amount: BigNumberish = 1,
|
||||
): Promise<PackRewards> {
|
||||
if (this._vrf) {
|
||||
throw new Error(
|
||||
"This contract is using Chainlink VRF, use `contract.vrf.open()` or `contract.vrf.openAndClaim()` instead",
|
||||
);
|
||||
}
|
||||
const receipt = await this.contractWrapper.sendTransaction(
|
||||
"openPack",
|
||||
[tokenId, amount],
|
||||
@@ -716,4 +738,19 @@ export class Pack extends StandardErc1155<PackContract> {
|
||||
): Promise<any> {
|
||||
return this.contractWrapper.call(functionName, ...args);
|
||||
}
|
||||
|
||||
private detectVrf() {
|
||||
if (
|
||||
detectContractFeature<IPackVRFDirect>(this.contractWrapper, "PackVRF")
|
||||
) {
|
||||
return new PackVRF(
|
||||
this.contractWrapper.getSignerOrProvider(),
|
||||
this.contractWrapper.readContract.address,
|
||||
this.storage,
|
||||
this.contractWrapper.options,
|
||||
this.chainId,
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@ import {
|
||||
TransactionResultWithId,
|
||||
} from "../../core/types";
|
||||
import { PaperCheckout } from "../../integrations/thirdweb-checkout";
|
||||
import { Abi } from "../../schema/contracts/custom";
|
||||
import { DropErc721ContractSchema } from "../../schema/contracts/drop-erc721";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { ClaimOptions, UploadProgressEvent } from "../../types";
|
||||
import type { SignatureDrop as SignatureDropContract } from "@thirdweb-dev/contracts-js";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/SignatureDrop.json";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
|
||||
|
||||
@@ -55,7 +55,7 @@ import { BigNumber, BigNumberish, CallOverrides, constants } from "ethers";
|
||||
export class SignatureDrop extends StandardErc721<SignatureDropContract> {
|
||||
static contractRoles = ["admin", "minter", "transfer"] as const;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public erc721: Erc721<SignatureDropContract>;
|
||||
public owner: ContractOwner<SignatureDropContract>;
|
||||
public encoder: ContractEncoder<SignatureDropContract>;
|
||||
@@ -171,7 +171,7 @@ export class SignatureDrop extends StandardErc721<SignatureDropContract> {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<SignatureDropContract>(
|
||||
network,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ContractWrapper } from "../../core/classes/contract-wrapper";
|
||||
import { GasCostEstimator } from "../../core/classes/gas-cost-estimator";
|
||||
import { UpdateableNetwork } from "../../core/interfaces/contract";
|
||||
import { NetworkOrSignerOrProvider, TransactionResult } from "../../core/types";
|
||||
import { Abi } from "../../schema/contracts/custom";
|
||||
import { SplitsContractSchema } from "../../schema/contracts/splits";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { SplitRecipient } from "../../types/SplitRecipient";
|
||||
@@ -17,7 +18,6 @@ import type {
|
||||
Split as SplitContract,
|
||||
} from "@thirdweb-dev/contracts-js";
|
||||
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/Split.json";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { BigNumber, CallOverrides, Contract } from "ethers";
|
||||
|
||||
@@ -41,7 +41,7 @@ export class Split implements UpdateableNetwork {
|
||||
private contractWrapper: ContractWrapper<SplitContract>;
|
||||
private storage: ThirdwebStorage;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public metadata: ContractMetadata<SplitContract, typeof SplitsContractSchema>;
|
||||
public encoder: ContractEncoder<SplitContract>;
|
||||
public estimator: GasCostEstimator<SplitContract>;
|
||||
@@ -65,7 +65,7 @@ export class Split implements UpdateableNetwork {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<SplitContract>(
|
||||
network,
|
||||
|
||||
@@ -11,11 +11,11 @@ import { DropClaimConditions } from "../../core/classes/drop-claim-conditions";
|
||||
import { StandardErc20 } from "../../core/classes/erc-20-standard";
|
||||
import { GasCostEstimator } from "../../core/classes/gas-cost-estimator";
|
||||
import { NetworkOrSignerOrProvider, TransactionResult } from "../../core/types";
|
||||
import { Abi } from "../../schema/contracts/custom";
|
||||
import { DropErc20ContractSchema } from "../../schema/contracts/drop-erc20";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { Amount, CurrencyValue } from "../../types";
|
||||
import { PrebuiltTokenDrop } from "../../types/eips";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/DropERC20.json";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { CallOverrides, constants } from "ethers";
|
||||
|
||||
@@ -35,7 +35,7 @@ import { CallOverrides, constants } from "ethers";
|
||||
export class TokenDrop extends StandardErc20<PrebuiltTokenDrop> {
|
||||
static contractRoles = ["admin", "transfer"] as const;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public metadata: ContractMetadata<
|
||||
PrebuiltTokenDrop,
|
||||
typeof DropErc20ContractSchema
|
||||
@@ -82,7 +82,7 @@ export class TokenDrop extends StandardErc20<PrebuiltTokenDrop> {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<PrebuiltTokenDrop>(
|
||||
network,
|
||||
|
||||
@@ -12,12 +12,12 @@ import { Erc20SignatureMintable } from "../../core/classes/erc-20-signature-mint
|
||||
import { StandardErc20 } from "../../core/classes/erc-20-standard";
|
||||
import { GasCostEstimator } from "../../core/classes/gas-cost-estimator";
|
||||
import { NetworkOrSignerOrProvider, TransactionResult } from "../../core/types";
|
||||
import { Abi } from "../../schema/contracts/custom";
|
||||
import { TokenErc20ContractSchema } from "../../schema/contracts/token-erc20";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { TokenMintInput } from "../../schema/tokens/token";
|
||||
import { Amount, CurrencyValue } from "../../types";
|
||||
import type { TokenERC20 } from "@thirdweb-dev/contracts-js";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/TokenERC20.json";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { CallOverrides, constants } from "ethers";
|
||||
|
||||
@@ -38,7 +38,7 @@ import { CallOverrides, constants } from "ethers";
|
||||
export class Token extends StandardErc20<TokenERC20> {
|
||||
static contractRoles = ["admin", "minter", "transfer"] as const;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public metadata: ContractMetadata<
|
||||
TokenERC20,
|
||||
typeof TokenErc20ContractSchema
|
||||
@@ -74,7 +74,7 @@ export class Token extends StandardErc20<TokenERC20> {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<TokenERC20>(
|
||||
network,
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
TransactionResultWithId,
|
||||
} from "../../core/types";
|
||||
import { VoteType } from "../../enums";
|
||||
import { Abi } from "../../schema";
|
||||
import { VoteContractSchema } from "../../schema/contracts/vote";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { CurrencyValue } from "../../types/currency";
|
||||
@@ -26,7 +27,6 @@ import {
|
||||
} from "../../types/vote";
|
||||
import type { IERC20, VoteERC20 } from "@thirdweb-dev/contracts-js";
|
||||
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
|
||||
import type ABI from "@thirdweb-dev/contracts-js/dist/abis/VoteERC20.json";
|
||||
import { ProposalCreatedEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/VoteERC20";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import {
|
||||
@@ -55,7 +55,7 @@ export class Vote implements UpdateableNetwork {
|
||||
private contractWrapper: ContractWrapper<VoteERC20>;
|
||||
private storage: ThirdwebStorage;
|
||||
|
||||
public abi: typeof ABI;
|
||||
public abi: Abi;
|
||||
public metadata: ContractMetadata<VoteERC20, typeof VoteContractSchema>;
|
||||
public encoder: ContractEncoder<VoteERC20>;
|
||||
public estimator: GasCostEstimator<VoteERC20>;
|
||||
@@ -75,7 +75,7 @@ export class Vote implements UpdateableNetwork {
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
abi: typeof ABI,
|
||||
abi: Abi,
|
||||
chainId: number,
|
||||
contractWrapper = new ContractWrapper<VoteERC20>(
|
||||
network,
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
fetchExtendedReleaseMetadata,
|
||||
fetchPreDeployMetadata,
|
||||
} from "../../common/index";
|
||||
import { ChainId } from "../../constants";
|
||||
import { ChainId, EventType } from "../../constants";
|
||||
import { getContractAddressByChainId } from "../../constants/addresses";
|
||||
import {
|
||||
EditionDropInitializer,
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
} from "../../contracts";
|
||||
import { FactoryDeploymentSchema } from "../../schema/contracts/custom";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { DeployEvent, DeployEvents } from "../../types";
|
||||
import {
|
||||
MarketplaceContractDeployMetadata,
|
||||
MultiwrapContractDeployMetadata,
|
||||
@@ -39,7 +40,6 @@ import {
|
||||
PrebuiltContractType,
|
||||
} from "../types";
|
||||
import { ContractFactory } from "./factory";
|
||||
import { FactoryEvents } from "./factory-events";
|
||||
import { ContractRegistry } from "./registry";
|
||||
import { RPCConnectionHandler } from "./rpc-connection-handler";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
@@ -50,6 +50,7 @@ import {
|
||||
ContractInterface,
|
||||
ethers,
|
||||
} from "ethers";
|
||||
import { EventEmitter } from "eventemitter3";
|
||||
import invariant from "tiny-invariant";
|
||||
import { z } from "zod";
|
||||
|
||||
@@ -68,8 +69,16 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
* should never be accessed directly, use {@link ContractDeployer.getRegistry} instead
|
||||
*/
|
||||
private _registry: Promise<ContractRegistry> | undefined;
|
||||
public events: FactoryEvents | undefined;
|
||||
private storage: ThirdwebStorage;
|
||||
private events: EventEmitter<DeployEvents>;
|
||||
private transactionListener = (event: any) => {
|
||||
if (event.status === "submitted") {
|
||||
this.events.emit("contractDeployed", {
|
||||
status: "submitted",
|
||||
transactionHash: event.transactionHash,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
constructor(
|
||||
network: NetworkOrSignerOrProvider,
|
||||
@@ -78,7 +87,7 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
) {
|
||||
super(network, options);
|
||||
this.storage = storage;
|
||||
|
||||
this.events = new EventEmitter();
|
||||
// Initialize factory and registry (we don't need to make these calls async)
|
||||
this.getFactory();
|
||||
this.getRegistry();
|
||||
@@ -427,7 +436,15 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
} catch (e) {
|
||||
parsedVersion = undefined;
|
||||
}
|
||||
return await factory.deploy(contractType, parsedMetadata, parsedVersion);
|
||||
factory.on(EventType.Transaction, this.transactionListener);
|
||||
const deployedAddress = await factory.deploy(
|
||||
contractType,
|
||||
parsedMetadata,
|
||||
this.events,
|
||||
parsedVersion,
|
||||
);
|
||||
factory.off(EventType.Transaction, this.transactionListener);
|
||||
return deployedAddress;
|
||||
}
|
||||
|
||||
//
|
||||
@@ -515,14 +532,18 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
factoryAddress,
|
||||
this.getSignerOrProvider(),
|
||||
this.storage,
|
||||
{},
|
||||
this.options,
|
||||
);
|
||||
return await proxyFactory.deployProxyByImplementation(
|
||||
proxyFactory.on(EventType.Transaction, this.transactionListener);
|
||||
const deployedAddress = await proxyFactory.deployProxyByImplementation(
|
||||
implementationAddress,
|
||||
implementationAbi,
|
||||
initializerFunction,
|
||||
initializerArgs,
|
||||
this.events,
|
||||
);
|
||||
proxyFactory.off(EventType.Transaction, this.transactionListener);
|
||||
return deployedAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -602,8 +623,6 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
this.storage,
|
||||
this.options,
|
||||
);
|
||||
this.events = new FactoryEvents(factory);
|
||||
|
||||
return factory;
|
||||
}));
|
||||
}
|
||||
@@ -800,8 +819,39 @@ export class ContractDeployer extends RPCConnectionHandler {
|
||||
const deployer = await new ethers.ContractFactory(abi, bytecode)
|
||||
.connect(signer)
|
||||
.deploy(...constructorParams);
|
||||
this.events.emit("contractDeployed", {
|
||||
status: "submitted",
|
||||
transactionHash: deployer.deployTransaction.hash,
|
||||
});
|
||||
const deployedContract = await deployer.deployed();
|
||||
// TODO parse transaction receipt
|
||||
this.events.emit("contractDeployed", {
|
||||
status: "completed",
|
||||
contractAddress: deployedContract.address,
|
||||
transactionHash: deployedContract.deployTransaction.hash,
|
||||
});
|
||||
return deployedContract.address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Listen to all deploy transactions from this deployer
|
||||
* @param listener the listener to add
|
||||
*/
|
||||
public addDeployListener(listener: (event: DeployEvent) => void) {
|
||||
this.events.on("contractDeployed", listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a deploy listener
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public removeDeployListener(listener: (event: DeployEvent) => void) {
|
||||
this.events.off("contractDeployed", listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all deploy listeners
|
||||
*/
|
||||
public removeAllDeployListeners() {
|
||||
this.events.removeAllListeners("contractDeployed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,11 @@ export class ContractEvents<TContract extends BaseContract> {
|
||||
const parsedLog =
|
||||
this.contractWrapper.readContract.interface.parseLog(log);
|
||||
listener(
|
||||
this.toContractEvent(parsedLog.eventFragment, parsedLog.args, log),
|
||||
this.toContractEvent<TEvent>(
|
||||
parsedLog.eventFragment,
|
||||
parsedLog.args,
|
||||
log,
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
@@ -333,15 +337,31 @@ export class ContractEvents<TContract extends BaseContract> {
|
||||
const results: Record<string, any> = {};
|
||||
event.inputs.forEach((param, index) => {
|
||||
if (Array.isArray(args[index])) {
|
||||
const obj: Record<string, unknown> = {};
|
||||
const components = param.components;
|
||||
if (components) {
|
||||
const arr = args[index];
|
||||
for (let i = 0; i < components.length; i++) {
|
||||
const name = components[i].name;
|
||||
obj[name] = arr[i];
|
||||
if (param.type === "tuple[]") {
|
||||
// tuple[]
|
||||
const objArray: Record<string, unknown>[] = [];
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
const tuple = arr[i];
|
||||
const obj: Record<string, unknown> = {};
|
||||
for (let j = 0; j < components.length; j++) {
|
||||
const name = components[j].name;
|
||||
obj[name] = tuple[j];
|
||||
}
|
||||
objArray.push(obj);
|
||||
}
|
||||
results[param.name] = objArray;
|
||||
} else {
|
||||
// simple tuple
|
||||
const obj: Record<string, unknown> = {};
|
||||
for (let i = 0; i < components.length; i++) {
|
||||
const name = components[i].name;
|
||||
obj[name] = arr[i];
|
||||
}
|
||||
results[param.name] = obj;
|
||||
}
|
||||
results[param.name] = obj;
|
||||
}
|
||||
} else {
|
||||
results[param.name] = args[index];
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import {
|
||||
detectContractFeature,
|
||||
ExtensionNotImplementedError,
|
||||
fetchContractMetadataFromAddress,
|
||||
hasFunction,
|
||||
fetchContractMetadataFromAddress,
|
||||
} from "../../common";
|
||||
import { FEATURE_METADATA } from "../../constants/thirdweb-features";
|
||||
import { DetectableFeature } from "../interfaces/DetectableFeature";
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
fetchRawPredeployMetadata,
|
||||
fetchSourceFilesFromMetadata,
|
||||
resolveContractUriFromAddress,
|
||||
} from "../../common/feature-detection";
|
||||
} from "../../common";
|
||||
import { isIncrementalVersion } from "../../common/version-checker";
|
||||
import { getContractPublisherAddress } from "../../constants";
|
||||
import {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { hasFunction } from "../../common";
|
||||
import { detectContractFeature } from "../../common";
|
||||
import { normalizePriceValue, setErc20Allowance } from "../../common/currency";
|
||||
import { uploadOrExtractURIs } from "../../common/nft";
|
||||
import { FEATURE_NFT_SIGNATURE_MINTABLE_V2 } from "../../constants/erc721-features";
|
||||
@@ -22,7 +22,7 @@ import type {
|
||||
} from "@thirdweb-dev/contracts-js";
|
||||
import { TokensMintedWithSignatureEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/SignatureDrop";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { BigNumber, ethers } from "ethers";
|
||||
import { BigNumber } from "ethers";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/**
|
||||
@@ -397,17 +397,9 @@ export class Erc721WithQuantitySignatureMintable implements DetectableFeature {
|
||||
}
|
||||
|
||||
private async isLegacyNFTContract() {
|
||||
if (hasFunction<TokenERC721>("contractType", this.contractWrapper)) {
|
||||
try {
|
||||
const contractType = ethers.utils.toUtf8String(
|
||||
await this.contractWrapper.readContract.contractType(),
|
||||
);
|
||||
return contractType.includes("TokenERC721");
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return detectContractFeature<ISignatureMintERC721>(
|
||||
this.contractWrapper,
|
||||
"ERC721SignatureMintV1",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
import { ContractEvents } from "./contract-events";
|
||||
import { ContractWrapper } from "./contract-wrapper";
|
||||
import type { TWFactory } from "@thirdweb-dev/contracts-js";
|
||||
import { ProxyDeployedEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/TWFactory";
|
||||
|
||||
interface DeployEvent {
|
||||
transactionHash: string;
|
||||
contractAddress: string;
|
||||
}
|
||||
|
||||
export class FactoryEvents extends ContractEvents<TWFactory> {
|
||||
constructor(contractWrapper: ContractWrapper<TWFactory>) {
|
||||
super(contractWrapper);
|
||||
}
|
||||
|
||||
public addDeployListener(listener: (event: DeployEvent) => void) {
|
||||
this.addTransactionListener(async (event) => {
|
||||
if (!event.transactionHash) {
|
||||
return;
|
||||
}
|
||||
|
||||
const receipt = await this.contractWrapper
|
||||
.getProvider()
|
||||
.getTransactionReceipt(event.transactionHash);
|
||||
const events = this.contractWrapper.parseLogs<ProxyDeployedEvent>(
|
||||
"ProxyDeployed",
|
||||
receipt.logs,
|
||||
);
|
||||
|
||||
if (events.length > 0) {
|
||||
listener({
|
||||
...event,
|
||||
contractAddress: events[0].args.proxy,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
VoteInitializer,
|
||||
} from "../../contracts";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { DeployEvents } from "../../types";
|
||||
import {
|
||||
DeploySchemaForPrebuiltContractType,
|
||||
NetworkOrSignerOrProvider,
|
||||
@@ -36,6 +37,7 @@ import {
|
||||
ContractInterface,
|
||||
ethers,
|
||||
} from "ethers";
|
||||
import { EventEmitter } from "eventemitter3";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
@@ -75,6 +77,7 @@ export class ContractFactory extends ContractWrapper<TWFactory> {
|
||||
contractMetadata: z.input<
|
||||
DeploySchemaForPrebuiltContractType<TContractType>
|
||||
>,
|
||||
eventEmitter: EventEmitter<DeployEvents>,
|
||||
version?: number,
|
||||
): Promise<string> {
|
||||
const contract = PREBUILT_CONTRACTS_MAP[contractType];
|
||||
@@ -98,6 +101,7 @@ export class ContractFactory extends ContractWrapper<TWFactory> {
|
||||
const ABI = await contract.getAbi(
|
||||
implementationAddress,
|
||||
this.getProvider(),
|
||||
this.storage,
|
||||
);
|
||||
|
||||
const encodedFunc = Contract.getInterface(ABI).encodeFunctionData(
|
||||
@@ -121,7 +125,14 @@ export class ContractFactory extends ContractWrapper<TWFactory> {
|
||||
throw new Error("No ProxyDeployed event found");
|
||||
}
|
||||
|
||||
return events[0].args.proxy;
|
||||
const contractAddress = events[0].args.proxy;
|
||||
eventEmitter.emit("contractDeployed", {
|
||||
status: "completed",
|
||||
contractAddress,
|
||||
transactionHash: receipt.transactionHash,
|
||||
});
|
||||
|
||||
return contractAddress;
|
||||
}
|
||||
|
||||
// TODO once IContractFactory is implemented, this can be probably be moved to its own class
|
||||
@@ -130,6 +141,7 @@ export class ContractFactory extends ContractWrapper<TWFactory> {
|
||||
implementationAbi: ContractInterface,
|
||||
initializerFunction: string,
|
||||
initializerArgs: any[],
|
||||
eventEmitter: EventEmitter<DeployEvents>,
|
||||
): Promise<string> {
|
||||
const encodedFunc = Contract.getInterface(
|
||||
implementationAbi,
|
||||
@@ -150,7 +162,14 @@ export class ContractFactory extends ContractWrapper<TWFactory> {
|
||||
throw new Error("No ProxyDeployed event found");
|
||||
}
|
||||
|
||||
return events[0].args.proxy;
|
||||
const contractAddress = events[0].args.proxy;
|
||||
eventEmitter.emit("contractDeployed", {
|
||||
status: "completed",
|
||||
contractAddress,
|
||||
transactionHash: receipt.transactionHash,
|
||||
});
|
||||
|
||||
return contractAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -207,7 +207,7 @@ export class MarketplaceAuction {
|
||||
validateNewListingParam(listing);
|
||||
|
||||
await handleTokenApproval(
|
||||
this.contractWrapper.getSignerOrProvider(),
|
||||
this.contractWrapper,
|
||||
this.getAddress(),
|
||||
listing.assetContractAddress,
|
||||
listing.tokenId,
|
||||
|
||||
@@ -162,7 +162,7 @@ export class MarketplaceDirect {
|
||||
validateNewListingParam(listing);
|
||||
|
||||
await handleTokenApproval(
|
||||
this.contractWrapper.getSignerOrProvider(),
|
||||
this.contractWrapper,
|
||||
this.getAddress(),
|
||||
listing.assetContractAddress,
|
||||
listing.tokenId,
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
import { NetworkOrSignerOrProvider, TransactionResult } from "..";
|
||||
import { getMultichainRegistryAddress } from "../../constants/addresses";
|
||||
import { PublishedMetadata } from "../../schema/contracts/custom";
|
||||
import { SDKOptions } from "../../schema/sdk-options";
|
||||
import { AddContractInput, ContractInput, DeployedContract } from "../../types";
|
||||
import { ContractWrapper } from "./contract-wrapper";
|
||||
import type {
|
||||
TWMultichainRegistryRouter,
|
||||
TWMultichainRegistryLogic,
|
||||
} from "@thirdweb-dev/contracts-js";
|
||||
import TWRegistryABI from "@thirdweb-dev/contracts-js/dist/abis/TWMultichainRegistryLogic.json";
|
||||
import TWRegistryRouterABI from "@thirdweb-dev/contracts-js/dist/abis/TWMultichainRegistryRouter.json";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { constants, utils } from "ethers";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export class MultichainRegistry {
|
||||
private registryLogic: ContractWrapper<TWMultichainRegistryLogic>;
|
||||
private registryRouter: ContractWrapper<TWMultichainRegistryRouter>;
|
||||
private storage: ThirdwebStorage;
|
||||
|
||||
constructor(
|
||||
network: NetworkOrSignerOrProvider,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions = {},
|
||||
) {
|
||||
this.storage = storage;
|
||||
this.registryLogic = new ContractWrapper<TWMultichainRegistryLogic>(
|
||||
network,
|
||||
getMultichainRegistryAddress(),
|
||||
TWRegistryABI,
|
||||
options,
|
||||
);
|
||||
|
||||
this.registryRouter = new ContractWrapper<TWMultichainRegistryRouter>(
|
||||
network,
|
||||
getMultichainRegistryAddress(),
|
||||
TWRegistryRouterABI,
|
||||
options,
|
||||
);
|
||||
}
|
||||
|
||||
public async updateSigner(signer: NetworkOrSignerOrProvider) {
|
||||
this.registryLogic.updateSignerOrProvider(signer);
|
||||
this.registryRouter.updateSignerOrProvider(signer);
|
||||
}
|
||||
|
||||
public async getContractMetadataURI(
|
||||
chainId: number,
|
||||
address: string,
|
||||
): Promise<string> {
|
||||
return await this.registryLogic.readContract.getMetadataUri(
|
||||
chainId,
|
||||
address,
|
||||
);
|
||||
}
|
||||
|
||||
public async getContractMetadata(
|
||||
chainId: number,
|
||||
address: string,
|
||||
): Promise<PublishedMetadata> {
|
||||
const uri = await this.getContractMetadataURI(chainId, address);
|
||||
if (!uri) {
|
||||
throw new Error(
|
||||
`No metadata URI found for contract ${address} on chain ${chainId}`,
|
||||
);
|
||||
}
|
||||
// TODO define the metadata JSON schema
|
||||
return await this.storage.downloadJSON<PublishedMetadata>(uri);
|
||||
}
|
||||
|
||||
public async getContractAddresses(
|
||||
walletAddress: string,
|
||||
): Promise<DeployedContract[]> {
|
||||
return (await this.registryLogic.readContract.getAll(walletAddress))
|
||||
.filter(
|
||||
(result) =>
|
||||
utils.isAddress(result.deploymentAddress) &&
|
||||
result.deploymentAddress.toLowerCase() !== constants.AddressZero,
|
||||
)
|
||||
.map((result) => ({
|
||||
address: result.deploymentAddress,
|
||||
chainId: result.chainId.toNumber(),
|
||||
}));
|
||||
}
|
||||
|
||||
public async addContract(
|
||||
contract: AddContractInput,
|
||||
): Promise<TransactionResult> {
|
||||
return await this.addContracts([contract]);
|
||||
}
|
||||
|
||||
public async addContracts(
|
||||
contracts: AddContractInput[],
|
||||
): Promise<TransactionResult> {
|
||||
const deployerAddress = await this.registryRouter.getSignerAddress();
|
||||
const encoded: string[] = [];
|
||||
contracts.forEach((contact) => {
|
||||
encoded.push(
|
||||
this.registryLogic.readContract.interface.encodeFunctionData("add", [
|
||||
deployerAddress,
|
||||
contact.address,
|
||||
contact.chainId,
|
||||
contact.metadataURI || "",
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
receipt: await this.registryRouter.multiCall(encoded),
|
||||
};
|
||||
}
|
||||
|
||||
public async removeContract(
|
||||
contract: ContractInput,
|
||||
): Promise<TransactionResult> {
|
||||
return await this.removeContracts([contract]);
|
||||
}
|
||||
|
||||
public async removeContracts(
|
||||
contracts: ContractInput[],
|
||||
): Promise<TransactionResult> {
|
||||
const deployerAddress = await this.registryRouter.getSignerAddress();
|
||||
const encoded: string[] = [];
|
||||
contracts.forEach((contract) => {
|
||||
encoded.push(
|
||||
this.registryLogic.readContract.interface.encodeFunctionData("remove", [
|
||||
deployerAddress,
|
||||
contract.address,
|
||||
contract.chainId,
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
receipt: await this.registryRouter.multiCall(encoded),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,278 @@
|
||||
import {
|
||||
ContractEvents,
|
||||
NetworkOrSignerOrProvider,
|
||||
TransactionResultWithId,
|
||||
} from "..";
|
||||
import { fetchCurrencyMetadata } from "../../common";
|
||||
import { LINK_TOKEN_ADDRESS } from "../../constants";
|
||||
import { FEATURE_PACK_VRF } from "../../constants/thirdweb-features";
|
||||
import { PackRewards, SDKOptions } from "../../schema";
|
||||
import { Amount, CurrencyValue } from "../../types";
|
||||
import { DetectableFeature } from "../interfaces/DetectableFeature";
|
||||
import { UpdateableNetwork } from "../interfaces/contract";
|
||||
import { ContractWrapper } from "./contract-wrapper";
|
||||
import { Erc20 } from "./erc-20";
|
||||
import type { ERC20, PackVRFDirect } from "@thirdweb-dev/contracts-js";
|
||||
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/ERC20.json";
|
||||
import IPackAbi from "@thirdweb-dev/contracts-js/dist/abis/IPackVRFDirect.json";
|
||||
import {
|
||||
ITokenBundle,
|
||||
PackOpenedEvent,
|
||||
PackOpenedEventObject,
|
||||
PackOpenRequestedEvent,
|
||||
} from "@thirdweb-dev/contracts-js/dist/declarations/src/IPackVRFDirect";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { BigNumber, BigNumberish, ethers } from "ethers";
|
||||
|
||||
export class PackVRF implements UpdateableNetwork, DetectableFeature {
|
||||
featureName = FEATURE_PACK_VRF.name;
|
||||
private contractWrapper: ContractWrapper<PackVRFDirect>;
|
||||
private storage: ThirdwebStorage;
|
||||
public chainId: number;
|
||||
private events: ContractEvents<PackVRFDirect>;
|
||||
|
||||
constructor(
|
||||
network: NetworkOrSignerOrProvider,
|
||||
address: string,
|
||||
storage: ThirdwebStorage,
|
||||
options: SDKOptions,
|
||||
chainId: number,
|
||||
contractWrapper: ContractWrapper<PackVRFDirect> = new ContractWrapper(
|
||||
network,
|
||||
address,
|
||||
IPackAbi,
|
||||
options,
|
||||
),
|
||||
) {
|
||||
this.contractWrapper = contractWrapper;
|
||||
this.storage = storage;
|
||||
this.chainId = chainId;
|
||||
this.events = new ContractEvents(this.contractWrapper);
|
||||
}
|
||||
|
||||
onNetworkUpdated(network: NetworkOrSignerOrProvider): void {
|
||||
this.contractWrapper.updateSignerOrProvider(network);
|
||||
}
|
||||
|
||||
getAddress(): string {
|
||||
return this.contractWrapper.readContract.address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a pack using Chainlink VRFs random number generation
|
||||
* This will return a transaction result with the requestId of the open request, NOT the contents of the pack
|
||||
* To get the contents of the pack, you must call claimRewards once the VRF request has been fulfilled
|
||||
* You can use the canClaimRewards method to check if the VRF request has been fulfilled
|
||||
* @param tokenId
|
||||
* @param amount
|
||||
* @returns
|
||||
*/
|
||||
public async open(
|
||||
tokenId: BigNumberish,
|
||||
amount: BigNumberish = 1,
|
||||
): Promise<TransactionResultWithId> {
|
||||
const receipt = await this.contractWrapper.sendTransaction(
|
||||
"openPack",
|
||||
[tokenId, amount],
|
||||
{
|
||||
// Higher gas limit for opening packs
|
||||
gasLimit: 500000,
|
||||
},
|
||||
);
|
||||
let id = BigNumber.from(0);
|
||||
try {
|
||||
const event = this.contractWrapper.parseLogs<PackOpenRequestedEvent>(
|
||||
"PackOpenRequested",
|
||||
receipt?.logs,
|
||||
);
|
||||
id = event[0].args.requestId;
|
||||
} catch (e) {}
|
||||
|
||||
return {
|
||||
receipt,
|
||||
id,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Claim the rewards from a pack that has been opened
|
||||
* This will return the contents of the pack
|
||||
* Make sure to check if the VRF request has been fulfilled using canClaimRewards() before calling this method
|
||||
* @returns the random rewards from opening a pack
|
||||
*/
|
||||
public async claimRewards(): Promise<PackRewards> {
|
||||
const receipt = await this.contractWrapper.sendTransaction(
|
||||
"claimRewards",
|
||||
[],
|
||||
{
|
||||
// Higher gas limit for opening packs
|
||||
gasLimit: 500000,
|
||||
},
|
||||
);
|
||||
const event = this.contractWrapper.parseLogs<PackOpenedEvent>(
|
||||
"PackOpened",
|
||||
receipt?.logs,
|
||||
);
|
||||
if (event.length === 0) {
|
||||
throw new Error("PackOpened event not found");
|
||||
}
|
||||
const rewards = event[0].args.rewardUnitsDistributed;
|
||||
|
||||
return this.parseRewards(rewards);
|
||||
}
|
||||
|
||||
private async parseRewards(
|
||||
rewards: ITokenBundle.TokenStructOutput[],
|
||||
): Promise<PackRewards> {
|
||||
const erc20Rewards: PackRewards["erc20Rewards"] = [];
|
||||
const erc721Rewards: PackRewards["erc721Rewards"] = [];
|
||||
const erc1155Rewards: PackRewards["erc1155Rewards"] = [];
|
||||
|
||||
for (const reward of rewards) {
|
||||
switch (reward.tokenType) {
|
||||
case 0: {
|
||||
const tokenMetadata = await fetchCurrencyMetadata(
|
||||
this.contractWrapper.getProvider(),
|
||||
reward.assetContract,
|
||||
);
|
||||
erc20Rewards.push({
|
||||
contractAddress: reward.assetContract,
|
||||
quantityPerReward: ethers.utils
|
||||
.formatUnits(reward.totalAmount, tokenMetadata.decimals)
|
||||
.toString(),
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
erc721Rewards.push({
|
||||
contractAddress: reward.assetContract,
|
||||
tokenId: reward.tokenId.toString(),
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
erc1155Rewards.push({
|
||||
contractAddress: reward.assetContract,
|
||||
tokenId: reward.tokenId.toString(),
|
||||
quantityPerReward: reward.totalAmount.toString(),
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
erc20Rewards,
|
||||
erc721Rewards,
|
||||
erc1155Rewards,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup a listener that will be called everytime a pack is opened in this contract
|
||||
* @param callback the listener to call when a pack is opened
|
||||
* @returns a unsubscribe function to cleanup the listener
|
||||
*/
|
||||
public async addPackOpenEventListener(
|
||||
callback: (
|
||||
packId: string,
|
||||
openerAddress: string,
|
||||
rewards: PackRewards,
|
||||
) => void,
|
||||
) {
|
||||
return this.events.addEventListener<PackOpenedEventObject>(
|
||||
"PackOpened",
|
||||
async (event) => {
|
||||
callback(
|
||||
event.data.packId.toString(),
|
||||
event.data.opener,
|
||||
await this.parseRewards(event.data.rewardUnitsDistributed),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the connected address can claim rewards after opening a pack
|
||||
* @param claimerAddress Optional: the address to check if they can claim rewards, defaults to the connected address
|
||||
* @returns whether the connected address can claim rewards after opening a pack
|
||||
*/
|
||||
public async canClaimRewards(claimerAddress?: string): Promise<boolean> {
|
||||
const address =
|
||||
claimerAddress || (await this.contractWrapper.getSignerAddress());
|
||||
return await this.contractWrapper.readContract.canClaimRewards(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a pack and claim the rewards in one transaction.
|
||||
* This function will only start the flow of opening a pack, the rewards will be granted automatically to the connected address after VRF request is fulfilled
|
||||
* @param packId The id of the pack to open
|
||||
* @param amount Optional: the amount of packs to open, defaults to 1
|
||||
* @param gasLimit Optional: the gas limit to use for the VRF callback transaction, defaults to 500000
|
||||
* @returns
|
||||
*/
|
||||
public async openAndClaim(
|
||||
packId: BigNumberish,
|
||||
amount: BigNumberish = 1,
|
||||
gasLimit: BigNumberish = 500000,
|
||||
): Promise<TransactionResultWithId> {
|
||||
const receipt = await this.contractWrapper.sendTransaction(
|
||||
"openPackAndClaimRewards",
|
||||
[packId, amount, gasLimit],
|
||||
{
|
||||
// Higher gas limit for opening packs
|
||||
gasLimit: BigNumber.from(500000),
|
||||
},
|
||||
);
|
||||
let id = BigNumber.from(0);
|
||||
try {
|
||||
const event = this.contractWrapper.parseLogs<PackOpenRequestedEvent>(
|
||||
"PackOpenRequested",
|
||||
receipt?.logs,
|
||||
);
|
||||
id = event[0].args.requestId;
|
||||
} catch (e) {}
|
||||
|
||||
return {
|
||||
receipt,
|
||||
id,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the balance of LINK in the contract
|
||||
* @returns the balance of LINK in the contract
|
||||
*/
|
||||
public async getLinkBalance(): Promise<CurrencyValue> {
|
||||
return this.getLinkContract().balanceOf(
|
||||
this.contractWrapper.readContract.address,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer LINK to this contract
|
||||
* @param amount the amount of LINK to transfer to the contract
|
||||
*/
|
||||
public async transferLink(amount: Amount) {
|
||||
await this.getLinkContract().transfer(
|
||||
this.contractWrapper.readContract.address,
|
||||
amount,
|
||||
);
|
||||
}
|
||||
|
||||
private getLinkContract(): Erc20 {
|
||||
const linkAddress = LINK_TOKEN_ADDRESS[this.chainId];
|
||||
if (!linkAddress) {
|
||||
throw new Error(
|
||||
`No LINK token address found for chainId ${this.chainId}`,
|
||||
);
|
||||
}
|
||||
const contract = new ContractWrapper<ERC20>(
|
||||
this.contractWrapper.getSignerOrProvider(),
|
||||
linkAddress,
|
||||
ERC20Abi,
|
||||
this.contractWrapper.options,
|
||||
);
|
||||
return new Erc20(contract, this.storage, this.chainId);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import EventEmitter from "eventemitter3";
|
||||
export class RPCConnectionHandler extends EventEmitter {
|
||||
private provider: providers.Provider;
|
||||
private signer: Signer | undefined;
|
||||
protected readonly options: SDKOptionsOutput;
|
||||
public readonly options: SDKOptionsOutput;
|
||||
|
||||
constructor(network: NetworkOrSignerOrProvider, options: SDKOptions) {
|
||||
super();
|
||||
|
||||
@@ -17,6 +17,7 @@ import { WalletAuthenticator } from "./auth/wallet-authenticator";
|
||||
import type { ContractMetadata } from "./classes";
|
||||
import { ContractDeployer } from "./classes/contract-deployer";
|
||||
import { ContractPublisher } from "./classes/contract-publisher";
|
||||
import { MultichainRegistry } from "./classes/multichain-registry";
|
||||
import {
|
||||
getSignerAndProvider,
|
||||
RPCConnectionHandler,
|
||||
@@ -162,6 +163,10 @@ export class ThirdwebSDK extends RPCConnectionHandler {
|
||||
* New contract deployer
|
||||
*/
|
||||
public deployer: ContractDeployer;
|
||||
/**
|
||||
* The registry of deployed contracts
|
||||
*/
|
||||
public multiChainRegistry: MultichainRegistry;
|
||||
/**
|
||||
* Interact with the connected wallet
|
||||
*/
|
||||
@@ -187,6 +192,11 @@ export class ThirdwebSDK extends RPCConnectionHandler {
|
||||
this.wallet = new UserWallet(signerOrProvider, options);
|
||||
this.deployer = new ContractDeployer(signerOrProvider, options, storage);
|
||||
this.auth = new WalletAuthenticator(signerOrProvider, this.wallet, options);
|
||||
this.multiChainRegistry = new MultichainRegistry(
|
||||
signerOrProvider,
|
||||
this.storageHandler,
|
||||
this.options,
|
||||
);
|
||||
this._publisher = new ContractPublisher(
|
||||
signerOrProvider,
|
||||
this.options,
|
||||
@@ -425,7 +435,7 @@ export class ThirdwebSDK extends RPCConnectionHandler {
|
||||
if (!contractTypeOrABI || contractTypeOrABI === "custom") {
|
||||
const resolvedContractType = await this.resolveContractType(address);
|
||||
if (resolvedContractType === "custom") {
|
||||
// if it's a custom contract we gotta fetch the compilet metadata
|
||||
// if it's a custom contract we gotta fetch the compiler metadata
|
||||
try {
|
||||
const publisher = this.getPublisher();
|
||||
const metadata = await publisher.fetchCompilerMetadataFromAddress(
|
||||
@@ -439,7 +449,7 @@ export class ThirdwebSDK extends RPCConnectionHandler {
|
||||
// otherwise if it's a prebuilt contract we can just use the contract type
|
||||
const contractAbi = await PREBUILT_CONTRACTS_MAP[
|
||||
resolvedContractType
|
||||
].getAbi(address, this.getProvider());
|
||||
].getAbi(address, this.getProvider(), this.storage);
|
||||
newContract = await this.getContractFromAbi(address, contractAbi);
|
||||
}
|
||||
}
|
||||
@@ -515,6 +525,7 @@ export class ThirdwebSDK extends RPCConnectionHandler {
|
||||
* ```
|
||||
*/
|
||||
public async getContractList(walletAddress: string) {
|
||||
// TODO - this only reads from the current registry chain, not the multichain registry
|
||||
const addresses =
|
||||
(await (
|
||||
await this.deployer.getRegistry()
|
||||
@@ -574,6 +585,7 @@ export class ThirdwebSDK extends RPCConnectionHandler {
|
||||
this.auth.updateSignerOrProvider(this.getSignerOrProvider());
|
||||
this.deployer.updateSignerOrProvider(this.getSignerOrProvider());
|
||||
this._publisher.updateSignerOrProvider(this.getSignerOrProvider());
|
||||
this.multiChainRegistry.updateSigner(this.getSignerOrProvider());
|
||||
for (const [, contract] of this.contractCache) {
|
||||
contract.onNetworkUpdated(this.getSignerOrProvider());
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
isNativeToken,
|
||||
normalizePriceValue,
|
||||
} from "../../common/currency";
|
||||
import { EIP712Domain, signTypedDataInternal } from "../../common/sign";
|
||||
import { NATIVE_TOKEN_ADDRESS } from "../../constants";
|
||||
import { SDKOptions } from "../../schema";
|
||||
import { Amount, CurrencyValue } from "../../types";
|
||||
@@ -11,7 +12,7 @@ import { RPCConnectionHandler } from "../classes/rpc-connection-handler";
|
||||
import { NetworkOrSignerOrProvider, TransactionResult } from "../types";
|
||||
import type { IERC20 } from "@thirdweb-dev/contracts-js";
|
||||
import ERC20Abi from "@thirdweb-dev/contracts-js/dist/abis/IERC20.json";
|
||||
import { ethers, BigNumber, providers, Signer } from "ethers";
|
||||
import { ethers, BigNumber, providers, Signer, TypedDataField } from "ethers";
|
||||
import EventEmitter from "eventemitter3";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
@@ -183,6 +184,42 @@ export class UserWallet {
|
||||
return await signer.signMessage(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a typed data structure (EIP712) with the connected wallet private key
|
||||
* @param domain - the domain as EIP712 standard
|
||||
* @param types - the strcuture and data types as defined by the EIP712 standard
|
||||
* @param message - the data to sign
|
||||
* @returns the payload and its associated signature
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* // This is the message to be signed
|
||||
* // Now we can sign the message with the connected wallet
|
||||
* const { payload, signature } = await sdk.wallet.signTypedData(
|
||||
* {
|
||||
name: "MyEIP721Domain",
|
||||
version: "1",
|
||||
chainId: 1,
|
||||
verifyingContract: "0x...",
|
||||
},
|
||||
{ MyStruct: [ { name: "to", type: "address" }, { name: "quantity", type: "uint256" } ] },
|
||||
{ to: "0x...", quantity: 1 },
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
public async signTypedData(
|
||||
domain: EIP712Domain,
|
||||
types: Record<string, Array<TypedDataField>>,
|
||||
message: Record<string, any>,
|
||||
): Promise<{ payload: any; signature: string }> {
|
||||
return await signTypedDataInternal(
|
||||
this.requireWallet(),
|
||||
domain,
|
||||
types,
|
||||
message,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Recover the signing address from a signed message
|
||||
* @param message - the original message that was signed
|
||||
|
||||
@@ -5,14 +5,13 @@ export type { ContractType, NetworkOrSignerOrProvider } from "./core/types";
|
||||
|
||||
export type { Role } from "./common/role";
|
||||
|
||||
export { CommonContractSchema } from "./schema/contracts/common";
|
||||
export * from "./schema/contracts/custom";
|
||||
export * from "./schema/contracts/common/claim-conditions";
|
||||
export * from "./schema/tokens/common/properties";
|
||||
export * from "./constants/chains";
|
||||
export * from "./schema/tokens/token";
|
||||
export * from "./schema/tokens/edition";
|
||||
export * from "./schema/contracts/common";
|
||||
export * from "./schema/contracts/custom";
|
||||
export * from "./schema/auth";
|
||||
export type {
|
||||
SDKOptions,
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import { BytesLikeSchema } from "../../../../core/schema/shared";
|
||||
import { AddressSchema } from "../../shared";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
export const PluginMapInput = z.object({
|
||||
functionSelector: BytesLikeSchema,
|
||||
functionSignature: z.string(),
|
||||
pluginAddress: AddressSchema,
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./custom";
|
||||
export * from "./common";
|
||||
export * from "./drop-erc721";
|
||||
export * from "./drop-erc1155";
|
||||
@@ -8,4 +9,3 @@ export * from "./token-erc20";
|
||||
export * from "./token-erc721";
|
||||
export * from "./token-erc1155";
|
||||
export * from "./vote";
|
||||
export * from "./custom";
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
export interface DeployEvent {
|
||||
status: "submitted" | "completed";
|
||||
transactionHash: string;
|
||||
contractAddress?: string;
|
||||
}
|
||||
|
||||
export interface DeployEvents {
|
||||
contractDeployed: [DeployEvent];
|
||||
}
|
||||
@@ -1 +1,2 @@
|
||||
export * from "./deploy-metadata";
|
||||
export * from "./deploy-events";
|
||||
|
||||
@@ -8,3 +8,4 @@ export * from "./SplitRecipient";
|
||||
export * from "./deploy";
|
||||
export * from "./events";
|
||||
export * from "./multiwrap";
|
||||
export * from "./registry";
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import { PluginMapInput } from "../schema/contracts/common/plugins";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* Input model to pass a list of extension-addresses + function-selectors
|
||||
* @public
|
||||
*/
|
||||
export type Plugin = z.input<typeof PluginMapInput>;
|
||||
@@ -0,0 +1,13 @@
|
||||
export type ContractInput = {
|
||||
address: string;
|
||||
chainId: number;
|
||||
};
|
||||
|
||||
export type AddContractInput = ContractInput & {
|
||||
metadataURI?: string;
|
||||
};
|
||||
|
||||
export type DeployedContract = {
|
||||
address: string;
|
||||
chainId: number;
|
||||
};
|
||||
@@ -9,6 +9,7 @@ export type {
|
||||
} from "./core/schema/nft";
|
||||
|
||||
export type { CurrencyValue, TokenMetadata } from "./core/schema/token";
|
||||
export { getRpcUrl } from "./core/constants/urls";
|
||||
|
||||
export type { QueryAllParams } from "./core/schema/QueryParams";
|
||||
|
||||
|
||||
@@ -64,9 +64,7 @@ export class ClaimConditions {
|
||||
const goLiveDate = candyMachine.goLiveDate
|
||||
? new Date(candyMachine.goLiveDate.toNumber() * 1000)
|
||||
: null;
|
||||
const isWithinGoLiveDate = candyMachine.goLiveDate
|
||||
? candyMachine.goLiveDate.toNumber() * 1000 >= Date.now()
|
||||
: true;
|
||||
const isWithinGoLiveDate = goLiveDate ? goLiveDate <= new Date() : true;
|
||||
const maxClaimable =
|
||||
candyMachine.endSettings && candyMachine.endSettings.endSettingType === 1
|
||||
? candyMachine.endSettings.number.toNumber()
|
||||
@@ -155,7 +153,7 @@ export class ClaimConditions {
|
||||
const parsed = NFTDropUpdateableConditionsInputSchema.parse(metadata);
|
||||
|
||||
// recipients
|
||||
const wallet: PublicKey | undefined = parsed.primarySaleRecipient
|
||||
let wallet: PublicKey | undefined = parsed.primarySaleRecipient
|
||||
? new PublicKey(parsed.primarySaleRecipient)
|
||||
: undefined;
|
||||
const sellerFeeBasisPoints = parsed.sellerFeeBasisPoints;
|
||||
@@ -165,12 +163,19 @@ export class ClaimConditions {
|
||||
? sol(Number(parsed.price))
|
||||
: undefined;
|
||||
let tokenMint: PublicKey | undefined = undefined;
|
||||
if (parsed.currencyAddress && parsed.price) {
|
||||
if (parsed.currencyAddress) {
|
||||
const fetchedToken = await this.metaplex
|
||||
.tokens()
|
||||
.findMintByAddress({ address: new PublicKey(parsed.currencyAddress) });
|
||||
price = token(Number(parsed.price), fetchedToken.decimals);
|
||||
price = token(Number(parsed.price || 0), fetchedToken.decimals);
|
||||
tokenMint = fetchedToken.address;
|
||||
wallet = this.metaplex
|
||||
.tokens()
|
||||
.pdas()
|
||||
.associatedTokenAccount({
|
||||
mint: tokenMint,
|
||||
owner: wallet ? wallet : this.metaplex.identity().publicKey,
|
||||
});
|
||||
}
|
||||
|
||||
// dates
|
||||
|
||||
@@ -440,9 +440,9 @@ export class NFTDrop {
|
||||
* console.log("Claimed NFT at address", claimedAddresses[0]);
|
||||
* ```
|
||||
*/
|
||||
async claim(quantity: Amount): Promise<string[]> {
|
||||
async claim(amount: Amount): Promise<string[]> {
|
||||
const address = this.metaplex.identity().publicKey.toBase58();
|
||||
return this.claimTo(address, quantity);
|
||||
return this.claimTo(address, amount);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -462,7 +462,7 @@ export class NFTDrop {
|
||||
const candyMachine = await this.getCandyMachine();
|
||||
await this.claimConditions.assertCanClaimable(Number(amount));
|
||||
const builders = await Promise.all(
|
||||
[...Array(amount).keys()].map(async () => {
|
||||
[...Array(Number(amount)).keys()].map(async () => {
|
||||
return await this.metaplex
|
||||
.candyMachinesV2()
|
||||
.builders()
|
||||
|
||||
@@ -29,28 +29,43 @@ export async function sendMultipartTransaction(
|
||||
// make the connected wallet sign all transactions
|
||||
const signedTx = await metaplex.identity().signAllTransactions(txns);
|
||||
|
||||
// send the signed transactions
|
||||
let signatures = [];
|
||||
for (const tx of signedTx) {
|
||||
const signature = await metaplex.connection.sendRawTransaction(
|
||||
tx.serialize(),
|
||||
// send the signed transactions in batches
|
||||
const batchSize = 200; // sends 200 raw tx in parallel
|
||||
const batches = [];
|
||||
for (let i = 0; i < signedTx.length; i += batchSize) {
|
||||
batches.push(signedTx.slice(i, i + batchSize));
|
||||
}
|
||||
let signatures: string[][] = [];
|
||||
for (const txs of batches) {
|
||||
const signature = await Promise.all(
|
||||
txs.map((tx) => metaplex.connection.sendRawTransaction(tx.serialize())),
|
||||
);
|
||||
signatures.push(signature);
|
||||
}
|
||||
|
||||
// wait for confirmations in parallel
|
||||
const confirmations = await Promise.all(
|
||||
signatures.map((sig) => {
|
||||
return metaplex.rpc().confirmTransaction(sig, {
|
||||
blockhash: block.blockhash,
|
||||
lastValidBlockHeight: block.lastValidBlockHeight,
|
||||
});
|
||||
}),
|
||||
);
|
||||
// wait for confirmations in parallel batches
|
||||
let confirmations = [];
|
||||
for (let i = 0; i < signatures.length; i += 1) {
|
||||
await delay(1000); // add delay to avoid rate limiting
|
||||
const sigs = signatures[i];
|
||||
const confirmationBatch = await Promise.all(
|
||||
sigs.map((sig) => {
|
||||
return metaplex.rpc().confirmTransaction(sig, {
|
||||
blockhash: block.blockhash,
|
||||
lastValidBlockHeight: block.lastValidBlockHeight,
|
||||
});
|
||||
}),
|
||||
);
|
||||
confirmations.push(...confirmationBatch);
|
||||
}
|
||||
|
||||
if (confirmations.length === 0) {
|
||||
throw new Error("Transaction failed");
|
||||
}
|
||||
|
||||
return signatures.map((signature) => ({ signature }));
|
||||
return signatures.flatMap((sig) => sig).map((signature) => ({ signature }));
|
||||
}
|
||||
|
||||
async function delay(delayMs: number) {
|
||||
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
Abi,
|
||||
ChainId,
|
||||
CONTRACTS_MAP,
|
||||
ContractType,
|
||||
@@ -18,6 +19,7 @@ import {
|
||||
TokenInitializer,
|
||||
VoteInitializer,
|
||||
} from "../../src/evm";
|
||||
import { Plugin } from "../../src/evm/types/plugins";
|
||||
import { MockStorage } from "./mock/MockStorage";
|
||||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
|
||||
import {
|
||||
@@ -44,10 +46,19 @@ import {
|
||||
TWFactory__factory,
|
||||
TWRegistry,
|
||||
TWRegistry__factory,
|
||||
TWMultichainRegistryRouter,
|
||||
TWMultichainRegistryRouter__factory,
|
||||
TWMultichainRegistryLogic,
|
||||
TWMultichainRegistryLogic__factory,
|
||||
PluginMap,
|
||||
PluginMap__factory,
|
||||
VoteERC20__factory,
|
||||
TWProxy__factory,
|
||||
TWProxy,
|
||||
} from "@thirdweb-dev/contracts-js";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { ethers } from "ethers";
|
||||
import { FormatTypes, FunctionFragment, Interface } from "ethers/lib/utils";
|
||||
import hardhat from "hardhat";
|
||||
|
||||
// it's there, trust me bro
|
||||
@@ -227,6 +238,10 @@ export const mochaHooks = {
|
||||
process.env.factoryAddress = thirdwebFactoryDeployer.address;
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
process.env.contractPublisherAddress = contractPublisher.address;
|
||||
// eslint-disable-next-line turbo/no-undeclared-env-vars
|
||||
process.env.multiChainRegistryAddress = await setupMultichainRegistry(
|
||||
trustedForwarderAddress,
|
||||
);
|
||||
|
||||
storage = MockStorage();
|
||||
sdk = new ThirdwebSDK(
|
||||
@@ -241,6 +256,64 @@ export const mochaHooks = {
|
||||
},
|
||||
};
|
||||
|
||||
const generatePluginFunctions = (
|
||||
pluginAddress: string,
|
||||
pluginAbi: Abi,
|
||||
): Plugin[] => {
|
||||
const pluginInterface = new ethers.utils.Interface(pluginAbi);
|
||||
const pluginFunctions: Plugin[] = [];
|
||||
// TODO - filter out common functions like _msgSender(), contractType(), etc.
|
||||
for (const fnFragment of Object.values(pluginInterface.functions)) {
|
||||
const fn = pluginInterface.getFunction(fnFragment.name);
|
||||
pluginFunctions.push({
|
||||
functionSelector: pluginInterface.getSighash(fn),
|
||||
functionSignature:
|
||||
fn.name + "(" + fn.inputs.map((i) => i.type).join(",") + ")",
|
||||
pluginAddress,
|
||||
});
|
||||
}
|
||||
return pluginFunctions;
|
||||
};
|
||||
|
||||
// Setup multichain registry for tests
|
||||
async function setupMultichainRegistry(
|
||||
trustedForwarderAddress: string,
|
||||
): Promise<string> {
|
||||
const multichainRegistryLogicDeployer = (await new ethers.ContractFactory(
|
||||
TWMultichainRegistryLogic__factory.abi,
|
||||
TWMultichainRegistryLogic__factory.bytecode,
|
||||
)
|
||||
.connect(signer)
|
||||
.deploy()) as TWMultichainRegistryLogic;
|
||||
const multichainRegistryLogic =
|
||||
await multichainRegistryLogicDeployer.deployed();
|
||||
|
||||
const plugins: Plugin[] = generatePluginFunctions(
|
||||
multichainRegistryLogic.address,
|
||||
TWMultichainRegistryLogic__factory.abi,
|
||||
);
|
||||
|
||||
const pluginMapDeployer = (await new ethers.ContractFactory(
|
||||
PluginMap__factory.abi,
|
||||
PluginMap__factory.bytecode,
|
||||
)
|
||||
.connect(signer)
|
||||
.deploy(plugins)) as PluginMap;
|
||||
const pluginMap = await pluginMapDeployer.deployed();
|
||||
const multichainRegistryRouterDeployer = (await new ethers.ContractFactory(
|
||||
TWMultichainRegistryRouter__factory.abi,
|
||||
TWMultichainRegistryRouter__factory.bytecode,
|
||||
)
|
||||
.connect(signer)
|
||||
.deploy(pluginMap.address, [
|
||||
trustedForwarderAddress,
|
||||
])) as TWMultichainRegistryRouter;
|
||||
const multichainRegistryRouter =
|
||||
await multichainRegistryRouterDeployer.deployed();
|
||||
|
||||
return multichainRegistryRouter.address;
|
||||
}
|
||||
|
||||
export {
|
||||
ipfsGatewayUrl,
|
||||
sdk,
|
||||
|
||||
@@ -8,6 +8,10 @@ import {
|
||||
import { sdk, signers } from "./before-setup";
|
||||
import { AddressZero } from "@ethersproject/constants";
|
||||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
|
||||
import {
|
||||
MockContractPublisher__factory,
|
||||
TWFactory__factory,
|
||||
} from "@thirdweb-dev/contracts-js";
|
||||
import { expect } from "chai";
|
||||
import { ethers } from "ethers";
|
||||
|
||||
@@ -92,17 +96,25 @@ describe("Events", async () => {
|
||||
|
||||
it("Should emit deploy events", async () => {
|
||||
// eslint-disable-next-line no-unused-expressions
|
||||
expect(sdk.deployer.events).to.not.be.undefined;
|
||||
let txAddress = "";
|
||||
sdk.deployer.events?.addDeployListener((event) => {
|
||||
txAddress = event.contractAddress;
|
||||
const txAddress: string[] = [];
|
||||
sdk.deployer.addDeployListener((event) => {
|
||||
if (event.status === "completed") {
|
||||
txAddress.push(event.contractAddress || "");
|
||||
}
|
||||
});
|
||||
const address = await sdk.deployer.deployMarketplace({
|
||||
name: "Marketplace",
|
||||
});
|
||||
const secondAddress = await sdk.deployer.deployContractWithAbi(
|
||||
MockContractPublisher__factory.abi,
|
||||
MockContractPublisher__factory.bytecode,
|
||||
[],
|
||||
);
|
||||
// Wait for the async listener to get called
|
||||
await new Promise((res) => setTimeout(res, 2000));
|
||||
expect(txAddress).to.equal(address);
|
||||
sdk.deployer.removeAllDeployListeners();
|
||||
expect(txAddress[0]).to.equal(address);
|
||||
expect(txAddress[1]).to.equal(secondAddress);
|
||||
});
|
||||
|
||||
it("should emit Contract events", async () => {
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
TokenERC721__factory,
|
||||
} from "@thirdweb-dev/contracts-js";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { assert, expect } from "chai";
|
||||
import { expect } from "chai";
|
||||
import { ethers } from "ethers";
|
||||
import { readFileSync } from "fs";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { getMultichainRegistryAddress } from "../../src/evm";
|
||||
import { MultichainRegistry } from "../../src/evm/core/classes/multichain-registry";
|
||||
import { ContractRegistry } from "../../src/evm/core/classes/registry";
|
||||
import { sdk, signers } from "./before-setup";
|
||||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
|
||||
@@ -6,6 +8,8 @@ import { expect } from "chai";
|
||||
describe("Contract Registry", () => {
|
||||
let registry: ContractRegistry;
|
||||
|
||||
let multichainRegistry: MultichainRegistry;
|
||||
|
||||
let adminWallet: SignerWithAddress;
|
||||
|
||||
let address: string;
|
||||
@@ -14,6 +18,38 @@ describe("Contract Registry", () => {
|
||||
[adminWallet] = signers;
|
||||
});
|
||||
|
||||
it("multichain registry", async () => {
|
||||
sdk.updateSignerOrProvider(adminWallet);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
multichainRegistry = sdk.multiChainRegistry;
|
||||
console.log(
|
||||
"multichain registry address: ",
|
||||
getMultichainRegistryAddress(),
|
||||
);
|
||||
|
||||
address = await sdk.deployer.deployNFTCollection({
|
||||
name: "Test1",
|
||||
primary_sale_recipient: adminWallet.address,
|
||||
});
|
||||
|
||||
const chainId: number = await adminWallet.getChainId();
|
||||
const metadataURI: string = "ipfs://metadata";
|
||||
await multichainRegistry.addContract({
|
||||
address,
|
||||
chainId,
|
||||
metadataURI,
|
||||
});
|
||||
|
||||
let uri = await multichainRegistry.getContractMetadataURI(chainId, address);
|
||||
expect(uri).to.equal(metadataURI);
|
||||
|
||||
let contracts = await multichainRegistry.getContractAddresses(
|
||||
adminWallet.address,
|
||||
);
|
||||
|
||||
expect(contracts[0].address).to.equal(address);
|
||||
});
|
||||
|
||||
it("should allow adding and removing contracts", async () => {
|
||||
sdk.updateSignerOrProvider(adminWallet);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
|
||||
@@ -189,7 +189,7 @@ describe("Signature drop tests (v5)", async () => {
|
||||
name: "Test1",
|
||||
});
|
||||
const toSign = {
|
||||
to: adminWallet.address,
|
||||
to: samWallet.address,
|
||||
metadata: uri,
|
||||
quantity: 1,
|
||||
};
|
||||
@@ -207,12 +207,12 @@ describe("Signature drop tests (v5)", async () => {
|
||||
name: "Test2",
|
||||
});
|
||||
const toSign1 = {
|
||||
to: adminWallet.address,
|
||||
to: samWallet.address,
|
||||
metadata: uri1,
|
||||
quantity: 1,
|
||||
};
|
||||
const toSign2 = {
|
||||
to: adminWallet.address,
|
||||
to: samWallet.address,
|
||||
metadata: uri2,
|
||||
quantity: 1,
|
||||
};
|
||||
|
||||
@@ -195,12 +195,12 @@ describe("Edition sig minting", async () => {
|
||||
name: "Test2",
|
||||
});
|
||||
const toSign1 = {
|
||||
to: adminWallet.address,
|
||||
to: samWallet.address,
|
||||
metadata: uri1,
|
||||
quantity: 10,
|
||||
};
|
||||
const toSign2 = {
|
||||
to: adminWallet.address,
|
||||
to: samWallet.address,
|
||||
metadata: uri2,
|
||||
quantity: 10,
|
||||
};
|
||||
@@ -236,7 +236,7 @@ describe("Edition sig minting", async () => {
|
||||
it("should mint additional supply", async () => {
|
||||
const tx = await editionContract.signature.mint(v1);
|
||||
const additional = await editionContract.signature.generateFromTokenId({
|
||||
to: adminWallet.address,
|
||||
to: samWallet.address,
|
||||
tokenId: tx.id,
|
||||
quantity: 100,
|
||||
});
|
||||
|
||||
@@ -46,6 +46,7 @@ describe("NFT sig minting", async () => {
|
||||
currencyAddress: NATIVE_TOKEN_ADDRESS,
|
||||
metadata: {
|
||||
name: "OUCH VOUCH",
|
||||
background_color: "ff0000",
|
||||
},
|
||||
price: "1",
|
||||
to: samWallet.address,
|
||||
@@ -195,7 +196,7 @@ describe("NFT sig minting", async () => {
|
||||
name: "Test1",
|
||||
});
|
||||
const toSign = {
|
||||
to: adminWallet.address,
|
||||
to: samWallet.address,
|
||||
metadata: uri,
|
||||
};
|
||||
const payload = await nftContract.signature.generate(toSign);
|
||||
@@ -212,11 +213,11 @@ describe("NFT sig minting", async () => {
|
||||
name: "Test2",
|
||||
});
|
||||
const toSign1 = {
|
||||
to: adminWallet.address,
|
||||
to: samWallet.address,
|
||||
metadata: uri1,
|
||||
};
|
||||
const toSign2 = {
|
||||
to: adminWallet.address,
|
||||
to: samWallet.address,
|
||||
metadata: uri2,
|
||||
};
|
||||
const payloads = await nftContract.signature.generateBatch([
|
||||
|
||||
@@ -56,4 +56,25 @@ describe("Wallet", async () => {
|
||||
const address = sdk.wallet.recoverAddress(message, signature);
|
||||
expect(address).to.eq(adminWallet.address);
|
||||
});
|
||||
|
||||
it("should sign typed data and recover address", async () => {
|
||||
sdk.updateSignerOrProvider(adminWallet);
|
||||
const { payload, signature } = await sdk.wallet.signTypedData(
|
||||
{
|
||||
name: "MyEIP721Domain",
|
||||
version: "1",
|
||||
chainId: 1,
|
||||
verifyingContract: adminWallet.address,
|
||||
},
|
||||
{
|
||||
MyStruct: [
|
||||
{ name: "to", type: "address" },
|
||||
{ name: "quantity", type: "uint256" },
|
||||
],
|
||||
},
|
||||
{ to: adminWallet.address, quantity: 1 },
|
||||
);
|
||||
expect(payload !== undefined).to.eq(true);
|
||||
expect(signature !== undefined).to.eq(true);
|
||||
});
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user