Compare commits
39
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 | ||
|
|
517e2a75e3 | ||
|
|
72692689e9 | ||
|
|
efc56fa580 |
@@ -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,17 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 2.0.40
|
||||
|
||||
## 2.0.39
|
||||
|
||||
## 2.0.38
|
||||
|
||||
## 2.0.37
|
||||
|
||||
## 2.0.36
|
||||
|
||||
## 2.0.35
|
||||
|
||||
## 2.0.34
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "2.0.34",
|
||||
"version": "2.0.40",
|
||||
"exports": {
|
||||
"./next": {
|
||||
"module": "./next/dist/thirdweb-dev-auth-next.esm.js",
|
||||
|
||||
@@ -1,5 +1,63 @@
|
||||
# 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
|
||||
|
||||
- Updated dependencies [[`efc56fa`](https://github.com/thirdweb-dev/js/commit/efc56fa5802490ac8ef50037658d046afd89e9a1)]:
|
||||
- @thirdweb-dev/sdk@3.6.5
|
||||
|
||||
## 0.9.2
|
||||
|
||||
### 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.2",
|
||||
"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",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-typescript",
|
||||
["@babel/preset-env", { "targets": "defaults, not ie 11" }]
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
# folders
|
||||
dist/
|
||||
|
||||
# files
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: ["thirdweb"],
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
# @thirdweb-dev/pay
|
||||
|
||||
## 0.1.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- [#433](https://github.com/thirdweb-dev/js/pull/433) [`7269268`](https://github.com/thirdweb-dev/js/commit/72692689e9adb41e92038765fd01a36c2b7457e1) Thanks [@jnsdls](https://github.com/jnsdls)! - Initialize Pay Package
|
||||
@@ -0,0 +1,16 @@
|
||||
<p align="center">
|
||||
<br />
|
||||
<a href="https://thirdweb.com"><img src="https://github.com/thirdweb-dev/js/blob/main/packages/sdk/logo.svg?raw=true" width="200" alt=""/></a>
|
||||
<br />
|
||||
</p>
|
||||
<h1 align="center">thirdweb wallets</h1>
|
||||
<p align="center">
|
||||
<!-- <a href="https://www.npmjs.com/package/@thirdweb-dev/sdk"><img src="https://img.shields.io/npm/v/@thirdweb-dev/sdk?color=red&label=npm&logo=npm" alt="npm version"/></a> -->
|
||||
<!-- <a href="https://github.com/thirdweb-dev/js/actions/workflows/CI.yml"><img alt="Build Status" src="https://github.com/thirdweb-dev/js/actions/workflows/CI.yml/badge.svg"/></a> -->
|
||||
<!-- <a href="https://discord.gg/thirdweb"><img alt="Join our Discord!" src="https://img.shields.io/discord/834227967404146718.svg?color=7289da&label=discord&logo=discord&style=flat"/></a> -->
|
||||
|
||||
</p>
|
||||
<!-- <p align="center"><strong>Best in class Web3 SDK for Browser, Node and Mobile apps</strong></p> -->
|
||||
<br />
|
||||
|
||||
### todo
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"main": "dist/thirdweb-dev-pay-integrations-coinbase.cjs.js",
|
||||
"module": "dist/thirdweb-dev-pay-integrations-coinbase.esm.js"
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/pay",
|
||||
"version": "0.1.0",
|
||||
"main": "dist/thirdweb-dev-pay.cjs.js",
|
||||
"module": "dist/thirdweb-dev-pay.esm.js",
|
||||
"exports": {
|
||||
".": {
|
||||
"module": "./dist/thirdweb-dev-pay.esm.js",
|
||||
"default": "./dist/thirdweb-dev-pay.cjs.js"
|
||||
},
|
||||
"./integrations/coinbase": {
|
||||
"module": "./integrations/coinbase/dist/thirdweb-dev-pay-integrations-coinbase.esm.js",
|
||||
"default": "./integrations/coinbase/dist/thirdweb-dev-pay-integrations-coinbase.cjs.js"
|
||||
},
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/pay",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/thirdweb-dev/js/issues"
|
||||
},
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"files": [
|
||||
"dist/",
|
||||
"integrations/"
|
||||
],
|
||||
"preconstruct": {
|
||||
"entrypoints": [
|
||||
"index.ts",
|
||||
"integrations/**"
|
||||
],
|
||||
"___experimentalFlags_WILL_CHANGE_IN_PATCH": {
|
||||
"exports": true
|
||||
},
|
||||
"exports": true
|
||||
},
|
||||
"sideEffects": false,
|
||||
"dependencies": {
|
||||
"@coinbase/cbpay-js": "^1.6.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preconstruct/cli": "^2.2.1",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"scripts": {
|
||||
"format": "prettier --write 'src/**/*'",
|
||||
"lint": "eslint src/",
|
||||
"fix": "eslint src/ --fix",
|
||||
"clean": "rm -rf dist/",
|
||||
"build": "tsc && preconstruct build",
|
||||
"push": "yalc push"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./integrations/coinbase";
|
||||
@@ -0,0 +1,62 @@
|
||||
import { initOnRamp, InitOnRampParams } from "@coinbase/cbpay-js";
|
||||
|
||||
interface CoinbasePayOptions extends Pick<InitOnRampParams, "appId"> {}
|
||||
|
||||
const CHAIN_ID_MAP = {
|
||||
[-1]: "solana",
|
||||
1: "ethereum",
|
||||
69: "optimism",
|
||||
137: "polygon",
|
||||
} as const;
|
||||
|
||||
export type FundWalletOptions = {
|
||||
address: string;
|
||||
chainId: keyof typeof CHAIN_ID_MAP;
|
||||
assets?: string[];
|
||||
};
|
||||
|
||||
export class CoinbasePayIntegration {
|
||||
#appId: string;
|
||||
constructor(options: CoinbasePayOptions) {
|
||||
this.#appId = options.appId;
|
||||
}
|
||||
|
||||
async fundWallet(opts: FundWalletOptions): Promise<void> {
|
||||
const { address, chainId, assets } = opts;
|
||||
|
||||
return new Promise((res, rej) => {
|
||||
initOnRamp(
|
||||
{
|
||||
appId: this.#appId,
|
||||
widgetParameters: {
|
||||
destinationWallets: [
|
||||
{
|
||||
address,
|
||||
assets,
|
||||
supportedNetworks: [CHAIN_ID_MAP[chainId]],
|
||||
},
|
||||
],
|
||||
},
|
||||
experienceLoggedIn: "embedded",
|
||||
experienceLoggedOut: "popup",
|
||||
closeOnExit: true,
|
||||
onSuccess: () => {
|
||||
res();
|
||||
},
|
||||
onExit(error) {
|
||||
if (error) {
|
||||
return rej(error);
|
||||
}
|
||||
return res();
|
||||
},
|
||||
},
|
||||
(err, instance) => {
|
||||
if (err || !instance) {
|
||||
return rej(err);
|
||||
}
|
||||
instance.open();
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": "@thirdweb-dev/tsconfig/sdk.json",
|
||||
"include": ["src", "types"],
|
||||
"exclude": ["dist", "build", "node_modules"]
|
||||
}
|
||||
@@ -1,5 +1,31 @@
|
||||
# @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
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.6.4",
|
||||
"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,74 @@
|
||||
# @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
|
||||
|
||||
- [#440](https://github.com/thirdweb-dev/js/pull/440) [`efc56fa`](https://github.com/thirdweb-dev/js/commit/efc56fa5802490ac8ef50037658d046afd89e9a1) Thanks [@jnsdls](https://github.com/jnsdls)! - [EVM] - providers are now re-used if the constructor options are identical leading to better batching, also introduced an additional max batch size param (250 by default)
|
||||
|
||||
## 3.6.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/sdk",
|
||||
"version": "3.6.4",
|
||||
"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;
|
||||
|
||||
@@ -123,6 +123,11 @@ export function getProviderForNetwork(network: ChainOrRpc | SignerOrProvider) {
|
||||
}
|
||||
}
|
||||
|
||||
const READONLY_PROVIDER_MAP: Map<
|
||||
string,
|
||||
StaticJsonRpcBatchProvider | providers.JsonRpcBatchProvider
|
||||
> = new Map();
|
||||
|
||||
/**
|
||||
*
|
||||
* @param network - the chain name or rpc url
|
||||
@@ -136,11 +141,19 @@ export function getReadOnlyProvider(network: string, chainId?: number) {
|
||||
if (match) {
|
||||
switch (match[1]) {
|
||||
case "http":
|
||||
return chainId
|
||||
const seralizedOpts = `${network}-${chainId || -1}`;
|
||||
const existingProvider = READONLY_PROVIDER_MAP.get(seralizedOpts);
|
||||
if (existingProvider) {
|
||||
return existingProvider;
|
||||
}
|
||||
|
||||
const newProvider = chainId
|
||||
? // if we know the chainId we should use the StaticJsonRpcBatchProvider
|
||||
new StaticJsonRpcBatchProvider(network, chainId)
|
||||
: // otherwise fall back to the built in json rpc batch provider
|
||||
new providers.JsonRpcBatchProvider(network, chainId);
|
||||
READONLY_PROVIDER_MAP.set(seralizedOpts, newProvider);
|
||||
return newProvider;
|
||||
|
||||
case "ws":
|
||||
return new providers.WebSocketProvider(network, chainId);
|
||||
@@ -155,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,
|
||||
|
||||
@@ -1,99 +1,130 @@
|
||||
import { providers, utils } from "ethers";
|
||||
|
||||
const DEFAULT_BATCH_TIME_LIMIT_MS = 50;
|
||||
const DEFAULT_BATCH_SIZE_LIMIT = 250;
|
||||
|
||||
const DEFAULT_BATCH_OPTIONS = {
|
||||
timeLimitMs: DEFAULT_BATCH_TIME_LIMIT_MS,
|
||||
sizeLimit: DEFAULT_BATCH_SIZE_LIMIT,
|
||||
};
|
||||
|
||||
export type BatchOptions = Partial<typeof DEFAULT_BATCH_OPTIONS>;
|
||||
|
||||
// mostly copied from ethers.js directly but make it a StaticJsonRpcProvider
|
||||
export class StaticJsonRpcBatchProvider extends providers.StaticJsonRpcProvider {
|
||||
_pendingBatchAggregator: NodeJS.Timer | null;
|
||||
_pendingBatch: Array<{
|
||||
request: { method: string, params: Array<any>, id: number, jsonrpc: "2.0" },
|
||||
resolve: (result: any) => void,
|
||||
reject: (error: Error) => void
|
||||
}> | null;
|
||||
private _timeLimitMs: number;
|
||||
private _sizeLimit: number;
|
||||
_pendingBatchAggregator: NodeJS.Timer | null;
|
||||
_pendingBatch: Array<{
|
||||
request: { method: string; params: Array<any>; id: number; jsonrpc: "2.0" };
|
||||
resolve: (result: any) => void;
|
||||
reject: (error: Error) => void;
|
||||
}> | null;
|
||||
|
||||
constructor(url: string | utils.ConnectionInfo | undefined, network: providers.Networkish | undefined){
|
||||
super(url, network);
|
||||
this._pendingBatchAggregator = null;
|
||||
this._pendingBatch = null;
|
||||
constructor(
|
||||
url: string | utils.ConnectionInfo | undefined,
|
||||
network: providers.Networkish | undefined,
|
||||
batchOptions: BatchOptions = DEFAULT_BATCH_OPTIONS,
|
||||
) {
|
||||
super(url, network);
|
||||
this._timeLimitMs = batchOptions.timeLimitMs || DEFAULT_BATCH_SIZE_LIMIT;
|
||||
this._sizeLimit = batchOptions.sizeLimit || DEFAULT_BATCH_TIME_LIMIT_MS;
|
||||
this._pendingBatchAggregator = null;
|
||||
this._pendingBatch = null;
|
||||
}
|
||||
|
||||
private sendCurrentBatch(request: any) {
|
||||
// if we still have a timeout clear that first
|
||||
if (this._pendingBatchAggregator) {
|
||||
clearTimeout(this._pendingBatchAggregator);
|
||||
}
|
||||
// Get the current batch and clear it, so new requests
|
||||
// go into the next batch
|
||||
const batch = this._pendingBatch || [];
|
||||
this._pendingBatch = null;
|
||||
this._pendingBatchAggregator = null;
|
||||
|
||||
send(method: string, params: Array<any>): Promise<any> {
|
||||
const request = {
|
||||
method: method,
|
||||
params: params,
|
||||
id: (this._nextId++),
|
||||
jsonrpc: "2.0"
|
||||
};
|
||||
// Get the request as an array of requests
|
||||
const request_ = batch.map((inflight) => inflight.request);
|
||||
|
||||
if (this._pendingBatch === null) {
|
||||
this._pendingBatch = [ ];
|
||||
}
|
||||
this.emit("debug", {
|
||||
action: "requestBatch",
|
||||
request: utils.deepCopy(request),
|
||||
provider: this,
|
||||
});
|
||||
|
||||
const inflightRequest: any = { request, resolve: null, reject: null };
|
||||
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
inflightRequest.resolve = resolve;
|
||||
inflightRequest.reject = reject;
|
||||
return utils.fetchJson(this.connection, JSON.stringify(request_)).then(
|
||||
(result) => {
|
||||
this.emit("debug", {
|
||||
action: "response",
|
||||
request: request_,
|
||||
response: result,
|
||||
provider: this,
|
||||
});
|
||||
|
||||
this._pendingBatch.push(inflightRequest);
|
||||
// For each result, feed it to the correct Promise, depending
|
||||
// on whether it was a success or error
|
||||
batch.forEach((inflightRequest_, index) => {
|
||||
const payload = result[index];
|
||||
if (payload.error) {
|
||||
const error = new Error(payload.error.message);
|
||||
(error as any).code = payload.error.code;
|
||||
(error as any).data = payload.error.data;
|
||||
inflightRequest_.reject(error);
|
||||
} else {
|
||||
inflightRequest_.resolve(payload.result);
|
||||
}
|
||||
});
|
||||
},
|
||||
(error) => {
|
||||
this.emit("debug", {
|
||||
action: "response",
|
||||
error: error,
|
||||
request: request_,
|
||||
provider: this,
|
||||
});
|
||||
|
||||
if (!this._pendingBatchAggregator) {
|
||||
// Schedule batch for next event loop + short duration
|
||||
this._pendingBatchAggregator = setTimeout(() => {
|
||||
// If there was an error, reject all the requests
|
||||
batch.forEach((inflightRequest_) => {
|
||||
inflightRequest_.reject(error);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
// Get the current batch and clear it, so new requests
|
||||
// go into the next batch
|
||||
const batch = this._pendingBatch || [];
|
||||
this._pendingBatch = null;
|
||||
this._pendingBatchAggregator = null;
|
||||
send(method: string, params: Array<any>): Promise<any> {
|
||||
const request = {
|
||||
method: method,
|
||||
params: params,
|
||||
id: this._nextId++,
|
||||
jsonrpc: "2.0",
|
||||
};
|
||||
|
||||
// Get the request as an array of requests
|
||||
const request_ = batch.map((inflight) => inflight.request);
|
||||
|
||||
this.emit("debug", {
|
||||
action: "requestBatch",
|
||||
request: utils.deepCopy(request),
|
||||
provider: this
|
||||
});
|
||||
|
||||
return utils.fetchJson(this.connection, JSON.stringify(request_)).then((result) => {
|
||||
this.emit("debug", {
|
||||
action: "response",
|
||||
request: request_,
|
||||
response: result,
|
||||
provider: this
|
||||
});
|
||||
|
||||
// For each result, feed it to the correct Promise, depending
|
||||
// on whether it was a success or error
|
||||
batch.forEach((inflightRequest_, index) => {
|
||||
const payload = result[index];
|
||||
if (payload.error) {
|
||||
const error = new Error(payload.error.message);
|
||||
(<any>error).code = payload.error.code;
|
||||
(<any>error).data = payload.error.data;
|
||||
inflightRequest_.reject(error);
|
||||
} else {
|
||||
inflightRequest_.resolve(payload.result);
|
||||
}
|
||||
});
|
||||
|
||||
}, (error) => {
|
||||
this.emit("debug", {
|
||||
action: "response",
|
||||
error: error,
|
||||
request: request,
|
||||
provider: this
|
||||
});
|
||||
|
||||
batch.forEach((inflightRequest_) => {
|
||||
inflightRequest_.reject(error);
|
||||
});
|
||||
});
|
||||
|
||||
}, 10);
|
||||
}
|
||||
|
||||
return promise;
|
||||
if (this._pendingBatch === null) {
|
||||
this._pendingBatch = [];
|
||||
}
|
||||
}
|
||||
|
||||
const inflightRequest: any = { request, resolve: null, reject: null };
|
||||
|
||||
const promise = new Promise((resolve, reject) => {
|
||||
inflightRequest.resolve = resolve;
|
||||
inflightRequest.reject = reject;
|
||||
});
|
||||
|
||||
// if we would go *over* the size limit of the batch with this request, send the batch now
|
||||
if (this._pendingBatch.length === this._sizeLimit) {
|
||||
this.sendCurrentBatch(request);
|
||||
}
|
||||
|
||||
this._pendingBatch.push(inflightRequest);
|
||||
|
||||
if (!this._pendingBatchAggregator) {
|
||||
// Schedule batch for next event loop + short duration
|
||||
this._pendingBatchAggregator = setTimeout(() => {
|
||||
this.sendCurrentBatch(request);
|
||||
}, this._timeLimitMs);
|
||||
}
|
||||
|
||||
return promise;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user