Compare commits
28
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e5eb13b82 | ||
|
|
2b11353909 | ||
|
|
5882091eab | ||
|
|
8fc5f204b0 | ||
|
|
c953571588 | ||
|
|
edcd22d612 | ||
|
|
0d5503aae9 | ||
|
|
998e521733 | ||
|
|
be606dd3c9 | ||
|
|
d794b8f9f4 | ||
|
|
21b29490d4 | ||
|
|
7b1d62b323 | ||
|
|
e78da6b36c | ||
|
|
ed711c8cb2 | ||
|
|
05a7495a13 | ||
|
|
11bb053246 | ||
|
|
efb3546ec8 | ||
|
|
0a5d2b5bdd | ||
|
|
ac3e019cd1 | ||
|
|
3c5dc4804a | ||
|
|
30ac3aef84 | ||
|
|
ef4cb09219 | ||
|
|
ad7dae3b16 | ||
|
|
0fd8aa04a9 | ||
|
|
620e89dc25 | ||
|
|
86d33c4b3e | ||
|
|
d43f6171d9 | ||
|
|
06ca1c407d |
@@ -1,5 +1,35 @@
|
||||
# @thirdweb-dev/auth
|
||||
|
||||
## 3.2.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`be606dd3`](https://github.com/thirdweb-dev/js/commit/be606dd3c93c1514834c1d970e864d7f949a07ab), [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae)]:
|
||||
- @thirdweb-dev/wallets@1.0.3
|
||||
|
||||
## 3.2.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ed711c8c`](https://github.com/thirdweb-dev/js/commit/ed711c8cb2ed6a0deb1b2a5eeec06df1d4edc5e8), [`05a7495a`](https://github.com/thirdweb-dev/js/commit/05a7495a132aabab5f48abbdb80a468ff6f65df8), [`e78da6b3`](https://github.com/thirdweb-dev/js/commit/e78da6b36cfa6d954234820563201bf760186ed1)]:
|
||||
- @thirdweb-dev/wallets@1.0.2
|
||||
|
||||
## 3.2.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08)]:
|
||||
- @thirdweb-dev/wallets@1.0.1
|
||||
|
||||
## 3.2.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1250](https://github.com/thirdweb-dev/js/pull/1250) [`d43f6171`](https://github.com/thirdweb-dev/js/commit/d43f6171d910e31b748b171b012174390aac3fff) Thanks [@adam-maj](https://github.com/adam-maj)! - Allow setting login payload validity duration
|
||||
|
||||
- Updated dependencies [[`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e), [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc)]:
|
||||
- @thirdweb-dev/wallets@1.0.0
|
||||
|
||||
## 3.2.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/auth",
|
||||
"version": "3.2.3",
|
||||
"version": "3.2.7",
|
||||
"main": "dist/thirdweb-dev-auth.cjs.js",
|
||||
"module": "dist/thirdweb-dev-auth.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -25,6 +25,11 @@ export default async function handler(
|
||||
version: ctx.authOptions?.version,
|
||||
chainId: parsedPayload.data.chainId || ctx.authOptions?.chainId,
|
||||
resources: ctx.authOptions?.resources,
|
||||
expirationTime: ctx.authOptions?.loginPayloadDurationInSeconds
|
||||
? new Date(
|
||||
Date.now() + 1000 * ctx.authOptions.loginPayloadDurationInSeconds,
|
||||
)
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return res.status(200).json({ payload });
|
||||
|
||||
@@ -44,6 +44,7 @@ export type ThirdwebAuthConfig<
|
||||
validateTokenId?:
|
||||
| ((tokenId: string) => void)
|
||||
| ((tokenId: string) => Promise<void>);
|
||||
loginPayloadDurationInSeconds?: number;
|
||||
tokenDurationInSeconds?: number;
|
||||
refreshIntervalInSeconds?: number;
|
||||
};
|
||||
|
||||
@@ -25,6 +25,11 @@ export default async function handler(
|
||||
version: ctx.authOptions?.version,
|
||||
chainId: parsedPayload.data.chainId || ctx.authOptions?.chainId,
|
||||
resources: ctx.authOptions?.resources,
|
||||
expirationTime: ctx.authOptions?.loginPayloadDurationInSeconds
|
||||
? new Date(
|
||||
Date.now() + 1000 * ctx.authOptions.loginPayloadDurationInSeconds,
|
||||
)
|
||||
: undefined,
|
||||
});
|
||||
|
||||
return res.status(200).json({ payload });
|
||||
|
||||
@@ -55,6 +55,7 @@ export type ThirdwebAuthConfig<
|
||||
validateTokenId?:
|
||||
| ((tokenId: string) => void)
|
||||
| ((tokenId: string) => Promise<void>);
|
||||
loginPayloadDurationInSeconds?: number;
|
||||
tokenDurationInSeconds?: number;
|
||||
refreshIntervalInSeconds?: number;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
# @thirdweb-dev/chains
|
||||
|
||||
## 0.1.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1276](https://github.com/thirdweb-dev/js/pull/1276) [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad) Thanks [@MananTank](https://github.com/MananTank)! - Do not change order or RPCs in `getChainRPCs` to Fix RPC override issue
|
||||
|
||||
## 0.1.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1248](https://github.com/thirdweb-dev/js/pull/1248) [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - update chains
|
||||
|
||||
- [#1243](https://github.com/thirdweb-dev/js/pull/1243) [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19) Thanks [@therealharpaljadeja](https://github.com/therealharpaljadeja)! - update chains
|
||||
|
||||
## 0.1.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -10,9 +10,9 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://ethereum.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://mainnet.infura.io/v3/${INFURA_API_KEY}",
|
||||
"wss://mainnet.infura.io/ws/v3/${INFURA_API_KEY}",
|
||||
"https://eth-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://api.mycryptoapi.com/eth",
|
||||
"https://cloudflare-eth.com",
|
||||
"https://ethereum.publicnode.com"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Optimism",
|
||||
"name": "OP Mainnet",
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://optimism.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://optimism-mainnet.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://opt-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://mainnet.optimism.io/"
|
||||
],
|
||||
"faucets": [],
|
||||
|
||||
@@ -10,8 +10,8 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://polygon.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://polygon-mainnet.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://polygon-mainnet.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://polygon-rpc.com/",
|
||||
"https://rpc-mainnet.matic.network",
|
||||
"https://matic-mainnet.chainstacklabs.com",
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import type { Chain } from "../src/types";
|
||||
export default {
|
||||
"name": "Pego Network",
|
||||
"chain": "PEGO",
|
||||
"rpc": [
|
||||
"https://pego-network.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://pegorpc.com",
|
||||
"https://node1.pegorpc.com",
|
||||
"https://node2.pegorpc.com",
|
||||
"https://node3.pegorpc.com"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
"name": "Pego Native Token",
|
||||
"symbol": "PG",
|
||||
"decimals": 18
|
||||
},
|
||||
"infoURL": "https://pego.network",
|
||||
"shortName": "pg",
|
||||
"chainId": 20201022,
|
||||
"networkId": 20201022,
|
||||
"icon": {
|
||||
"url": "ipfs://QmVf1afskRHuZjFSLCZH8397KrVNAoYgyAePX9VMBrPVtx",
|
||||
"width": 246,
|
||||
"height": 247,
|
||||
"format": "png"
|
||||
},
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Pego Network Explorer",
|
||||
"url": "https://scan.pego.network",
|
||||
"standard": "EIP3091"
|
||||
}
|
||||
],
|
||||
"testnet": false,
|
||||
"slug": "pego-network"
|
||||
} as const satisfies Chain;
|
||||
@@ -4,8 +4,8 @@ export default {
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://optimism-goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://opt-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://optimism-goerli.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://opt-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://goerli.optimism.io/"
|
||||
],
|
||||
"faucets": [
|
||||
|
||||
@@ -13,8 +13,8 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://arbitrum-goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://arb-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://arbitrum-goerli.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://arb-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://goerli-rollup.arbitrum.io/rpc/"
|
||||
],
|
||||
"faucets": [],
|
||||
|
||||
@@ -12,15 +12,20 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://celo-alfajores-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://alfajores-forno.celo-testnet.org",
|
||||
"wss://alfajores-forno.celo-testnet.org/ws"
|
||||
"wss://alfajores-forno.celo-testnet.org/ws",
|
||||
"https://alfajores-forno.celo-testnet.org"
|
||||
],
|
||||
"faucets": [
|
||||
"https://celo.org/developers/faucet",
|
||||
"https://cauldron.pretoriaresearchlab.io/alfajores-faucet"
|
||||
"https://cauldron.pretoriaresearchlab.io/alfajores-faucet",
|
||||
"https://celo.org/developers/faucet"
|
||||
],
|
||||
"infoURL": "https://docs.celo.org/",
|
||||
"explorers": [
|
||||
{
|
||||
"name": "Celoscan",
|
||||
"url": "https://alfajores.celoscan.io/",
|
||||
"standard": "EIP3091"
|
||||
},
|
||||
{
|
||||
"name": "Celoscan",
|
||||
"url": "https://celoscan.io",
|
||||
|
||||
@@ -5,9 +5,9 @@ export default {
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://goerli.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://goerli.infura.io/v3/${INFURA_API_KEY}",
|
||||
"wss://goerli.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://eth-goerli.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://rpc.goerli.mudit.blog/",
|
||||
"https://ethereum-goerli.publicnode.com"
|
||||
],
|
||||
|
||||
@@ -5,7 +5,8 @@ export default {
|
||||
"rpc": [
|
||||
"https://rollux.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.rollux.com",
|
||||
"wss://rpc.rollux.com/wss"
|
||||
"wss://rpc.rollux.com/wss",
|
||||
"https://rpc.ankr.com/rollux/${ANKR_API_KEY}"
|
||||
],
|
||||
"faucets": [
|
||||
"https://rollux.id/faucetapp"
|
||||
|
||||
@@ -5,10 +5,10 @@ export default {
|
||||
"chain": "ETH",
|
||||
"rpc": [
|
||||
"https://linea-testnet.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://rpc.goerli.linea.build",
|
||||
"wss://rpc.goerli.linea.build",
|
||||
"https://linea-goerli.infura.io/v3/${INFURA_API_KEY}",
|
||||
"wss://linea-goerli.infura.io/v3/${INFURA_API_KEY}"
|
||||
"wss://linea-goerli.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://rpc.goerli.linea.build",
|
||||
"wss://rpc.goerli.linea.build"
|
||||
],
|
||||
"faucets": [
|
||||
"https://faucetlink.to/goerli"
|
||||
|
||||
@@ -4,7 +4,7 @@ export default {
|
||||
"chain": "ETC",
|
||||
"rpc": [
|
||||
"https://ethereum-classic.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://www.ethercluster.com/etc"
|
||||
"https://etc.rivet.link"
|
||||
],
|
||||
"faucets": [
|
||||
"https://free-online-app.com/faucet-for-eth-evm-chains/?"
|
||||
|
||||
@@ -4,7 +4,7 @@ export default {
|
||||
"chain": "ETC",
|
||||
"rpc": [
|
||||
"https://ethereum-classic-testnet-mordor.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://www.ethercluster.com/mordor"
|
||||
"https://rpc.mordor.etccooperative.org"
|
||||
],
|
||||
"faucets": [],
|
||||
"nativeCurrency": {
|
||||
|
||||
@@ -11,8 +11,8 @@ export default {
|
||||
},
|
||||
"rpc": [
|
||||
"https://mumbai.rpc.thirdweb.com/${THIRDWEB_API_KEY}",
|
||||
"https://polygon-mumbai.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://polygon-mumbai.infura.io/v3/${INFURA_API_KEY}",
|
||||
"https://polygon-mumbai.g.alchemy.com/v2/${ALCHEMY_API_KEY}",
|
||||
"https://matic-mumbai.chainstacklabs.com",
|
||||
"https://rpc-mumbai.maticvigil.com",
|
||||
"https://matic-testnet-archive-rpc.bwarelabs.com",
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
// @ts-check
|
||||
/** @typedef { import("../../src/types").Chain } Chain */
|
||||
|
||||
/** @type {Partial<Chain>} */
|
||||
export default {
|
||||
explorers: [
|
||||
{
|
||||
name: "Celoscan",
|
||||
url: "https://alfajores.celoscan.io/",
|
||||
standard: "EIP3091",
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/chains",
|
||||
"version": "0.1.24",
|
||||
"version": "0.1.26",
|
||||
"main": "dist/thirdweb-dev-chains.cjs.js",
|
||||
"module": "dist/thirdweb-dev-chains.esm.js",
|
||||
"browser": {
|
||||
|
||||
@@ -80,6 +80,33 @@ chains = chains
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Sort RPCs in chain
|
||||
* @param {Chain} chain
|
||||
*/
|
||||
function sortRPCs(chain) {
|
||||
const thirdwebRPCs = [];
|
||||
const alchemyRPCs = [];
|
||||
const infuraRPCs = [];
|
||||
const otherRPCs = [];
|
||||
|
||||
chain.rpc.forEach((rpc) => {
|
||||
if (rpc.includes("${THIRDWEB_API_KEY}")) {
|
||||
thirdwebRPCs.push(rpc);
|
||||
} else if (rpc.includes("${ALCHEMY_API_KEY}")) {
|
||||
alchemyRPCs.push(rpc);
|
||||
} else if (rpc.includes("${INFURA_API_KEY}")) {
|
||||
infuraRPCs.push(rpc);
|
||||
} else {
|
||||
otherRPCs.push(rpc);
|
||||
}
|
||||
});
|
||||
|
||||
chain.rpc = [...thirdwebRPCs, ...infuraRPCs, ...alchemyRPCs, ...otherRPCs];
|
||||
}
|
||||
|
||||
chains.forEach(sortRPCs);
|
||||
|
||||
const imports = [];
|
||||
const exports = [];
|
||||
const exportNames = [];
|
||||
@@ -146,6 +173,10 @@ function findSlug(chain) {
|
||||
if (slug === "base-goerli-testnet") {
|
||||
slug = "base-goerli";
|
||||
}
|
||||
// optimisim rename handling
|
||||
if (slug === "op") {
|
||||
slug = "optimism";
|
||||
}
|
||||
// end special cases
|
||||
|
||||
takenSlugs[slug] = true;
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -28,59 +28,45 @@ export function getChainRPCs(
|
||||
...options,
|
||||
};
|
||||
|
||||
const modeChains = chain.rpc.filter((rpc) => {
|
||||
if (rpc.startsWith("http") && mode === "http") {
|
||||
return true;
|
||||
}
|
||||
if (rpc.startsWith("ws") && mode === "ws") {
|
||||
return true;
|
||||
const processedRPCs: string[] = [];
|
||||
|
||||
chain.rpc.forEach((rpc) => {
|
||||
// exclude RPC if mode mismatch
|
||||
if (mode === "http" && !rpc.startsWith("http")) {
|
||||
return;
|
||||
}
|
||||
|
||||
return false;
|
||||
if (mode === "ws" && !rpc.startsWith("ws")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Replace API_KEY placeholder with value
|
||||
if (thirdwebApiKey && rpc.includes("${THIRDWEB_API_KEY}")) {
|
||||
processedRPCs.push(rpc.replace("${THIRDWEB_API_KEY}", thirdwebApiKey));
|
||||
} else if (infuraApiKey && rpc.includes("${INFURA_API_KEY}")) {
|
||||
processedRPCs.push(rpc.replace("${INFURA_API_KEY}", infuraApiKey));
|
||||
} else if (alchemyApiKey && rpc.includes("${ALCHEMY_API_KEY}")) {
|
||||
processedRPCs.push(rpc.replace("${ALCHEMY_API_KEY}", alchemyApiKey));
|
||||
}
|
||||
|
||||
// exclude RPCs with unknown placeholder
|
||||
else if (rpc.includes("${")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add as is
|
||||
else {
|
||||
processedRPCs.push(rpc);
|
||||
}
|
||||
});
|
||||
|
||||
const thirdwebRPC = modeChains
|
||||
.filter((rpc) => {
|
||||
return rpc.includes("${THIRDWEB_API_KEY}") && thirdwebApiKey;
|
||||
})
|
||||
.map((rpc) =>
|
||||
thirdwebApiKey ? rpc.replace("${THIRDWEB_API_KEY}", thirdwebApiKey) : rpc,
|
||||
);
|
||||
|
||||
const alchemyRPC = modeChains
|
||||
.filter((rpc) => {
|
||||
return rpc.includes("${ALCHEMY_API_KEY}") && alchemyApiKey;
|
||||
})
|
||||
.map((rpc) =>
|
||||
alchemyApiKey ? rpc.replace("${ALCHEMY_API_KEY}", alchemyApiKey) : rpc,
|
||||
);
|
||||
|
||||
const infuraRPC = modeChains
|
||||
.filter((rpc) => {
|
||||
return rpc.includes("${INFURA_API_KEY}") && infuraApiKey;
|
||||
})
|
||||
.map((rpc) =>
|
||||
infuraApiKey ? rpc.replace("${INFURA_API_KEY}", infuraApiKey) : rpc,
|
||||
);
|
||||
|
||||
const allOtherRpcs = modeChains.filter((rpc) => {
|
||||
return !rpc.includes("${");
|
||||
});
|
||||
|
||||
const orderedRPCs = [
|
||||
...thirdwebRPC,
|
||||
...infuraRPC,
|
||||
...alchemyRPC,
|
||||
...allOtherRpcs,
|
||||
];
|
||||
|
||||
if (orderedRPCs.length === 0) {
|
||||
if (processedRPCs.length === 0) {
|
||||
throw new Error(
|
||||
`No RPC available for chainId "${chain.chainId}" with mode ${mode}`,
|
||||
);
|
||||
}
|
||||
|
||||
return orderedRPCs;
|
||||
return processedRPCs;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,23 @@
|
||||
# thirdweb
|
||||
|
||||
## 0.10.28
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1274](https://github.com/thirdweb-dev/js/pull/1274) [`8fc5f204`](https://github.com/thirdweb-dev/js/commit/8fc5f204b00733089c02beee92c86b0f1fcac271) Thanks [@Marfuen](https://github.com/Marfuen)! - Added all detections for deploy command and some minor bug fixes
|
||||
|
||||
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8), [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad)]:
|
||||
- @thirdweb-dev/sdk@3.10.27
|
||||
- @thirdweb-dev/chains@0.1.26
|
||||
|
||||
## 0.10.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d), [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/sdk@3.10.26
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 0.10.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -2,7 +2,7 @@ import { CREATE_MESSAGES } from "../constants/constants";
|
||||
import { prepareEnvironment } from "@gmrchk/cli-testing-library";
|
||||
|
||||
// this creates an app, can take some time that's fine
|
||||
jest.setTimeout(120_000);
|
||||
jest.setTimeout(240_000);
|
||||
|
||||
describe("npx thirdweb detect", () => {
|
||||
it("should detect ERC721Base extensions", async () => {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "thirdweb",
|
||||
"main": "dist/cli/index.js",
|
||||
"version": "0.10.26",
|
||||
"version": "0.10.28",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/cli",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,27 +1,28 @@
|
||||
import inquirer from "inquirer";
|
||||
import { info } from "../helpers/logger";
|
||||
import { FrameworkType, PackageManagerType } from "../types/ProjectType";
|
||||
import inquirer from "inquirer";
|
||||
import NextDetector from "./frameworks/next";
|
||||
import CRADetector from "./frameworks/cra";
|
||||
import RemixDetector from "./frameworks/remix";
|
||||
import GatsbyDetector from "./frameworks/gatsby";
|
||||
import VueDetector from "./frameworks/vue";
|
||||
import ReactNativeCLIDetector from "./frameworks/reactNativeCli";
|
||||
import DjangoDetector from "./frameworks/django";
|
||||
import ExpoDetector from "./frameworks/expo";
|
||||
import FoundryDetector from "./frameworks/foundry";
|
||||
import HardhatDetector from "./frameworks/hardhat";
|
||||
import { FrameworkDetector } from "./detector";
|
||||
import TruffleDetector from "./frameworks/truffle";
|
||||
import BrownieDetector from "./frameworks/brownie";
|
||||
import FastAPIDetector from "./frameworks/fastAPI";
|
||||
import FlaskDetector from "./frameworks/flask";
|
||||
import PopulusDetector from "./frameworks/populus";
|
||||
import FastifyDetector from "./frameworks/fastify";
|
||||
import CRADetector from "./frameworks/cra";
|
||||
import DjangoDetector from "./frameworks/django";
|
||||
import EchoDetector from "./frameworks/echo";
|
||||
import ExpoDetector from "./frameworks/expo";
|
||||
import FastAPIDetector from "./frameworks/fastAPI";
|
||||
import FastifyDetector from "./frameworks/fastify";
|
||||
import FiberDetector from "./frameworks/fiber";
|
||||
import FlaskDetector from "./frameworks/flask";
|
||||
import FoundryDetector from "./frameworks/foundry";
|
||||
import GatsbyDetector from "./frameworks/gatsby";
|
||||
import GinDetector from "./frameworks/gin";
|
||||
import HardhatDetector from "./frameworks/hardhat";
|
||||
import NextDetector from "./frameworks/next";
|
||||
import PopulusDetector from "./frameworks/populus";
|
||||
import ReactNativeCLIDetector from "./frameworks/reactNativeCli";
|
||||
import RemixDetector from "./frameworks/remix";
|
||||
import RevelDetector from "./frameworks/revel";
|
||||
import TruffleDetector from "./frameworks/truffle";
|
||||
import ViteDetector from "./frameworks/vite";
|
||||
import VueDetector from "./frameworks/vue";
|
||||
import ZenjectDetector from "./frameworks/zenject";
|
||||
|
||||
export default async function detect(
|
||||
@@ -50,6 +51,7 @@ export default async function detect(
|
||||
new RevelDetector(),
|
||||
new TruffleDetector(),
|
||||
new VueDetector(),
|
||||
new ViteDetector(),
|
||||
new ZenjectDetector(),
|
||||
];
|
||||
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
import inquirer from "inquirer";
|
||||
import { info } from "../helpers/logger";
|
||||
import { LibraryType, PackageManagerType } from "../types/ProjectType";
|
||||
import { LibraryDetector } from "./detector";
|
||||
import inquirer from "inquirer";
|
||||
import ReactDetector from "./libraries/react";
|
||||
import ExpressDetector from "./libraries/express";
|
||||
import ReactNativeDetector from "./libraries/reactNative";
|
||||
import ViteDetector from "./libraries/vite";
|
||||
import Web3PyDetector from "./libraries/web3py";
|
||||
import PlayMakerDetector from "./libraries/playmaker";
|
||||
import ReactDetector from "./libraries/react";
|
||||
import ReactNativeDetector from "./libraries/reactNative";
|
||||
import Web3PyDetector from "./libraries/web3py";
|
||||
|
||||
export default async function detect(
|
||||
path: string,
|
||||
@@ -19,7 +18,6 @@ export default async function detect(
|
||||
new ExpressDetector(),
|
||||
new ReactDetector(),
|
||||
new ReactNativeDetector(),
|
||||
new ViteDetector(),
|
||||
new Web3PyDetector(),
|
||||
new PlayMakerDetector(),
|
||||
];
|
||||
|
||||
+5
-5
@@ -1,10 +1,10 @@
|
||||
import { LibraryDetector } from "../detector";
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import { LibraryType } from "../../types/ProjectType";
|
||||
import { parsePackageJson } from "../../../lib/utils";
|
||||
import { FrameworkType } from "../../types/ProjectType";
|
||||
import { FrameworkDetector } from "../detector";
|
||||
|
||||
export default class ViteDetector implements LibraryDetector {
|
||||
public libraryType: LibraryType = "vite";
|
||||
export default class ViteDetector implements FrameworkDetector {
|
||||
public frameworkType: FrameworkType = "vite";
|
||||
|
||||
public matches(path: string): boolean {
|
||||
const packageJsonPath = path + "/package.json";
|
||||
@@ -16,7 +16,7 @@ export default class ViteDetector implements LibraryDetector {
|
||||
const packageJson = readFileSync(packageJsonPath);
|
||||
const { dependencies, devDependencies } = parsePackageJson(packageJson);
|
||||
const viteDependencyExists =
|
||||
dependencies["vite"] || devDependencies["vite"] || false;
|
||||
!!dependencies["vite"] || !!devDependencies["vite"] || false;
|
||||
|
||||
return viteDependencyExists;
|
||||
}
|
||||
@@ -56,6 +56,7 @@ export type FrameworkType =
|
||||
| "revel"
|
||||
| "fiber"
|
||||
| "zenject"
|
||||
| "vite"
|
||||
| "none";
|
||||
export type LibraryType =
|
||||
| "react"
|
||||
|
||||
@@ -1,30 +1,57 @@
|
||||
import NPMDetector from "../core/detection/npm";
|
||||
import ViteDetector from "../core/detection/vite";
|
||||
import YarnDetector from "../core/detection/yarn";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import detectFramework from "../core/detection/detectFramework";
|
||||
import detectPackageManager from "../core/detection/detectPackageManager";
|
||||
import { logger } from "../core/helpers/logger";
|
||||
import { runCommand } from "../create/helpers/run-command";
|
||||
import { upload } from "../storage/command";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
|
||||
export async function deployApp(distPath = "dist", projectPath = ".") {
|
||||
const storage = new ThirdwebStorage();
|
||||
const supportedFrameworks = [new ViteDetector()];
|
||||
const detectedPackageManager = await detectPackageManager(projectPath, {});
|
||||
const detectedFramework = await detectFramework(projectPath, {}, detectedPackageManager);
|
||||
|
||||
const possibleProjects = supportedFrameworks
|
||||
.filter((detector) => detector.matches(projectPath))
|
||||
.map((detector) => detector.projectType);
|
||||
|
||||
const hasYarn = new YarnDetector().matches(".");
|
||||
const hasNPM = new NPMDetector().matches(".");
|
||||
|
||||
if (possibleProjects.length === 0) {
|
||||
if (detectedFramework === "none") {
|
||||
throw new Error("No supported project detected");
|
||||
}
|
||||
|
||||
switch (detectedFramework) {
|
||||
case "next":
|
||||
distPath = "out";
|
||||
break;
|
||||
case "cra":
|
||||
distPath = "build";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
logger.info(`Detected project type: ${detectedFramework}`);
|
||||
logger.info(`Detected package manager: ${detectedPackageManager}`);
|
||||
logger.info(`distPath: ${distPath}`);
|
||||
logger.info(`projectPath: ${projectPath}`);
|
||||
|
||||
try {
|
||||
if (hasYarn) {
|
||||
await runCommand("yarn", ["build"]);
|
||||
} else if (hasNPM) {
|
||||
await runCommand("npm", ["build"]);
|
||||
switch (detectedPackageManager) {
|
||||
case "yarn":
|
||||
await runCommand("yarn", ["build"], true);
|
||||
if (detectedFramework === "next") {
|
||||
await runCommand("yarn", ["export"], true);
|
||||
}
|
||||
break;
|
||||
case "npm":
|
||||
await runCommand("npm", ["run", "build"], true);
|
||||
if (detectedFramework === "next") {
|
||||
await runCommand("npm", ["run", "export"], true);
|
||||
}
|
||||
break;
|
||||
case "pnpm":
|
||||
await runCommand("pnpm", ["build"], true);
|
||||
if (detectedFramework === "next") {
|
||||
await runCommand("pnpm", ["export"], true);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("No supported package manager detected");
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Can't build project");
|
||||
@@ -33,9 +60,9 @@ export async function deployApp(distPath = "dist", projectPath = ".") {
|
||||
|
||||
try {
|
||||
const uri = await upload(storage, distPath);
|
||||
return `https://thirdweb.com/app/deploy/${uri.replace("ipfs://", "")}`;
|
||||
return `${uri.replace("ipfs://", "https://ipfs-public.thirdwebcdn.com/ipfs/")}`;
|
||||
} catch (err) {
|
||||
console.error("Can't upload project");
|
||||
console.error("Can't upload project", err);
|
||||
return Promise.reject("Can't upload project");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { spinner } from "../core/helpers/logger";
|
||||
import { BufferOrStringWithName, ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { spinner } from "../core/helpers/logger";
|
||||
|
||||
function recurseFiles(
|
||||
uploadPath: string,
|
||||
|
||||
@@ -1,5 +1,47 @@
|
||||
# @thirdweb-dev/react-core
|
||||
|
||||
## 3.14.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1271](https://github.com/thirdweb-dev/js/pull/1271) [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8) Thanks [@nkrishang](https://github.com/nkrishang)! - Rename smart wallets to account
|
||||
|
||||
- [#1273](https://github.com/thirdweb-dev/js/pull/1273) [`edcd22d6`](https://github.com/thirdweb-dev/js/commit/edcd22d61236edb2832f9b2f9796e891d58cb145) Thanks [@MananTank](https://github.com/MananTank)! - Add `autoConnectTimeout` to `ThirdwebProvider` to timeout wallet autoconnect
|
||||
|
||||
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8), [`be606dd3`](https://github.com/thirdweb-dev/js/commit/be606dd3c93c1514834c1d970e864d7f949a07ab), [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad), [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae)]:
|
||||
- @thirdweb-dev/wallets@1.0.3
|
||||
- @thirdweb-dev/sdk@3.10.27
|
||||
- @thirdweb-dev/chains@0.1.26
|
||||
|
||||
## 3.14.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ed711c8c`](https://github.com/thirdweb-dev/js/commit/ed711c8cb2ed6a0deb1b2a5eeec06df1d4edc5e8), [`05a7495a`](https://github.com/thirdweb-dev/js/commit/05a7495a132aabab5f48abbdb80a468ff6f65df8), [`e78da6b3`](https://github.com/thirdweb-dev/js/commit/e78da6b36cfa6d954234820563201bf760186ed1)]:
|
||||
- @thirdweb-dev/wallets@1.0.2
|
||||
|
||||
## 3.14.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08)]:
|
||||
- @thirdweb-dev/wallets@1.0.1
|
||||
|
||||
## 3.14.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1227](https://github.com/thirdweb-dev/js/pull/1227) [`06ca1c40`](https://github.com/thirdweb-dev/js/commit/06ca1c407dfee9d3d1fdaed1b6223ad0f9b8857b) Thanks [@nkrishang](https://github.com/nkrishang)! - Add react hooks for smart wallet
|
||||
|
||||
- [#1248](https://github.com/thirdweb-dev/js/pull/1248) [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087) Thanks [@nachoiacovino](https://github.com/nachoiacovino)! - Export account hooks
|
||||
|
||||
- [#1253](https://github.com/thirdweb-dev/js/pull/1253) [`ad7dae3b`](https://github.com/thirdweb-dev/js/commit/ad7dae3b163e61c7a6eb57f654885a7fdaa4cbb6) Thanks [@rattrayd11](https://github.com/rattrayd11)! - Stop using useActiveChain deprecated hook
|
||||
|
||||
- Updated dependencies [[`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d), [`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e), [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354), [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/sdk@3.10.26
|
||||
- @thirdweb-dev/wallets@1.0.0
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 3.14.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-core",
|
||||
"version": "3.14.3",
|
||||
"version": "3.14.7",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-core",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -113,10 +113,6 @@
|
||||
"ethers": ">=5.5.1",
|
||||
"react": ">=18.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"ansi-regex": "^6.0.1",
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@solana/web3.js": {
|
||||
"optional": true
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Chain, defaultChains } from "@thirdweb-dev/chains";
|
||||
import { useCallback, useState } from "react";
|
||||
import { useActiveChain, useChainId } from "../../evm/hooks/wallet";
|
||||
import { useChain, useChainId } from "../../evm/hooks/wallet";
|
||||
import { useSupportedChains } from "../../evm/hooks/useSupportedChains";
|
||||
import { useSwitchChain, useWallet } from "./wallet-hooks";
|
||||
import { assertWindowEthereum, walletIds } from "@thirdweb-dev/wallets";
|
||||
@@ -29,7 +29,7 @@ type NetworkMetadata = {
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated - use `useActiveChain`, `useSwitchChain`, `useChainId` instead
|
||||
* @deprecated - use `useChain`, `useSwitchChain`, `useChainId` instead
|
||||
*
|
||||
* Hook for getting metadata about the network the current wallet is connected to and switching networks
|
||||
*
|
||||
@@ -55,7 +55,7 @@ type NetworkMetadata = {
|
||||
* @public
|
||||
*/
|
||||
export function useNetwork(): [NetworkMetadata, SwitchNetwork | undefined] {
|
||||
const chain = useActiveChain();
|
||||
const chain = useChain();
|
||||
const chainId = useChainId();
|
||||
const switchChain = useSwitchChain();
|
||||
const supportedChains = useSupportedChains();
|
||||
|
||||
@@ -61,6 +61,15 @@ export interface ThirdwebProviderCoreProps<TChains extends Chain[]>
|
||||
* Whether or not to automatically switch to wallet's network to active chain
|
||||
*/
|
||||
autoSwitch?: boolean;
|
||||
|
||||
/**
|
||||
* Timeout for auto-connecting wallet in milliseconds
|
||||
*
|
||||
* If wallet fails to connect in this time, it will stop trying to connect and user will have to manually connect
|
||||
*
|
||||
* @defaultValue 15000
|
||||
*/
|
||||
autoConnectTimeout?: number;
|
||||
}
|
||||
|
||||
export const ThirdwebProviderCore = <TChains extends Chain[]>({
|
||||
@@ -145,6 +154,7 @@ export const ThirdwebProviderCore = <TChains extends Chain[]>({
|
||||
dAppMeta={dAppMeta}
|
||||
activeChain={activeChainWithKey}
|
||||
autoSwitch={props.autoSwitch}
|
||||
autoConnectTimeout={props.autoConnectTimeout}
|
||||
>
|
||||
<ThirdwebSDKProviderWrapper
|
||||
queryClient={props.queryClient}
|
||||
|
||||
@@ -101,12 +101,15 @@ export function ThirdwebWalletProvider(
|
||||
dAppMeta?: DAppMetaData;
|
||||
chains: Chain[];
|
||||
autoSwitch?: boolean;
|
||||
autoConnectTimeout?: number;
|
||||
}>,
|
||||
) {
|
||||
const [signer, setSigner] = useState<Signer | undefined>(undefined);
|
||||
const [connectionStatus, setConnectionStatus] =
|
||||
useState<ConnectionStatus>("unknown");
|
||||
|
||||
const autoConnectTimeout = props.autoConnectTimeout || 15000;
|
||||
|
||||
const [activeWallet, setActiveWallet] = useState<
|
||||
WalletInstance | undefined
|
||||
>();
|
||||
@@ -311,8 +314,14 @@ export function ThirdwebWalletProvider(
|
||||
const personalWalletInstance = createWalletInstance(personalWalleObj);
|
||||
|
||||
try {
|
||||
await personalWalletInstance.autoConnect(
|
||||
personalWalletInfo.connectParams,
|
||||
await timeoutPromise(
|
||||
personalWalletInstance.autoConnect(
|
||||
personalWalletInfo.connectParams,
|
||||
),
|
||||
{
|
||||
ms: autoConnectTimeout,
|
||||
message: "Failed to Auto connect. Auto connect timed out.",
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@@ -337,7 +346,10 @@ export function ThirdwebWalletProvider(
|
||||
|
||||
try {
|
||||
setConnectionStatus("connecting");
|
||||
await wallet.autoConnect(walletInfo.connectParams);
|
||||
await timeoutPromise(wallet.autoConnect(walletInfo.connectParams), {
|
||||
ms: autoConnectTimeout,
|
||||
message: "Failed to Auto connect. Auto connect timed out.",
|
||||
});
|
||||
setConnectedWallet(wallet, walletInfo.connectParams, true);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
@@ -356,6 +368,7 @@ export function ThirdwebWalletProvider(
|
||||
props.shouldAutoConnect,
|
||||
activeWallet,
|
||||
connectionStatus,
|
||||
autoConnectTimeout,
|
||||
]);
|
||||
|
||||
const connectWallet = useCallback(
|
||||
@@ -496,3 +509,32 @@ async function saveLastConnectedWalletInfo(
|
||||
console.error("Error saving the last connected wallet info", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeout a promise with a given Error message if the promise does not resolve in given time
|
||||
*
|
||||
* @param promise - Promise to track for timeout
|
||||
* @param option - timeout options
|
||||
* @returns
|
||||
*/
|
||||
function timeoutPromise<T>(
|
||||
promise: Promise<T>,
|
||||
option: { ms: number; message: string },
|
||||
) {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
reject(new Error(option.message));
|
||||
}, option.ms);
|
||||
|
||||
promise.then(
|
||||
(res) => {
|
||||
clearTimeout(timeoutId);
|
||||
resolve(res);
|
||||
},
|
||||
(err) => {
|
||||
clearTimeout(timeoutId);
|
||||
reject(err);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { WalletAddress } from "../../types";
|
||||
import {
|
||||
cacheKeys,
|
||||
invalidateContractAndBalances,
|
||||
} from "../../utils/cache-keys";
|
||||
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
|
||||
import {
|
||||
useMutation,
|
||||
useQueryClient,
|
||||
UseQueryResult,
|
||||
} from "@tanstack/react-query";
|
||||
import type { AccountEvent, SmartContract } from "@thirdweb-dev/sdk";
|
||||
import type { BytesLike } from "ethers";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/** **********************/
|
||||
/** READ HOOKS **/
|
||||
/** **********************/
|
||||
|
||||
/**
|
||||
* Get all accounts
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: accounts, isLoading, error } = useAccounts(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a account factory contract
|
||||
* @returns a response object that includes an array of all accounts with their associated admin
|
||||
* @twfeature AccountFactory
|
||||
* @see {@link https://portal.thirdweb.com/react/react.useaccounts?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useAccounts(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
): UseQueryResult<AccountEvent[]> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.accountFactory.getAll(contractAddress),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.accountFactory.getAllAccounts,
|
||||
"Contract instance does not support contract.accountFactory.getAllAccounts",
|
||||
);
|
||||
return contract.accountFactory.getAllAccounts();
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all accounts associated with the provided address
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: accountsForAddress, isLoading, error } = useAccountsForAddress(contract, "{{account_address}}");
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a account factory contract
|
||||
* @returns a response object that includes an array of all accounts associated with the adress
|
||||
* @twfeature AccountFactory
|
||||
* @see {@link https://portal.thirdweb.com/react/react.useaccountsforaddress?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useAccountsForAddress(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
address: RequiredParam<WalletAddress>,
|
||||
): UseQueryResult<string[]> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.accountFactory.getAllForAddress(
|
||||
contractAddress,
|
||||
address,
|
||||
),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.accountFactory.getAssociatedAccounts,
|
||||
"Contract instance does not support contract.accountFactory.getAssociatedAccounts",
|
||||
);
|
||||
return contract.accountFactory.getAssociatedAccounts(address || "");
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a account has been deployed for the given admin
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: isAccountDeployed, isLoading, error } = useIsAccountDeployed(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a account factory contract
|
||||
* @returns a boolean indicating if a account has been deployed for the given admin
|
||||
* @twfeature AccountFactory
|
||||
* @see {@link https://portal.thirdweb.com/react/react.useisaccountdeployed?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useIsAccountDeployed(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
admin: RequiredParam<WalletAddress>,
|
||||
extraData?: BytesLike,
|
||||
): UseQueryResult<boolean> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.accountFactory.isAccountDeployed(contractAddress, admin),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.accountFactory.isAccountDeployed,
|
||||
"Contract instance does not support contract.accountFactory.getAllAccounts",
|
||||
);
|
||||
invariant(admin, "No account address provided");
|
||||
return contract.accountFactory.isAccountDeployed(admin, extraData);
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
}
|
||||
|
||||
/** **********************/
|
||||
/** WRITE HOOKS **/
|
||||
/** **********************/
|
||||
/**
|
||||
* Create a account
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const { contract } = useContract("{{contract_address}}");
|
||||
* const {
|
||||
* mutate: createAccount,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useCreateAccount(contract);
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to create account", error);
|
||||
* }
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* disabled={isLoading}
|
||||
* onClick={() => createAccount("0x...")}
|
||||
* >
|
||||
* Create Account
|
||||
* </button>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a account factory contract
|
||||
* @returns a mutation object that can be used to create a account
|
||||
* @twfeature AccountFactory
|
||||
* @see {@link https://portal.thirdweb.com/react/react.usecreateaccount?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useCreateAccount(contract: RequiredParam<SmartContract>) {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
async (admin: string, extraData?: BytesLike) => {
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
|
||||
return contract.accountFactory.createAccount(admin, extraData);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
invalidateContractAndBalances(
|
||||
queryClient,
|
||||
contractAddress,
|
||||
activeChainId,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import type { providers } from "ethers";
|
||||
import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import {
|
||||
cacheKeys,
|
||||
invalidateContractAndBalances,
|
||||
} from "../../utils/cache-keys";
|
||||
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
|
||||
import {
|
||||
useMutation,
|
||||
UseMutationResult,
|
||||
useQueryClient,
|
||||
UseQueryResult,
|
||||
} from "@tanstack/react-query";
|
||||
import type {
|
||||
SignerWithRestrictions,
|
||||
SignerWithRestrictionsBatchInput,
|
||||
SmartContract,
|
||||
} from "@thirdweb-dev/sdk";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/** **********************/
|
||||
/** READ HOOKS **/
|
||||
/** **********************/
|
||||
|
||||
/**
|
||||
* Get all accounts
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: accounts, isLoading, error } = useAccountSigners(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a account
|
||||
* @returns a response object that includes an array of all signers of the provided account
|
||||
* @twfeature Account
|
||||
* @see {@link https://portal.thirdweb.com/react/react.useaccountsigners?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useAccountSigners(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
): UseQueryResult<SignerWithRestrictions[]> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.account.signers(contractAddress),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.account.getSignersWithRestrictions,
|
||||
"Contract instance does not support contract.account.getSignersWithRestrictions",
|
||||
);
|
||||
return contract.account.getSignersWithRestrictions();
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
}
|
||||
|
||||
/** **********************/
|
||||
/** WRITE HOOKS **/
|
||||
/** **********************/
|
||||
/**
|
||||
* Set the account's entire snapshot of permissions
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const { contract } = useContract("{{contract_address}}");
|
||||
* const {
|
||||
* mutate: setAccountSigners,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useSetAccountSigners(contract);
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to set account signers", error);
|
||||
* }
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* disabled={isLoading}
|
||||
* onClick={() => setAccountSigners("0x...")}
|
||||
* >
|
||||
* Set Account Signers
|
||||
* </button>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a account contract
|
||||
* @returns a mutation object that can be used to set the account signers
|
||||
* @twfeature Account
|
||||
* @see {@link https://portal.thirdweb.com/react/react.usesetaccountsigners?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useSetAccountSigners(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
): UseMutationResult<
|
||||
{ receipt: providers.TransactionReceipt },
|
||||
unknown,
|
||||
SignerWithRestrictionsBatchInput,
|
||||
unknown
|
||||
> {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
async (permissionsSnapshot: SignerWithRestrictionsBatchInput) => {
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
|
||||
return contract.account.setAccess(permissionsSnapshot);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
invalidateContractAndBalances(
|
||||
queryClient,
|
||||
contractAddress,
|
||||
activeChainId,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -504,7 +504,7 @@ export function useEnglishAuctionWinningBid(
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.auction.getWinningBid(
|
||||
cacheKeys.contract.marketplace.englishAuctions.getWinningBid(
|
||||
contractAddress,
|
||||
auctionId,
|
||||
),
|
||||
@@ -596,7 +596,7 @@ export function useBidBuffer(
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.getBidBufferBps(contractAddress),
|
||||
cacheKeys.contract.marketplace.auction.getBidBufferBps(contractAddress, listingId),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
|
||||
@@ -647,7 +647,7 @@ export function useMinimumNextBid(
|
||||
) {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.marketplace.auction.getWinner(
|
||||
cacheKeys.contract.marketplace.auction.getMinimumNextBid(
|
||||
contractAddress,
|
||||
listingId,
|
||||
),
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
import {
|
||||
RequiredParam,
|
||||
requiredParamInvariant,
|
||||
} from "../../../core/query-utils/required-param";
|
||||
import { useSDKChainId } from "../../providers/thirdweb-sdk-provider";
|
||||
import { WalletAddress } from "../../types";
|
||||
import {
|
||||
cacheKeys,
|
||||
invalidateContractAndBalances,
|
||||
} from "../../utils/cache-keys";
|
||||
import { useQueryWithNetwork } from "../query-utils/useQueryWithNetwork";
|
||||
import {
|
||||
useMutation,
|
||||
useQueryClient,
|
||||
UseQueryResult,
|
||||
} from "@tanstack/react-query";
|
||||
import type { AccountEvent, SmartContract } from "@thirdweb-dev/sdk";
|
||||
import type { BytesLike } from "ethers";
|
||||
import invariant from "tiny-invariant";
|
||||
|
||||
/** **********************/
|
||||
/** READ HOOKS **/
|
||||
/** **********************/
|
||||
|
||||
/**
|
||||
* Get all wallets
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: smartWallets, isLoading, error } = useSmartWallets(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a smart wallet factory contract
|
||||
* @returns a response object that includes an array of all smart wallets with their associated admin
|
||||
* @twfeature SmartWalletFactory
|
||||
* @see {@link https://portal.thirdweb.com/react/react.usesmartwallets?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useSmartWallets(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
): UseQueryResult<AccountEvent[]> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.smartWalletFactory.getAll(contractAddress),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.smartWalletFactory.getAllAccounts,
|
||||
"Contract instance does not support contract.smartWalletFactory.getAllAccounts",
|
||||
);
|
||||
return contract.smartWalletFactory.getAllAccounts();
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all wallets associated with the provided address
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: smartWalletsForAddress, isLoading, error } = useSmartWalletsForAddress(contract, "{{wallet_address}}");
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a smart wallet factory contract
|
||||
* @returns a response object that includes an array of all smart wallets associated with the adress
|
||||
* @twfeature SmartWalletFactory
|
||||
* @see {@link https://portal.thirdweb.com/react/react.usesmartwalletsforaddress?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useSmartWalletsForAddress(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
address: RequiredParam<WalletAddress>,
|
||||
): UseQueryResult<string[]> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.smartWalletFactory.getAllForAddress(
|
||||
contractAddress,
|
||||
address,
|
||||
),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.smartWalletFactory.getAssociatedWallets,
|
||||
"Contract instance does not support contract.smartWalletFactory.getAssociatedWallets",
|
||||
);
|
||||
return contract.smartWalletFactory.getAssociatedWallets(address || "");
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a smart wallet has been deployed for the given admin
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const { data: isSmartWalletDeployed, isLoading, error } = useIsSmartWalletDeployed(contract);
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a smart wallet factory contract
|
||||
* @returns a boolean indicating if a smart wallet has been deployed for the given admin
|
||||
* @twfeature SmartWalletFactory
|
||||
* @see {@link https://portal.thirdweb.com/react/react.useissmartwalletdeployed?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useIsSmartWalletDeployed(
|
||||
contract: RequiredParam<SmartContract>,
|
||||
admin: RequiredParam<WalletAddress>,
|
||||
extraData?: BytesLike,
|
||||
): UseQueryResult<boolean> {
|
||||
const contractAddress = contract?.getAddress();
|
||||
return useQueryWithNetwork(
|
||||
cacheKeys.contract.smartWalletFactory.isSmartWalletDeployed(
|
||||
contractAddress,
|
||||
admin,
|
||||
),
|
||||
() => {
|
||||
requiredParamInvariant(contract, "No Contract instance provided");
|
||||
invariant(
|
||||
contract.smartWalletFactory.isWalletDeployed,
|
||||
"Contract instance does not support contract.smartWalletFactory.getAllWallets",
|
||||
);
|
||||
invariant(admin, "No wallet address provided");
|
||||
return contract.smartWalletFactory.isWalletDeployed(admin, extraData);
|
||||
},
|
||||
{ enabled: !!contract },
|
||||
);
|
||||
}
|
||||
|
||||
/** **********************/
|
||||
/** WRITE HOOKS **/
|
||||
/** **********************/
|
||||
/**
|
||||
* Create a smart wallet
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* const Component = () => {
|
||||
* const { contract } = useContract("{{contract_address}}");
|
||||
* const {
|
||||
* mutate: createSmartWallet,
|
||||
* isLoading,
|
||||
* error,
|
||||
* } = useCreateSmartWallet(contract);
|
||||
*
|
||||
* if (error) {
|
||||
* console.error("failed to create smart wallet", error);
|
||||
* }
|
||||
*
|
||||
* return (
|
||||
* <button
|
||||
* disabled={isLoading}
|
||||
* onClick={() => createSmartWallet("0x...")}
|
||||
* >
|
||||
* Create Smart Wallet
|
||||
* </button>
|
||||
* );
|
||||
* };
|
||||
* ```
|
||||
*
|
||||
* @param contract - an instance of a smart wallet factory contract
|
||||
* @returns a mutation object that can be used to create a smart wallet
|
||||
* @twfeature SmartWalletFactory
|
||||
* @see {@link https://portal.thirdweb.com/react/react.usecreatesmartwallet?utm_source=sdk | Documentation}
|
||||
* @beta
|
||||
*/
|
||||
export function useCreateSmartWallet(contract: RequiredParam<SmartContract>) {
|
||||
const activeChainId = useSDKChainId();
|
||||
const contractAddress = contract?.getAddress();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation(
|
||||
async (admin: string, extraData?: BytesLike) => {
|
||||
requiredParamInvariant(contract, "contract is undefined");
|
||||
|
||||
return contract.smartWalletFactory.createWallet(admin, extraData);
|
||||
},
|
||||
{
|
||||
onSettled: () =>
|
||||
invalidateContractAndBalances(
|
||||
queryClient,
|
||||
contractAddress,
|
||||
activeChainId,
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -194,13 +194,16 @@ export {
|
||||
useBurnToken,
|
||||
} from "./hooks/async/token";
|
||||
|
||||
// smart wallet factory
|
||||
// account factory
|
||||
export {
|
||||
useIsSmartWalletDeployed,
|
||||
useSmartWallets,
|
||||
useCreateSmartWallet,
|
||||
useSmartWalletsForAddress,
|
||||
} from "./hooks/async/smart-wallet-factory";
|
||||
useIsAccountDeployed,
|
||||
useAccounts,
|
||||
useCreateAccount,
|
||||
useAccountsForAddress,
|
||||
} from "./hooks/async/account-factory";
|
||||
|
||||
// account
|
||||
export { useAccountSigners, useSetAccountSigners } from "./hooks/async/account";
|
||||
|
||||
// thirdweb hooks (work as long as at least `<ThirdwebSdkProvider>` is used)
|
||||
|
||||
|
||||
@@ -118,15 +118,25 @@ export const cacheKeys = {
|
||||
overrides,
|
||||
]),
|
||||
|
||||
smartWalletFactory: {
|
||||
accountFactory: {
|
||||
getAll: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, ["smartWalletFactory"]),
|
||||
isSmartWalletDeployed: (contractAdress: RequiredParam<ContractAddress>, admin: RequiredParam<string>) =>
|
||||
createContractCacheKey(contractAdress, ["isSmartWalletDeployed", admin]),
|
||||
getAllForAddress: (contractAdress: RequiredParam<ContractAddress>, address: RequiredParam<string>) =>
|
||||
createContractCacheKey(contractAddress, ["accountFactory"]),
|
||||
isAccountDeployed: (
|
||||
contractAdress: RequiredParam<ContractAddress>,
|
||||
admin: RequiredParam<string>,
|
||||
) => createContractCacheKey(contractAdress, ["isAccountDeployed", admin]),
|
||||
getAllForAddress: (
|
||||
contractAdress: RequiredParam<ContractAddress>,
|
||||
address: RequiredParam<string>,
|
||||
) =>
|
||||
createContractCacheKey(contractAdress, ["getAllForAddress", address]),
|
||||
},
|
||||
|
||||
account: {
|
||||
signers: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, ["account", "signers"]),
|
||||
},
|
||||
|
||||
app: {
|
||||
get: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, ["appURI"]),
|
||||
@@ -193,12 +203,8 @@ export const cacheKeys = {
|
||||
},
|
||||
},
|
||||
sharedMetadata: {
|
||||
get: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
) =>
|
||||
createContractCacheKey(
|
||||
contractAddress
|
||||
),
|
||||
get: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress),
|
||||
},
|
||||
drop: {
|
||||
getAllUnclaimed: (
|
||||
@@ -273,10 +279,16 @@ export const cacheKeys = {
|
||||
contractAddress,
|
||||
params ? ["getActiveListings", params] : ["getActiveListings"],
|
||||
),
|
||||
getBidBufferBps: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, ["getBidBufferBps"]),
|
||||
|
||||
auction: {
|
||||
getBidBufferBps: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"auction",
|
||||
"getBidBufferBps",
|
||||
{ listingId },
|
||||
]),
|
||||
getWinningBid: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
@@ -286,6 +298,15 @@ export const cacheKeys = {
|
||||
"getWinningBid",
|
||||
{ listingId },
|
||||
]),
|
||||
getMinimumNextBid: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"auction",
|
||||
"getMinimumNextBid",
|
||||
{ listingId },
|
||||
]),
|
||||
getWinner: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
@@ -305,8 +326,8 @@ export const cacheKeys = {
|
||||
createContractCacheKey(
|
||||
contractAddress,
|
||||
params
|
||||
? ["getAllDirectListings", params]
|
||||
: ["getAllDirectListings"],
|
||||
? ["directListings", "getAll", params]
|
||||
: ["directListings", "getAll"],
|
||||
),
|
||||
getAllValid: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
@@ -315,20 +336,22 @@ export const cacheKeys = {
|
||||
createContractCacheKey(
|
||||
contractAddress,
|
||||
params
|
||||
? ["getAllValidDirectListings", params]
|
||||
: ["getAllValidDirectListings"],
|
||||
? ["directListings", "getAllValid", params]
|
||||
: ["directListings", "getAllValid"],
|
||||
),
|
||||
getListing: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
listingId: RequiredParam<BigNumberish>,
|
||||
) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"directListings",
|
||||
"getListing",
|
||||
{ listingId },
|
||||
]),
|
||||
getTotalCount: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"getTotalDirectListingsCount",
|
||||
"directListings",
|
||||
"getTotalCount",
|
||||
]),
|
||||
},
|
||||
|
||||
@@ -340,8 +363,8 @@ export const cacheKeys = {
|
||||
createContractCacheKey(
|
||||
contractAddress,
|
||||
params
|
||||
? ["getAllEnglishAuctions", params]
|
||||
: ["getAllEnglishAuctions"],
|
||||
? ["englishAuctions", "getAll", params]
|
||||
: ["englishAuctions", "getAll"],
|
||||
),
|
||||
getAllValid: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
@@ -350,14 +373,15 @@ export const cacheKeys = {
|
||||
createContractCacheKey(
|
||||
contractAddress,
|
||||
params
|
||||
? ["getAllEValidEnglishAuctions", params]
|
||||
: ["getAllEValidEnglishAuctions"],
|
||||
? ["englishAuctions", "getAllValid", params]
|
||||
: ["englishAuctions", "getAllValid"],
|
||||
),
|
||||
getAuction: (
|
||||
contractAddress: RequiredParam<ContractAddress>,
|
||||
auctionId: RequiredParam<BigNumberish>,
|
||||
) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"englishAuctions",
|
||||
"getAuction",
|
||||
{ auctionId },
|
||||
]),
|
||||
@@ -366,12 +390,14 @@ export const cacheKeys = {
|
||||
auctionId: RequiredParam<BigNumberish>,
|
||||
) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"englishAuctions",
|
||||
"getWinningBid",
|
||||
{ auctionId },
|
||||
]),
|
||||
getTotalCount: (contractAddress: RequiredParam<ContractAddress>) =>
|
||||
createContractCacheKey(contractAddress, [
|
||||
"getTotalEnglishAuctionsCount",
|
||||
"englishAuctions",
|
||||
"getTotalCount",
|
||||
]),
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# @thirdweb-dev/react-native-compat
|
||||
|
||||
## 0.2.26
|
||||
|
||||
## 0.2.25
|
||||
|
||||
## 0.2.24
|
||||
|
||||
## 0.2.23
|
||||
|
||||
## 0.2.22
|
||||
|
||||
## 0.2.21
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native-compat",
|
||||
"description": "Shims for Thirdweb in React Native Projects",
|
||||
"version": "0.2.22",
|
||||
"version": "0.2.26",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native-compat",
|
||||
"license": "Apache-2.0",
|
||||
|
||||
@@ -1,5 +1,49 @@
|
||||
# @thirdweb-dev/react-native
|
||||
|
||||
## 0.2.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1270](https://github.com/thirdweb-dev/js/pull/1270) [`0d5503aa`](https://github.com/thirdweb-dev/js/commit/0d5503aae90d9cd7a7adcabad19f7f45d9a37063) Thanks [@iketw](https://github.com/iketw)! - Only handle Coinbase callback URL if Coinbase is added as a supportedWallet
|
||||
|
||||
- [#1277](https://github.com/thirdweb-dev/js/pull/1277) [`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - remove ethers/lib/utils dependency
|
||||
|
||||
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8), [`be606dd3`](https://github.com/thirdweb-dev/js/commit/be606dd3c93c1514834c1d970e864d7f949a07ab), [`edcd22d6`](https://github.com/thirdweb-dev/js/commit/edcd22d61236edb2832f9b2f9796e891d58cb145), [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad), [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae)]:
|
||||
- @thirdweb-dev/wallets@1.0.3
|
||||
- @thirdweb-dev/sdk@3.10.27
|
||||
- @thirdweb-dev/react-core@3.14.7
|
||||
- @thirdweb-dev/chains@0.1.26
|
||||
|
||||
## 0.2.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ed711c8c`](https://github.com/thirdweb-dev/js/commit/ed711c8cb2ed6a0deb1b2a5eeec06df1d4edc5e8), [`05a7495a`](https://github.com/thirdweb-dev/js/commit/05a7495a132aabab5f48abbdb80a468ff6f65df8), [`e78da6b3`](https://github.com/thirdweb-dev/js/commit/e78da6b36cfa6d954234820563201bf760186ed1)]:
|
||||
- @thirdweb-dev/wallets@1.0.2
|
||||
- @thirdweb-dev/react-core@3.14.6
|
||||
|
||||
## 0.2.24
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08)]:
|
||||
- @thirdweb-dev/wallets@1.0.1
|
||||
- @thirdweb-dev/react-core@3.14.5
|
||||
|
||||
## 0.2.23
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1215](https://github.com/thirdweb-dev/js/pull/1215) [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc) Thanks [@iketw](https://github.com/iketw)! - Migrate wallets to WCV2 and remove WCV1 support.
|
||||
|
||||
Please, check our changelogs for more info: https://blog.thirdweb.com/changelog/
|
||||
|
||||
- Updated dependencies [[`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d), [`06ca1c40`](https://github.com/thirdweb-dev/js/commit/06ca1c407dfee9d3d1fdaed1b6223ad0f9b8857b), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e), [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354), [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc), [`ad7dae3b`](https://github.com/thirdweb-dev/js/commit/ad7dae3b163e61c7a6eb57f654885a7fdaa4cbb6), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/sdk@3.10.26
|
||||
- @thirdweb-dev/react-core@3.14.4
|
||||
- @thirdweb-dev/wallets@1.0.0
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 0.2.22
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react-native",
|
||||
"version": "0.2.22",
|
||||
"version": "0.2.26",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react-native",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -44,10 +44,6 @@
|
||||
"react-native-svg": "^13.8.0",
|
||||
"tiny-invariant": "^1.2.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"react-native-mmkv": "2.5.1",
|
||||
"@magic-sdk/provider": "17.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.19.3",
|
||||
"@babel/preset-env": "^7.1.6",
|
||||
|
||||
@@ -17,7 +17,6 @@ export { localWallet } from "./wallets/wallets/local-wallet";
|
||||
export { LocalWallet } from "./wallets/wallets/LocalWallet";
|
||||
export { magicWallet } from "./wallets/wallets/magic-wallet";
|
||||
export { MagicWallet } from "./wallets/wallets/MagicWallet";
|
||||
export * from "./wallets/wallets/WalletConnectV1";
|
||||
export * from "./wallets/wallets/WalletConnectV2";
|
||||
export type { WCMeta } from "./wallets/types/wc";
|
||||
|
||||
|
||||
@@ -65,7 +65,9 @@ export const ThirdwebProvider = <
|
||||
theme,
|
||||
...restProps
|
||||
}: PropsWithChildren<ThirdwebProviderProps<TChains>>) => {
|
||||
useCoinbaseWalletListener();
|
||||
useCoinbaseWalletListener(
|
||||
!!supportedWallets.find((w) => w.id === walletIds.coinbase),
|
||||
);
|
||||
|
||||
const hasMagicConfig = useMemo(
|
||||
() => !!supportedWallets.find((wc) => wc.id === walletIds.magicLink),
|
||||
|
||||
@@ -17,8 +17,7 @@ import {
|
||||
WagmiConnector,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import type { Address } from "abitype";
|
||||
import { providers } from "ethers";
|
||||
import { getAddress, hexValue } from "ethers/lib/utils.js";
|
||||
import { providers, utils } from "ethers";
|
||||
|
||||
export type CoinbaseWalletConnectorOptions = WalletMobileSDKProviderOptions &
|
||||
ConfigurationParams & {
|
||||
@@ -130,7 +129,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
|
||||
throw new Error("No accounts found");
|
||||
}
|
||||
// return checksum address
|
||||
return getAddress(accounts[0] as string);
|
||||
return utils.getAddress(accounts[0] as string);
|
||||
}
|
||||
|
||||
async getChainId() {
|
||||
@@ -193,7 +192,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
|
||||
|
||||
async switchChain(chainId: number): Promise<Chain> {
|
||||
const provider = await this.getProvider();
|
||||
const id = hexValue(chainId);
|
||||
const id = utils.hexValue(chainId);
|
||||
|
||||
try {
|
||||
await provider.request({
|
||||
@@ -279,7 +278,7 @@ export class CoinbaseWalletConnector extends WagmiConnector<
|
||||
if (accounts.length === 0) {
|
||||
this.emit("disconnect");
|
||||
} else {
|
||||
this.emit("change", { account: getAddress(accounts[0] as string) });
|
||||
this.emit("change", { account: utils.getAddress(accounts[0] as string) });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import { useCoinbaseWalletListener } from "./useCoinbaseWalletListener";
|
||||
*/
|
||||
export function useCoinbaseWallet(callbackURL: string) {
|
||||
const connect = useConnect();
|
||||
useCoinbaseWalletListener();
|
||||
useCoinbaseWalletListener(true);
|
||||
|
||||
return useCallback(
|
||||
async (connectOptions?: { chainId?: number; callbackURL: string }) => {
|
||||
|
||||
@@ -7,12 +7,16 @@ import { Linking } from "react-native";
|
||||
*
|
||||
* This hook sets up the UniversalLinks listener.
|
||||
*/
|
||||
export function useCoinbaseWalletListener() {
|
||||
export function useCoinbaseWalletListener(enable: boolean) {
|
||||
useEffect(() => {
|
||||
if (!enable) {
|
||||
return;
|
||||
}
|
||||
|
||||
const sub = Linking.addEventListener("url", ({ url }) => {
|
||||
// @ts-ignore - Passing a URL object to handleResponse crashes the function
|
||||
handleResponse(url);
|
||||
});
|
||||
return () => sub?.remove();
|
||||
}, []);
|
||||
}, [enable]);
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import {
|
||||
WalletOptions,
|
||||
WalletConnectV1Options,
|
||||
WalletConnectV1 as WalletConnectV1Wallets,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import { formatWalletConnectDisplayUri } from "../../utils/uri";
|
||||
import { Linking } from "react-native";
|
||||
import { ExtraCoreWalletOptions } from "@thirdweb-dev/react-core";
|
||||
import { WCMeta } from "../types/wc";
|
||||
import { createAsyncLocalStorage } from "../../../core/AsyncStorage";
|
||||
|
||||
export type WC1Options = Omit<
|
||||
WalletOptions<WalletConnectV1Options>,
|
||||
"qrcode" | "walletId"
|
||||
> &
|
||||
ExtraCoreWalletOptions & {
|
||||
walletId: NonNullable<WalletOptions["walletId"]>;
|
||||
};
|
||||
|
||||
export abstract class WalletConnectV1 extends WalletConnectV1Wallets {
|
||||
constructor(options: WC1Options) {
|
||||
super({
|
||||
...options,
|
||||
walletId: options.walletId,
|
||||
walletStorage:
|
||||
options.walletStorage || createAsyncLocalStorage(options.walletId),
|
||||
qrcode: false,
|
||||
});
|
||||
|
||||
this.on("open_wallet", this._onWCOpenWallet);
|
||||
|
||||
this.on("disconnect", () => {
|
||||
this.removeListener("open_wallet", this._onWCOpenWallet);
|
||||
});
|
||||
}
|
||||
|
||||
abstract getMeta(): WCMeta;
|
||||
|
||||
_onWCOpenWallet(uri?: string) {
|
||||
const links = this.getMeta().links;
|
||||
|
||||
if (uri) {
|
||||
const fullUrl = formatWalletConnectDisplayUri(uri, links);
|
||||
|
||||
Linking.openURL(fullUrl);
|
||||
} else {
|
||||
const fullUrl = formatWalletConnectDisplayUri("", links);
|
||||
|
||||
Linking.openURL(fullUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
import { walletIds } from "@thirdweb-dev/wallets";
|
||||
import { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { WalletConnectV1 } from "./WalletConnectV1";
|
||||
import { WalletConnectV2 } from "./WalletConnectV2";
|
||||
import { WCMeta } from "../types/wc";
|
||||
|
||||
export class MetaMaskWallet extends WalletConnectV1 {
|
||||
export class MetaMaskWallet extends WalletConnectV2 {
|
||||
static id = walletIds.metamask;
|
||||
static meta = {
|
||||
name: "MetaMask",
|
||||
@@ -20,11 +20,17 @@ export class MetaMaskWallet extends WalletConnectV1 {
|
||||
}
|
||||
}
|
||||
|
||||
export const metamaskWallet = () => {
|
||||
type MetaMaskWalletConfig = { projectId?: string };
|
||||
|
||||
export const metamaskWallet = (config?: MetaMaskWalletConfig) => {
|
||||
return {
|
||||
id: MetaMaskWallet.id,
|
||||
meta: MetaMaskWallet.meta,
|
||||
create: (options: WalletOptions) =>
|
||||
new MetaMaskWallet({ ...options, walletId: walletIds.metamask }),
|
||||
new MetaMaskWallet({
|
||||
...options,
|
||||
walletId: walletIds.metamask,
|
||||
projectId: config?.projectId,
|
||||
}),
|
||||
} satisfies WalletConfig;
|
||||
};
|
||||
|
||||
@@ -2,9 +2,9 @@ import {
|
||||
WalletOptions as WalletOptionsRC,
|
||||
WalletConfig,
|
||||
} from "@thirdweb-dev/react-core";
|
||||
import { WalletConnectV1 } from "./WalletConnectV1";
|
||||
import { WalletConnectV2 } from "./WalletConnectV2";
|
||||
|
||||
export class RainbowWallet extends WalletConnectV1 {
|
||||
export class RainbowWallet extends WalletConnectV2 {
|
||||
static id = "rainbow" as const;
|
||||
static meta = {
|
||||
name: "Rainbow",
|
||||
@@ -21,11 +21,17 @@ export class RainbowWallet extends WalletConnectV1 {
|
||||
}
|
||||
}
|
||||
|
||||
export const rainbowWallet = () => {
|
||||
type RainbowWalletConfig = { projectId?: string };
|
||||
|
||||
export const rainbowWallet = (config?: RainbowWalletConfig) => {
|
||||
return {
|
||||
id: RainbowWallet.id,
|
||||
meta: RainbowWallet.meta,
|
||||
create: (options: WalletOptionsRC) =>
|
||||
new RainbowWallet({ ...options, walletId: RainbowWallet.id }),
|
||||
new RainbowWallet({
|
||||
...options,
|
||||
walletId: RainbowWallet.id,
|
||||
projectId: config?.projectId,
|
||||
}),
|
||||
} satisfies WalletConfig;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { WC2Options, WalletConnectV2 } from "./WalletConnectV2";
|
||||
import { WalletConnectV2 } from "./WalletConnectV2";
|
||||
import { WCMeta } from "../types/wc";
|
||||
|
||||
export class TrustWallet extends WalletConnectV2 {
|
||||
@@ -14,10 +14,6 @@ export class TrustWallet extends WalletConnectV2 {
|
||||
},
|
||||
};
|
||||
|
||||
constructor(options: WC2Options) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
getMeta(): WCMeta {
|
||||
return TrustWallet.meta;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,51 @@
|
||||
# @thirdweb-dev/react
|
||||
|
||||
## 3.14.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1210](https://github.com/thirdweb-dev/js/pull/1210) [`d794b8f9`](https://github.com/thirdweb-dev/js/commit/d794b8f9f41dbd7e461ef07d0808c5b6d2f85515) Thanks [@konojunya](https://github.com/konojunya)! - Add zerion to useInstalledWallets
|
||||
|
||||
- [#1269](https://github.com/thirdweb-dev/js/pull/1269) [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae) Thanks [@MananTank](https://github.com/MananTank)! - - Expose `advancedOptions` and `styles` for paper wallet
|
||||
- Allow using "+" in paper email
|
||||
- Allow using "+" in magic email
|
||||
- Update Paper SDK version
|
||||
- Updated dependencies [[`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053), [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8), [`be606dd3`](https://github.com/thirdweb-dev/js/commit/be606dd3c93c1514834c1d970e864d7f949a07ab), [`edcd22d6`](https://github.com/thirdweb-dev/js/commit/edcd22d61236edb2832f9b2f9796e891d58cb145), [`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad), [`998e5217`](https://github.com/thirdweb-dev/js/commit/998e521733efd6a67e42f9bf0beab5fbdccf08ae)]:
|
||||
- @thirdweb-dev/wallets@1.0.3
|
||||
- @thirdweb-dev/sdk@3.10.27
|
||||
- @thirdweb-dev/react-core@3.14.7
|
||||
- @thirdweb-dev/chains@0.1.26
|
||||
|
||||
## 3.14.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`ed711c8c`](https://github.com/thirdweb-dev/js/commit/ed711c8cb2ed6a0deb1b2a5eeec06df1d4edc5e8), [`05a7495a`](https://github.com/thirdweb-dev/js/commit/05a7495a132aabab5f48abbdb80a468ff6f65df8), [`e78da6b3`](https://github.com/thirdweb-dev/js/commit/e78da6b36cfa6d954234820563201bf760186ed1)]:
|
||||
- @thirdweb-dev/wallets@1.0.2
|
||||
- @thirdweb-dev/react-core@3.14.6
|
||||
|
||||
## 3.14.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies [[`efb3546e`](https://github.com/thirdweb-dev/js/commit/efb3546ec8268156be00301af28b9d83ecd5ab08)]:
|
||||
- @thirdweb-dev/wallets@1.0.1
|
||||
- @thirdweb-dev/react-core@3.14.5
|
||||
|
||||
## 3.14.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1215](https://github.com/thirdweb-dev/js/pull/1215) [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc) Thanks [@iketw](https://github.com/iketw)! - Migrate wallets to WCV2 and remove WCV1 support.
|
||||
|
||||
Please, check our changelogs for more info: https://blog.thirdweb.com/changelog/
|
||||
|
||||
- Updated dependencies [[`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d), [`06ca1c40`](https://github.com/thirdweb-dev/js/commit/06ca1c407dfee9d3d1fdaed1b6223ad0f9b8857b), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`ac3e019c`](https://github.com/thirdweb-dev/js/commit/ac3e019cd1776dbdb0d06b213420ad17586f678e), [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354), [`3c5dc480`](https://github.com/thirdweb-dev/js/commit/3c5dc4804abc56b933ec45e9e1da11eb182296cc), [`ad7dae3b`](https://github.com/thirdweb-dev/js/commit/ad7dae3b163e61c7a6eb57f654885a7fdaa4cbb6), [`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/sdk@3.10.26
|
||||
- @thirdweb-dev/react-core@3.14.4
|
||||
- @thirdweb-dev/wallets@1.0.0
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 3.14.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/react",
|
||||
"version": "3.14.3",
|
||||
"version": "3.14.7",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/react",
|
||||
"author": "thirdweb eng <[email protected]>",
|
||||
"license": "Apache-2.0",
|
||||
@@ -153,10 +153,6 @@
|
||||
"react": ">=18.0.0",
|
||||
"react-dom": ">=18.0.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"ansi-regex": "^6.0.1",
|
||||
"typescript": "^4.6.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@solana/wallet-adapter-base": {
|
||||
"optional": true
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { useConnect, useWallet } from "@thirdweb-dev/react-core";
|
||||
import { PaperWallet, walletIds } from "@thirdweb-dev/wallets";
|
||||
import {
|
||||
PaperWallet,
|
||||
walletIds,
|
||||
PaperWalletAdditionalOptions,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import { useCallback, useEffect } from "react";
|
||||
import {
|
||||
useQuery,
|
||||
@@ -7,10 +11,12 @@ import {
|
||||
useQueryClient,
|
||||
} from "@tanstack/react-query";
|
||||
|
||||
type PaperConfig = Omit<PaperWalletAdditionalOptions, "chain" | "chains">;
|
||||
|
||||
export function usePaperWallet() {
|
||||
const connect = useConnect();
|
||||
return useCallback(
|
||||
async (options: { chainId?: number; clientId: string; email?: string }) => {
|
||||
async (options: { chainId?: number; email?: string } & PaperConfig) => {
|
||||
const { paperWallet } = await import(
|
||||
"../../../wallet/wallets/paperWallet"
|
||||
);
|
||||
|
||||
@@ -18,15 +18,15 @@ interface ThirdwebProviderProps<TChains extends Chain[]>
|
||||
"createWalletStorage" | "supportedWallets"
|
||||
> {
|
||||
/**
|
||||
* Wallets that will be supported by the dApp
|
||||
* @defaultValue [metamaskWallet(), coinbaseWallet(), walletConnectV1()]
|
||||
* Wallets supported by the dApp
|
||||
* @defaultValue `[ metamaskWallet(), coinbaseWallet(), walletConnect() ]`
|
||||
*
|
||||
* @example
|
||||
* ```jsx
|
||||
* import { metamaskWallet, coinbaseWallet, walletConnectV1 } from "@thirdweb-dev/react";
|
||||
* import { metamaskWallet, coinbaseWallet, walletConnect } from "@thirdweb-dev/react";
|
||||
*
|
||||
* <ThirdwebProvider
|
||||
* supportedWallets={[metamaskWallet(), coinbaseWallet(), walletConnectV1()]}
|
||||
* supportedWallets={[metamaskWallet(), coinbaseWallet(), walletConnect()]}
|
||||
* />
|
||||
* ```
|
||||
*/
|
||||
|
||||
@@ -385,6 +385,17 @@ const NetworkList = /* @__PURE__ */ memo(function NetworkList(props: {
|
||||
const [switchingChainId, setSwitchingChainId] = useState(-1);
|
||||
const [errorSwitchingChainId, setErrorSwitchingChainId] = useState(-1);
|
||||
|
||||
const close = props.close;
|
||||
|
||||
useEffect(() => {
|
||||
// if switching and switched successfully - close modal
|
||||
if (switchingChainId !== -1 && activeChainId === switchingChainId) {
|
||||
if (close) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
}, [switchingChainId, close, activeChainId]);
|
||||
|
||||
const handleSwitch = async (chain: Chain) => {
|
||||
setErrorSwitchingChainId(-1);
|
||||
setSwitchingChainId(chain.chainId);
|
||||
|
||||
@@ -3,22 +3,22 @@ import { assertWindowEthereum } from "@thirdweb-dev/wallets";
|
||||
export function useInstalledWallets() {
|
||||
let isMetamaskInstalled = false;
|
||||
let isCoinbaseWalletInstalled = false;
|
||||
let isTrustWalletInstalled: boolean | undefined = false;
|
||||
let isZerionWalletInstalled = false;
|
||||
let isTrustWalletInstalled = false;
|
||||
|
||||
if (assertWindowEthereum(globalThis.window)) {
|
||||
isMetamaskInstalled = globalThis.window.ethereum?.isMetaMask;
|
||||
isMetamaskInstalled = !!globalThis.window.ethereum?.isMetaMask;
|
||||
isCoinbaseWalletInstalled =
|
||||
globalThis.window.ethereum?.isCoinbaseWallet ||
|
||||
globalThis.window.ethereum?.providers?.some((p) => p.isCoinbaseWallet) ||
|
||||
false;
|
||||
isTrustWalletInstalled = globalThis.window.ethereum?.isTrust;
|
||||
!!globalThis.window.ethereum?.isCoinbaseWallet ||
|
||||
!!globalThis.window.ethereum?.providers?.some((p) => p.isCoinbaseWallet);
|
||||
isZerionWalletInstalled = !!globalThis.window.ethereum?.isZerion;
|
||||
isTrustWalletInstalled = !!globalThis.window.ethereum?.isTrust;
|
||||
}
|
||||
|
||||
const installedWallets = {
|
||||
metamask: !!isMetamaskInstalled,
|
||||
coinbaseWallet: !!isCoinbaseWalletInstalled,
|
||||
trustWallet: !!isTrustWalletInstalled,
|
||||
return {
|
||||
metamask: isMetamaskInstalled,
|
||||
coinbaseWallet: isCoinbaseWalletInstalled,
|
||||
trustWallet: isTrustWalletInstalled,
|
||||
zerionWallet: isZerionWalletInstalled,
|
||||
};
|
||||
|
||||
return installedWallets;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { coinbaseWallet } from "./coinbase/coinbaseWallet";
|
||||
import { metamaskWallet } from "./metamask/metamaskWallet";
|
||||
import { walletConnectV1 } from "./walletConnectV1";
|
||||
import { walletConnect } from "./walletConnect";
|
||||
|
||||
export const defaultWallets: WalletConfig<any>[] = /* @__PURE__ */ (() => [
|
||||
metamaskWallet(),
|
||||
coinbaseWallet(),
|
||||
walletConnectV1(),
|
||||
walletConnect(),
|
||||
])();
|
||||
|
||||
@@ -79,7 +79,7 @@ const MagicSelectionUI: React.FC<
|
||||
|
||||
if (isEmail && isEmailEnabled) {
|
||||
const emailRegex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,})$/g;
|
||||
const isValidEmail = emailRegex.test(input);
|
||||
const isValidEmail = emailRegex.test(input.replace(/\+/g, ""));
|
||||
if (!isValidEmail) {
|
||||
return "Invalid email address";
|
||||
}
|
||||
|
||||
@@ -2,12 +2,28 @@ import type { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { MetaMaskWallet, assertWindowEthereum } from "@thirdweb-dev/wallets";
|
||||
import { MetamaskConnectUI } from "./MetamaskConnectUI";
|
||||
|
||||
export const metamaskWallet = (): WalletConfig<MetaMaskWallet> => {
|
||||
type MetamaskWalletOptions = {
|
||||
/**
|
||||
* When connecting MetaMask using the QR Code - Wallet Connect connector is used which requires a project id.
|
||||
* This project id is Your project’s unique identifier for wallet connect that can be obtained at cloud.walletconnect.com.
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#projectid-required
|
||||
*/
|
||||
projectId?: string;
|
||||
};
|
||||
|
||||
export const metamaskWallet = (
|
||||
options?: MetamaskWalletOptions,
|
||||
): WalletConfig<MetaMaskWallet> => {
|
||||
return {
|
||||
id: MetaMaskWallet.id,
|
||||
meta: MetaMaskWallet.meta,
|
||||
create: (options: WalletOptions) => {
|
||||
return new MetaMaskWallet({ ...options, qrcode: false });
|
||||
create: (walletOptions: WalletOptions) => {
|
||||
return new MetaMaskWallet({
|
||||
...walletOptions,
|
||||
projectId: options?.projectId,
|
||||
qrcode: false,
|
||||
});
|
||||
},
|
||||
connectUI: MetamaskConnectUI,
|
||||
isInstalled() {
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { PaperWallet } from "@thirdweb-dev/wallets";
|
||||
import {
|
||||
PaperWallet,
|
||||
PaperWalletAdditionalOptions,
|
||||
} from "@thirdweb-dev/wallets";
|
||||
import {
|
||||
WalletConfig,
|
||||
WalletOptions,
|
||||
@@ -11,7 +14,7 @@ import { Spinner } from "../../components/Spinner";
|
||||
import { Flex } from "../../components/basic";
|
||||
import { InputSelectionUI } from "./InputSelectionUI";
|
||||
|
||||
type PaperConfig = { clientId: string };
|
||||
type PaperConfig = Omit<PaperWalletAdditionalOptions, "chain" | "chains">;
|
||||
|
||||
export const paperWallet = (config: PaperConfig): WalletConfig<PaperWallet> => {
|
||||
return {
|
||||
@@ -32,7 +35,8 @@ const PaperSelectionUI: React.FC<SelectUIProps<PaperWallet>> = (props) => {
|
||||
placeholder="Enter your email address"
|
||||
name="email"
|
||||
type="email"
|
||||
errorMessage={(input) => {
|
||||
errorMessage={(_input) => {
|
||||
const input = _input.replace(/\+/g, "");
|
||||
const emailRegex = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,})$/g;
|
||||
const isValidEmail = emailRegex.test(input);
|
||||
if (!isValidEmail) {
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import { WalletConnectV1 } from "@thirdweb-dev/wallets";
|
||||
import { WalletConfig, WalletOptions } from "@thirdweb-dev/react-core";
|
||||
import { walletConnect } from "./walletConnect";
|
||||
|
||||
export const walletConnectV1 = (): WalletConfig<WalletConnectV1> => {
|
||||
return {
|
||||
id: WalletConnectV1.id,
|
||||
meta: WalletConnectV1.meta,
|
||||
create(options: WalletOptions) {
|
||||
return new WalletConnectV1({ ...options, qrcode: true });
|
||||
},
|
||||
};
|
||||
};
|
||||
/**
|
||||
* @deprecated Use `walletConnect` instead
|
||||
*
|
||||
* The WalletConnect v1.0 protocol has been shut down and no longer works.
|
||||
* To avoid breaking change, `walletConnectV1` is still available but is an alias of `walletConnect`.
|
||||
*/
|
||||
export const walletConnectV1 = walletConnect;
|
||||
|
||||
@@ -2,12 +2,28 @@ import type { WalletOptions, WalletConfig } from "@thirdweb-dev/react-core";
|
||||
import { ZerionWallet, assertWindowEthereum } from "@thirdweb-dev/wallets";
|
||||
import { ZerionConnectUI } from "./ZerionConnectUI";
|
||||
|
||||
export const zerionWallet = (): WalletConfig<ZerionWallet> => {
|
||||
type ZerionkWalletOptions = {
|
||||
/**
|
||||
* When connecting MetaMask using the QR Code - Wallet Connect connector is used which requires a project id.
|
||||
* This project id is Your project’s unique identifier for wallet connect that can be obtained at cloud.walletconnect.com.
|
||||
*
|
||||
* https://docs.walletconnect.com/2.0/web3modal/options#projectid-required
|
||||
*/
|
||||
projectId?: string;
|
||||
};
|
||||
|
||||
export const zerionWallet = (
|
||||
options?: ZerionkWalletOptions,
|
||||
): WalletConfig<ZerionWallet> => {
|
||||
return {
|
||||
id: ZerionWallet.id,
|
||||
meta: ZerionWallet.meta,
|
||||
create: (options: WalletOptions) => {
|
||||
return new ZerionWallet(options);
|
||||
create: (walletOptions: WalletOptions) => {
|
||||
return new ZerionWallet({
|
||||
...walletOptions,
|
||||
projectId: options?.projectId,
|
||||
qrcode: false,
|
||||
});
|
||||
},
|
||||
connectUI: ZerionConnectUI,
|
||||
isInstalled() {
|
||||
|
||||
@@ -24,6 +24,7 @@ module.exports = {
|
||||
files: "./test/**/*",
|
||||
rules: {
|
||||
"@typescript-eslint/no-restricted-imports": "off",
|
||||
"better-tree-shaking/no-top-level-side-effects": "off",
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,5 +1,27 @@
|
||||
# @thirdweb-dev/sdk
|
||||
|
||||
## 3.10.27
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1277](https://github.com/thirdweb-dev/js/pull/1277) [`2b113539`](https://github.com/thirdweb-dev/js/commit/2b113539098384f910b3c4d54e1fde9d35a6f053) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - remove ethers/lib/utils dependency
|
||||
|
||||
- [#1271](https://github.com/thirdweb-dev/js/pull/1271) [`c9535715`](https://github.com/thirdweb-dev/js/commit/c95357158819abd42d4b0900ecc2fa40fcb957f8) Thanks [@nkrishang](https://github.com/nkrishang)! - Rename smart wallets to account
|
||||
|
||||
- Updated dependencies [[`5882091e`](https://github.com/thirdweb-dev/js/commit/5882091eab65978009a5a5305701f121851b10ad)]:
|
||||
- @thirdweb-dev/chains@0.1.26
|
||||
|
||||
## 3.10.26
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- [#1249](https://github.com/thirdweb-dev/js/pull/1249) [`ef4cb092`](https://github.com/thirdweb-dev/js/commit/ef4cb092192c58c9b292b29590b888f45f9fd23d) Thanks [@kumaryash90](https://github.com/kumaryash90)! - Update EIP155 error substrings for any evm deployments
|
||||
|
||||
- [#1254](https://github.com/thirdweb-dev/js/pull/1254) [`30ac3aef`](https://github.com/thirdweb-dev/js/commit/30ac3aef840bde51a61acf786c709cffd3c47354) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Fetch base64 NFTs
|
||||
|
||||
- Updated dependencies [[`620e89dc`](https://github.com/thirdweb-dev/js/commit/620e89dc25c91557e2164a602c7aedd733525087), [`0fd8aa04`](https://github.com/thirdweb-dev/js/commit/0fd8aa04a9424497758d13a51a72363edcc30e19)]:
|
||||
- @thirdweb-dev/chains@0.1.25
|
||||
|
||||
## 3.10.25
|
||||
|
||||
### Patch Changes
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@thirdweb-dev/sdk",
|
||||
"version": "3.10.25",
|
||||
"version": "3.10.27",
|
||||
"description": "The main thirdweb SDK.",
|
||||
"repository": "https://github.com/thirdweb-dev/js/tree/main/packages/sdk",
|
||||
"license": "Apache-2.0",
|
||||
@@ -197,12 +197,6 @@
|
||||
"yaml": "^2.1.1",
|
||||
"zod": "^3.20.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"bn.js": "^5.2.1",
|
||||
"nanoid": "^3.1.31",
|
||||
"typescript": "^4.6.2",
|
||||
"@microsoft/tsdoc": "^0.14.1"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/thirdweb-dev/js/issues"
|
||||
},
|
||||
|
||||
@@ -10,6 +10,8 @@ export const ERROR_SUBSTRINGS = [
|
||||
"recovered sender mismatch",
|
||||
"transaction hash mismatch",
|
||||
"chainid no support",
|
||||
"chainid (0)",
|
||||
"chainid(0)",
|
||||
];
|
||||
|
||||
export const ERROR_SUBSTRINGS_COMPOSITE = [
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { BigNumber, providers, constants } from "ethers";
|
||||
import { isAddress } from "ethers/lib/utils";
|
||||
import { BigNumber, providers, constants, utils } from "ethers";
|
||||
import { extractIPFSHashFromBytecode } from "./extractIPFSHashFromBytecode";
|
||||
import { extractMinimalProxyImplementationAddress } from "./extractMinimalProxyImplementationAddress";
|
||||
|
||||
@@ -49,7 +48,7 @@ export async function resolveContractUriFromAddress(
|
||||
);
|
||||
const implementationAddress = `0x${proxyStorage.slice(-40)}`;
|
||||
if (
|
||||
isAddress(implementationAddress) &&
|
||||
utils.isAddress(implementationAddress) &&
|
||||
implementationAddress !== constants.AddressZero
|
||||
) {
|
||||
return await resolveContractUriFromAddress(
|
||||
|
||||
@@ -46,6 +46,22 @@ export async function fetchTokenMetadata(
|
||||
tokenUri: string,
|
||||
storage: ThirdwebStorage,
|
||||
): Promise<NFTMetadata> {
|
||||
// check for base64 encoded JSON
|
||||
if (
|
||||
tokenUri.startsWith("data:application/json;base64") &&
|
||||
typeof Buffer !== "undefined"
|
||||
) {
|
||||
const base64 = tokenUri.split(",")[1];
|
||||
const jsonMetadata = JSON.parse(
|
||||
Buffer.from(base64, "base64").toString("utf-8"),
|
||||
);
|
||||
return CommonNFTOutput.parse({
|
||||
...jsonMetadata,
|
||||
id: BigNumber.from(tokenId).toString(),
|
||||
uri: tokenUri,
|
||||
});
|
||||
}
|
||||
// handle dynamic id URIs (2 possible formats)
|
||||
const parsedUri = tokenUri.replace(
|
||||
"{id}",
|
||||
utils.hexZeroPad(BigNumber.from(tokenId).toHexString(), 32).slice(2),
|
||||
|
||||
@@ -62,8 +62,8 @@ import {
|
||||
FEATURE_ENGLISH_AUCTIONS,
|
||||
FEATURE_OFFERS,
|
||||
FEATURE_EXTENSION_ROUTER,
|
||||
FEATURE_SMART_WALLET,
|
||||
FEATURE_SMART_WALLET_FACTORY,
|
||||
FEATURE_ACCOUNT,
|
||||
FEATURE_ACCOUNT_FACTORY,
|
||||
} from "./thirdweb-features";
|
||||
|
||||
/**
|
||||
@@ -127,8 +127,8 @@ export type Feature =
|
||||
| typeof FEATURE_DIRECT_LISTINGS
|
||||
| typeof FEATURE_ENGLISH_AUCTIONS
|
||||
| typeof FEATURE_OFFERS
|
||||
| typeof FEATURE_SMART_WALLET
|
||||
| typeof FEATURE_SMART_WALLET_FACTORY;
|
||||
| typeof FEATURE_ACCOUNT
|
||||
| typeof FEATURE_ACCOUNT_FACTORY;
|
||||
|
||||
export type Extension = Feature;
|
||||
|
||||
@@ -170,6 +170,6 @@ export const SUPPORTED_FEATURES: Record<string, Feature> = /* @__PURE__ */ {
|
||||
[FEATURE_DIRECT_LISTINGS.name]: FEATURE_DIRECT_LISTINGS,
|
||||
[FEATURE_ENGLISH_AUCTIONS.name]: FEATURE_ENGLISH_AUCTIONS,
|
||||
[FEATURE_OFFERS.name]: FEATURE_OFFERS,
|
||||
[FEATURE_SMART_WALLET_FACTORY.name]: FEATURE_SMART_WALLET_FACTORY,
|
||||
[FEATURE_SMART_WALLET.name]: FEATURE_SMART_WALLET,
|
||||
[FEATURE_ACCOUNT_FACTORY.name]: FEATURE_ACCOUNT_FACTORY,
|
||||
[FEATURE_ACCOUNT.name]: FEATURE_ACCOUNT,
|
||||
};
|
||||
|
||||
@@ -279,24 +279,24 @@ export const FEATURE_OFFERS = {
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_SMART_WALLET_FACTORY = {
|
||||
name: "SmartWalletFactory",
|
||||
namespace: "smartwallet.factory",
|
||||
export const FEATURE_ACCOUNT_FACTORY = {
|
||||
name: "AccountFactory",
|
||||
namespace: "accountFactory",
|
||||
docLinks: {
|
||||
// TODO
|
||||
sdk: "sdk.smartWalletFactory",
|
||||
contracts: "smartWalletFactory",
|
||||
sdk: "sdk.accountFactory",
|
||||
contracts: "",
|
||||
},
|
||||
abis: [IAccountFactory],
|
||||
features: {},
|
||||
} as const;
|
||||
|
||||
export const FEATURE_SMART_WALLET = {
|
||||
name: "SmartWallet",
|
||||
namespace: "smartwallet",
|
||||
export const FEATURE_ACCOUNT = {
|
||||
name: "Account",
|
||||
namespace: "account",
|
||||
docLinks: {
|
||||
// TODO
|
||||
sdk: "",
|
||||
sdk: "sdk.account",
|
||||
contracts: "",
|
||||
},
|
||||
abis: [IAccountCore],
|
||||
|
||||
@@ -14,8 +14,8 @@ import {
|
||||
FEATURE_PLATFORM_FEE,
|
||||
FEATURE_PRIMARY_SALE,
|
||||
FEATURE_ROYALTY,
|
||||
FEATURE_SMART_WALLET_FACTORY,
|
||||
FEATURE_SMART_WALLET,
|
||||
FEATURE_ACCOUNT_FACTORY,
|
||||
FEATURE_ACCOUNT,
|
||||
} from "../constants/thirdweb-features";
|
||||
import { Transaction } from "../core/classes/transactions";
|
||||
import { ContractAppURI } from "../core/classes/contract-appuri";
|
||||
@@ -54,7 +54,7 @@ import type {
|
||||
EnglishAuctionsLogic,
|
||||
OffersLogic,
|
||||
IAccountFactory,
|
||||
IAccountCore
|
||||
IAccountCore,
|
||||
} from "@thirdweb-dev/contracts-js";
|
||||
import { ThirdwebStorage } from "@thirdweb-dev/storage";
|
||||
import { BaseContract, CallOverrides } from "ethers";
|
||||
@@ -66,8 +66,8 @@ import { ContractOwner } from "../core/classes/contract-owner";
|
||||
import { MarketplaceV3DirectListings } from "../core/classes/marketplacev3-direct-listings";
|
||||
import { MarketplaceV3EnglishAuctions } from "../core/classes/marketplacev3-english-auction";
|
||||
import { MarketplaceV3Offers } from "../core/classes/marketplacev3-offers";
|
||||
import { SmartWalletFactory } from "../core/classes/smart-wallet-factory";
|
||||
import { SmartWallet } from "../core/classes/smart-wallet";
|
||||
import { AccountFactory } from "../core/classes/account-factory";
|
||||
import { Account } from "../core/classes/account";
|
||||
|
||||
/**
|
||||
* Custom contract dynamic class with feature detection
|
||||
@@ -299,46 +299,40 @@ export class SmartContract<
|
||||
}
|
||||
|
||||
/**
|
||||
* Smart Wallet Factory
|
||||
* Account Factory
|
||||
*
|
||||
* @remarks Create smart wallets and fetch data about them.
|
||||
* @remarks Create accounts and fetch data about them.
|
||||
* @example
|
||||
* ```javascript
|
||||
*
|
||||
* // Predict the address of the smart wallet that will be created for an admin.
|
||||
* const deterministicAddress = await contract.smartWalletFactory.predictWalletAddress(admin, extraData);
|
||||
* // Predict the address of the account that will be created for an admin.
|
||||
* const deterministicAddress = await contract.accountFactory.predictAccountAddress(admin, extraData);
|
||||
*
|
||||
* // Create smart wallets
|
||||
* const tx = await contract.smartWalletFactory.createWallet(admin, extraData);
|
||||
* // Create accounts
|
||||
* const tx = await contract.accountFactory.createAccount(admin, extraData);
|
||||
* // the same as `deterministicAddress`
|
||||
* const smartWalletAddress = tx.address;
|
||||
* const accountAddress = tx.address;
|
||||
*
|
||||
* // Get all smart wallets created by the factory
|
||||
* const allWallets = await contract.smartWalletFactory.getAllWallets();
|
||||
* // Get all accounts created by the factory
|
||||
* const allAccounts = await contract.accountFactory.getAllAccounts();
|
||||
*
|
||||
* // Get all smart wallets on which a signer has been given authority.
|
||||
* const associatedWallets = await contract.smartWalletFactory.getAssociatedWallets(signer);
|
||||
* // Get all accounts on which a signer has been given authority.
|
||||
* const associatedAccounts = await contract.accountFactory.getAssociatedAccounts(signer);
|
||||
*
|
||||
* // Get all signers who have been given authority on a smart wallet.
|
||||
* const associatedSigners = await contract.smartWalletFactory.getAssociatedSigners(smartWalletAddress);
|
||||
* // Get all signers who have been given authority on a account.
|
||||
* const associatedSigners = await contract.accountFactory.getAssociatedSigners(accountAddress);
|
||||
*
|
||||
* // Check whether a smart wallet has already been created for a given admin.
|
||||
* const isWalletDeployed = await contract.smartWalletFactory.isWalletDeployed(admin, extraData);
|
||||
* // Check whether a account has already been created for a given admin.
|
||||
* const isAccountDeployed = await contract.accountFactory.isAccountDeployed(admin, extraData);
|
||||
* ```
|
||||
*/
|
||||
get smartWalletFactory(): SmartWalletFactory<IAccountFactory> {
|
||||
return assertEnabled(
|
||||
this.detectSmartWalletFactory(),
|
||||
FEATURE_SMART_WALLET_FACTORY,
|
||||
);
|
||||
get accountFactory(): AccountFactory<IAccountFactory> {
|
||||
return assertEnabled(this.detectAccountFactory(), FEATURE_ACCOUNT_FACTORY);
|
||||
}
|
||||
|
||||
// TODO documentation
|
||||
get smartWallet(): SmartWallet<IAccountCore> {
|
||||
return assertEnabled(
|
||||
this.detectSmartWallet(),
|
||||
FEATURE_SMART_WALLET,
|
||||
)
|
||||
get account(): Account<IAccountCore> {
|
||||
return assertEnabled(this.detectAccount(), FEATURE_ACCOUNT);
|
||||
}
|
||||
|
||||
private _chainId: number;
|
||||
@@ -568,25 +562,28 @@ export class SmartContract<
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// ========== Smart account features ==========
|
||||
// ========== Account features ==========
|
||||
|
||||
private detectSmartWalletFactory() {
|
||||
private detectAccountFactory() {
|
||||
if (
|
||||
detectContractFeature<IAccountFactory>(
|
||||
this.contractWrapper,
|
||||
FEATURE_SMART_WALLET_FACTORY.name,
|
||||
FEATURE_ACCOUNT_FACTORY.name,
|
||||
)
|
||||
) {
|
||||
return new SmartWalletFactory(this.contractWrapper);
|
||||
return new AccountFactory(this.contractWrapper);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private detectSmartWallet() {
|
||||
private detectAccount() {
|
||||
if (
|
||||
detectContractFeature<IAccountCore>(this.contractWrapper, FEATURE_SMART_WALLET.name)
|
||||
detectContractFeature<IAccountCore>(
|
||||
this.contractWrapper,
|
||||
FEATURE_ACCOUNT.name,
|
||||
)
|
||||
) {
|
||||
return new SmartWallet(this.contractWrapper);
|
||||
return new Account(this.contractWrapper);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
+46
-46
@@ -1,6 +1,6 @@
|
||||
import type { IAccountFactory } from "@thirdweb-dev/contracts-js";
|
||||
import { DetectableFeature } from "../interfaces/DetectableFeature";
|
||||
import { FEATURE_SMART_WALLET_FACTORY } from "../../constants/thirdweb-features";
|
||||
import { FEATURE_ACCOUNT_FACTORY } from "../../constants/thirdweb-features";
|
||||
|
||||
import { ContractEvents } from "./contract-events";
|
||||
import { ContractWrapper } from "./contract-wrapper";
|
||||
@@ -9,13 +9,13 @@ import { Transaction } from "./transactions";
|
||||
import { TransactionResultWithAddress } from "../types";
|
||||
import { type BytesLike, utils } from "ethers";
|
||||
import { AccountCreatedEvent } from "@thirdweb-dev/contracts-js/dist/declarations/src/AccountFactory";
|
||||
import type { AccountEvent } from "../../types/smart-wallet";
|
||||
import type { AccountEvent } from "../../types/account";
|
||||
import { isContractDeployed } from "../../common/any-evm-utils/isContractDeployed";
|
||||
|
||||
export class SmartWalletFactory<TContract extends IAccountFactory>
|
||||
export class AccountFactory<TContract extends IAccountFactory>
|
||||
implements DetectableFeature
|
||||
{
|
||||
featureName = FEATURE_SMART_WALLET_FACTORY.name;
|
||||
featureName = FEATURE_ACCOUNT_FACTORY.name;
|
||||
private contractWrapper: ContractWrapper<IAccountFactory>;
|
||||
|
||||
// utilities
|
||||
@@ -36,19 +36,19 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
|
||||
*******************************/
|
||||
|
||||
/**
|
||||
* Get the deterministic address of the smart wallet that will be created
|
||||
* Get the deterministic address of the account that will be created
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const walletAddress = await contract.smartWalletFactory.predictWalletAddress(admin);
|
||||
* const accountAddress = await contract.accountFactory.predictAccountAddress(admin);
|
||||
* ```
|
||||
* @param admin - The admin of the smart wallet.
|
||||
* @param extraData - (Optional) Extra data to be passed to the smart wallet on creation.
|
||||
* @returns the deterministic address of the smart wallet that will be created for the given admin.
|
||||
* @param admin - The admin of the account.
|
||||
* @param extraData - (Optional) Extra data to be passed to the account on creation.
|
||||
* @returns the deterministic address of the account that will be created for the given admin.
|
||||
*
|
||||
* @twfeature SmartWalletFactory
|
||||
* @twfeature AccountFactory
|
||||
*/
|
||||
public async predictWalletAddress(
|
||||
public async predictAccountAddress(
|
||||
admin: string,
|
||||
extraData?: BytesLike,
|
||||
): Promise<string> {
|
||||
@@ -60,48 +60,48 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all signers who have authority on the given smart wallet
|
||||
* Get all signers who have authority on the given account
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const allSigners = await contract.smartWalletFactory.getAssociatedSigners(admin);
|
||||
* const allSigners = await contract.accountFactory.getAssociatedSigners(admin);
|
||||
* ```
|
||||
* @param wallet - The smart wallet address.
|
||||
* @returns all signers who have authority on the given smart wallet.
|
||||
* @param account - The account address.
|
||||
* @returns all signers who have authority on the given account.
|
||||
*
|
||||
* @twfeature SmartWalletFactory
|
||||
* @twfeature AccountFactory
|
||||
*/
|
||||
public async getAssociatedSigners(wallet: string): Promise<string[]> {
|
||||
return this.contractWrapper.readContract.getSignersOfAccount(wallet);
|
||||
public async getAssociatedSigners(account: string): Promise<string[]> {
|
||||
return this.contractWrapper.readContract.getSignersOfAccount(account);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all wallets on which the given signer has authority
|
||||
* Get all accounts on which the given signer has authority
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const allWallets = await contract.smartWalletFactory.getAssociatedWallets(admin);
|
||||
* const allAccounts = await contract.accountFactory.getAssociatedAccounts(admin);
|
||||
* ```
|
||||
* @param signer - The smart wallet address.
|
||||
* @returns all wallets on which the given signer has authority.
|
||||
* @param signer - The account address.
|
||||
* @returns all accounts on which the given signer has authority.
|
||||
*
|
||||
* @twfeature SmartWalletFactory
|
||||
* @twfeature AccountFactory
|
||||
*/
|
||||
public async getAssociatedWallets(signer: string): Promise<string[]> {
|
||||
public async getAssociatedAccounts(signer: string): Promise<string[]> {
|
||||
return this.contractWrapper.readContract.getAccountsOfSigner(signer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all wallets
|
||||
* Get all accounts
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const allWallets = await contract.smartWalletFactory.getAllWallets();
|
||||
* const allAccounts = await contract.accountFactory.getAllAccounts();
|
||||
* ```
|
||||
*
|
||||
* @returns all wallets created via the smart wallet factory.
|
||||
* @returns all accounts created via the account factory.
|
||||
*
|
||||
* @twfeature SmartWalletFactory
|
||||
* @twfeature AccountFactory
|
||||
*/
|
||||
public async getAllAccounts(): Promise<AccountEvent[]> {
|
||||
const allAccounts =
|
||||
@@ -122,17 +122,17 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a smart wallet has been deployed for the given admin
|
||||
* Check if a account has been deployed for the given admin
|
||||
*
|
||||
* @param admin - The admin of the smart wallet.
|
||||
* @param extraData - (Optional) Extra data to be passed to the smart wallet on creation.
|
||||
* @returns whether the smart wallet has been deployed for the given admin.
|
||||
* @param admin - The admin of the account.
|
||||
* @param extraData - (Optional) Extra data to be passed to the account on creation.
|
||||
* @returns whether the account has been deployed for the given admin.
|
||||
*/
|
||||
public async isWalletDeployed(
|
||||
public async isAccountDeployed(
|
||||
admin: string,
|
||||
extraData?: BytesLike,
|
||||
): Promise<boolean> {
|
||||
const addr = await this.predictWalletAddress(admin, extraData);
|
||||
const addr = await this.predictAccountAddress(admin, extraData);
|
||||
return isContractDeployed(addr, this.contractWrapper.getProvider());
|
||||
}
|
||||
|
||||
@@ -141,29 +141,29 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
|
||||
*******************************/
|
||||
|
||||
/**
|
||||
* Create a smart wallet
|
||||
* Create a account
|
||||
*
|
||||
* @remarks Create a smart wallet for an admin. The admin will have complete authority over the smart wallet.
|
||||
* @remarks Create a account for an admin. The admin will have complete authority over the account.
|
||||
*
|
||||
* @param admin - The admin of the smart wallet.
|
||||
* @param extraData - (Optional) Extra data to be passed to the smart wallet on creation.
|
||||
* @param admin - The admin of the account.
|
||||
* @param extraData - (Optional) Extra data to be passed to the account on creation.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const tx = await contract.smartWalletFactory.createWallet(admin, extraData);
|
||||
* const tx = await contract.accountFactory.createAccount(admin, extraData);
|
||||
* const receipt = tx.receipt();
|
||||
* const smartWalletAddress = tx.address;
|
||||
* const accountAddress = tx.address;
|
||||
* ```
|
||||
*
|
||||
* @twfeature SmartWalletFactory
|
||||
* @twfeature AccountFactory
|
||||
*/
|
||||
createWallet = /* @__PURE__ */ buildTransactionFunction(
|
||||
createAccount = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (
|
||||
walletAdmin: string,
|
||||
accountAdmin: string,
|
||||
extraData?: BytesLike,
|
||||
): Promise<Transaction<TransactionResultWithAddress>> => {
|
||||
if (await this.isWalletDeployed(walletAdmin, extraData)) {
|
||||
throw new Error(`Wallet already deployed for admin: ${walletAdmin}`);
|
||||
if (await this.isAccountDeployed(accountAdmin, extraData)) {
|
||||
throw new Error(`Account already deployed for admin: ${accountAdmin}`);
|
||||
}
|
||||
|
||||
let data: BytesLike = utils.toUtf8Bytes("");
|
||||
@@ -174,7 +174,7 @@ export class SmartWalletFactory<TContract extends IAccountFactory>
|
||||
return Transaction.fromContractWrapper({
|
||||
contractWrapper: this.contractWrapper,
|
||||
method: "createAccount",
|
||||
args: [walletAdmin, data],
|
||||
args: [accountAdmin, data],
|
||||
parse: (receipt) => {
|
||||
const event = this.contractWrapper.parseLogs<AccountCreatedEvent>(
|
||||
"AccountCreated",
|
||||
+300
-62
@@ -1,6 +1,6 @@
|
||||
import { DetectableFeature } from "../interfaces/DetectableFeature";
|
||||
import { ContractWrapper } from "./contract-wrapper";
|
||||
import { FEATURE_SMART_WALLET } from "../../constants/thirdweb-features";
|
||||
import { FEATURE_ACCOUNT } from "../../constants/thirdweb-features";
|
||||
import { utils, BigNumber } from "ethers";
|
||||
import { Transaction } from "./transactions";
|
||||
|
||||
@@ -18,18 +18,19 @@ import {
|
||||
SignerWithRestrictions,
|
||||
AccessRestrictionsInput,
|
||||
AccessRestrictionsSchema,
|
||||
SignerWithRestrictionsBatchInput,
|
||||
} from "../../types";
|
||||
import invariant from "tiny-invariant";
|
||||
import { buildTransactionFunction } from "../../common/transactions";
|
||||
import { SmartWalletFactory } from "./smart-wallet-factory";
|
||||
import { resolveOrGenerateId } from "../../common/signature-minting";
|
||||
import { AddressOrEns } from "../../schema";
|
||||
import { resolveAddress } from "../../common";
|
||||
import { Signer } from "ethers";
|
||||
|
||||
export class SmartWallet<TContract extends IAccountCore>
|
||||
export class Account<TContract extends IAccountCore>
|
||||
implements DetectableFeature
|
||||
{
|
||||
featureName = FEATURE_SMART_WALLET.name;
|
||||
featureName = FEATURE_ACCOUNT.name;
|
||||
private contractWrapper: ContractWrapper<IAccountCore>;
|
||||
|
||||
private emptyRole: string =
|
||||
@@ -47,6 +48,20 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
* HELPER FUNCTIONS
|
||||
********************************/
|
||||
|
||||
private hasDuplicateSigners(
|
||||
signers: SignerWithRestrictionsBatchInput,
|
||||
): boolean {
|
||||
const encounteredSigners = new Set();
|
||||
|
||||
return signers
|
||||
.map((item) => item.signer)
|
||||
.some((signer) => {
|
||||
const isDuplicate = encounteredSigners.has(signer);
|
||||
encounteredSigners.add(signer);
|
||||
return isDuplicate;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the access restrictions for a given role
|
||||
*
|
||||
@@ -72,7 +87,7 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate and sign a payload to grant or revoke a signer's access to the smart wallet.
|
||||
* Generate and sign a payload to grant or revoke a signer's access to the account.
|
||||
*
|
||||
* @param signer - The address of the signer
|
||||
* @param roleAction - The address of the signer
|
||||
@@ -122,12 +137,12 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the factory contract which deployed the smart wallet
|
||||
* Get the factory contract which deployed the account
|
||||
*
|
||||
* @returns Returns the address of the factory
|
||||
*
|
||||
*/
|
||||
private async getFactory(): Promise<SmartWalletFactory<IAccountFactory>> {
|
||||
private async getFactory(): Promise<ContractWrapper<IAccountFactory>> {
|
||||
// Get factory.
|
||||
const chainId = await this.contractWrapper.getChainID();
|
||||
const factoryAddress = await this.getFactoryAddress();
|
||||
@@ -137,7 +152,8 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
IAccountFactoryAbi,
|
||||
this.contractWrapper.options,
|
||||
);
|
||||
return new SmartWalletFactory(wrapper);
|
||||
wrapper.updateSignerOrProvider(this.contractWrapper.getSigner() as Signer);
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
@@ -145,16 +161,35 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
********************************/
|
||||
|
||||
/**
|
||||
* Get the restrictions under which a given signer can use the smart wallet.
|
||||
* Get whether a signer is an admin on the account.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const restrictionsForSigner = await contract.smartWallet.getAccessRestrictions(signer);
|
||||
* const isAdmin = await contract.account.isAdmin(signer);
|
||||
* ```
|
||||
* @param signer - The address of a signer of the smart wallet.
|
||||
* @returns the restrictions under which a given signer can use the smart wallet.
|
||||
* @param signer - The address of a signer of the account.
|
||||
* @returns whether a signer is an admin on the account.
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
* @twfeature Account
|
||||
*/
|
||||
public async isAdmin(signerAddress: AddressOrEns): Promise<boolean> {
|
||||
const resolvedSignerAddress = await resolveAddress(signerAddress);
|
||||
return await this.contractWrapper.readContract.isAdmin(
|
||||
resolvedSignerAddress,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the restrictions under which a given signer can use the account.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const restrictionsForSigner = await contract.account.getAccessRestrictions(signer);
|
||||
* ```
|
||||
* @param signer - The address of a signer of the account.
|
||||
* @returns the restrictions under which a given signer can use the account.
|
||||
*
|
||||
* @twfeature Account
|
||||
*/
|
||||
public async getAccessRestrictions(
|
||||
signerAddress: AddressOrEns,
|
||||
@@ -168,35 +203,36 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the address of the EIP-4337 factory contract which deployed the smart wallet
|
||||
* Get the deployer of the account
|
||||
* @remarks Get the address of the EIP-4337 factory contract which deployed the account
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const factoryAddress = await contract.smartWallet.getFactoryAddress();
|
||||
* const factoryAddress = await contract.account.getFactoryAddress();
|
||||
* ```
|
||||
* @returns the address of the factory which deployed the smart wallet.
|
||||
* @returns the address of the factory which deployed the account.
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
* @twfeature Account
|
||||
*/
|
||||
public async getFactoryAddress(): Promise<string> {
|
||||
return this.contractWrapper.readContract.factory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all signers (admin or non-admin) of the smart wallet, along with their access restrictions.
|
||||
* Get all signers with their access restrictions
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const allSigners = await contract.smartWallet.getSignersWithRestrictions();
|
||||
* const allSigners = await contract.account.getSignersWithRestrictions();
|
||||
* ```
|
||||
* @returns all signers (admin or non-admin) of the smart wallet, along with their access restrictions.
|
||||
* @returns all signers (admin or non-admin) of the account, along with their access restrictions.
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
* @twfeature Account
|
||||
*/
|
||||
public async getSignersWithRestrictions(): Promise<SignerWithRestrictions[]> {
|
||||
// Get all associated signers.
|
||||
const factory = await this.getFactory();
|
||||
const signers: string[] = await factory.getAssociatedSigners(
|
||||
const contract = await this.getFactory();
|
||||
const signers: string[] = await contract.readContract.getSignersOfAccount(
|
||||
this.getAddress(),
|
||||
);
|
||||
|
||||
@@ -214,19 +250,19 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
********************************/
|
||||
|
||||
/**
|
||||
* Grant an address admin access to the smart wallet.
|
||||
* Grant an address admin access to the account
|
||||
*
|
||||
* @remarks Grants an address admin access to the smart wallet. The admin will have complete authority over the smart wallet.
|
||||
* @remarks Grants an address admin access to the account. The admin will have complete authority over the account.
|
||||
*
|
||||
* @param signer - The address to be granted admin access to the smart wallet.
|
||||
* @param signer - The address to be granted admin access to the account.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const tx = await contract.smartWallet.grantAdminAccess(signer);
|
||||
* const tx = await contract.account.grantAdminAccess(signer);
|
||||
* const receipt = tx.receipt();
|
||||
* ```
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
* @twfeature Account
|
||||
*/
|
||||
grantAdminAccess = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (signerAddress: AddressOrEns): Promise<Transaction> => {
|
||||
@@ -240,19 +276,19 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
);
|
||||
|
||||
/**
|
||||
* Revoke an address' admin access to the smart wallet.
|
||||
* Revoke an address' admin access to the account
|
||||
*
|
||||
* @remarks Revokes an address' admin access to the smart wallet.
|
||||
* @remarks Revokes an address' admin access to the account.
|
||||
*
|
||||
* @param signer - The address of an admin of the smart wallet.
|
||||
* @param signer - The address of an admin of the account.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const tx = await contract.smartWallet.revokeAdminAccess(signer);
|
||||
* const tx = await contract.account.revokeAdminAccess(signer);
|
||||
* const receipt = tx.receipt();
|
||||
* ```
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
* @twfeature Account
|
||||
*/
|
||||
revokeAdminAccess = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (signerAddress: AddressOrEns): Promise<Transaction> => {
|
||||
@@ -266,20 +302,20 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
);
|
||||
|
||||
/**
|
||||
* Grant an address access to the smart wallet with certain restrictions.
|
||||
* Grant an address access to the account with restrictions
|
||||
*
|
||||
* @remarks Grants an address access to the smart wallet with certain restrictions.
|
||||
* @remarks Grants an address access to the account with certain restrictions.
|
||||
*
|
||||
* @param signer - The address to be granted access to the smart wallet.
|
||||
* @param restrictions - The restrictions to be applied to the signer's use of the smart wallet.
|
||||
* @param signer - The address to be granted access to the account.
|
||||
* @param restrictions - The restrictions to be applied to the signer's use of the account.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const tx = await contract.smartWallet.grantAccess(signer, restrictions);
|
||||
* const tx = await contract.account.grantAccess(signer, restrictions);
|
||||
* const receipt = tx.receipt();
|
||||
* ```
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
* @twfeature Account
|
||||
*/
|
||||
grantAccess = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (
|
||||
@@ -312,8 +348,9 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
const roleRestrictions: IAccountPermissions.RoleRestrictionsStruct = {
|
||||
role,
|
||||
approvedTargets: parsedRestrictions.approvedCallTargets,
|
||||
maxValuePerTransaction:
|
||||
maxValuePerTransaction: utils.parseEther(
|
||||
parsedRestrictions.nativeTokenLimitPerTransaction,
|
||||
),
|
||||
startTimestamp: parsedRestrictions.startDate,
|
||||
endTimestamp: parsedRestrictions.expirationDate,
|
||||
};
|
||||
@@ -358,20 +395,20 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
);
|
||||
|
||||
/**
|
||||
* Approve an address as a call target for a given signer on the smart wallet.
|
||||
* Approve an address as a call target for a given signer on the account
|
||||
*
|
||||
* @remarks Approves an address as a call target for a given signer on the smart wallet.
|
||||
* @remarks Approves an address as a call target for a given signer on the account.
|
||||
*
|
||||
* @param signer - A signer with restricted access to the smart wallet.
|
||||
* @param signer - A signer with restricted access to the account.
|
||||
* @param target - The address to approve as a call target for the signer.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const tx = await contract.smartWallet.approveTargetForSigner(signer, target);
|
||||
* const tx = await contract.account.approveTargetForSigner(signer, target);
|
||||
* const receipt = tx.receipt();
|
||||
* ```
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
* @twfeature Account
|
||||
*/
|
||||
approveTargetForSigner = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (
|
||||
@@ -407,20 +444,20 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
);
|
||||
|
||||
/**
|
||||
* Disapprove an address as a call target for a given signer on the smart wallet.
|
||||
* Disapprove an address as a call target for a given signer on the account
|
||||
*
|
||||
* @remarks Disapprove an address as a call target for a given signer on the smart wallet.
|
||||
* @remarks Disapprove an address as a call target for a given signer on the account.
|
||||
*
|
||||
* @param signer - A signer with restricted access to the smart wallet.
|
||||
* @param signer - A signer with restricted access to the account.
|
||||
* @param target - The address to disapprove as a call target for the signer.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const tx = await contract.smartWallet.disapproveTargetForSigner(signer, target);
|
||||
* const tx = await contract.account.disapproveTargetForSigner(signer, target);
|
||||
* const receipt = tx.receipt();
|
||||
* ```
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
* @twfeature Account
|
||||
*/
|
||||
disapproveTargetForSigner = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (
|
||||
@@ -459,20 +496,20 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
);
|
||||
|
||||
/**
|
||||
* Update an address' access to the smart wallet.
|
||||
* Update the restrictions of an address for using the account
|
||||
*
|
||||
* @remarks Updates an address' access to the smart wallet.
|
||||
* @remarks Updates an address' access to the account.
|
||||
*
|
||||
* @param signer - The address whose access to the smart wallet is to be updated.
|
||||
* @param restrictions - The restrictions to be applied to the signer's use of the smart wallet.
|
||||
* @param signer - The address whose access to the account is to be updated.
|
||||
* @param restrictions - The restrictions to be applied to the signer's use of the account.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const tx = await contract.smartWallet.updateAccess(signer, restrictions);
|
||||
* const tx = await contract.account.updateAccess(signer, restrictions);
|
||||
* const receipt = tx.receipt();
|
||||
* ```
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
* @twfeature Account
|
||||
*/
|
||||
updateAccess = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (
|
||||
@@ -497,8 +534,9 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
const roleRestrictions: IAccountPermissions.RoleRestrictionsStruct = {
|
||||
role: currentRole,
|
||||
approvedTargets: parsedRestrictions.approvedCallTargets,
|
||||
maxValuePerTransaction:
|
||||
maxValuePerTransaction: utils.parseEther(
|
||||
parsedRestrictions.nativeTokenLimitPerTransaction,
|
||||
),
|
||||
startTimestamp: parsedRestrictions.startDate,
|
||||
endTimestamp: parsedRestrictions.expirationDate,
|
||||
};
|
||||
@@ -512,19 +550,19 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
);
|
||||
|
||||
/**
|
||||
* Revoke an address' access to the smart wallet.
|
||||
* Revoke a scoped access address to the account
|
||||
*
|
||||
* @remarks Revokes an address' access to the smart wallet.
|
||||
* @remarks Revokes an address' access to the account.
|
||||
*
|
||||
* @param signer - The address whose access to the smart wallet is to be revoked.
|
||||
* @param signer - The address whose access to the account is to be revoked.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const tx = await contract.smartWallet.revokeAccess(signer);
|
||||
* const tx = await contract.account.revokeAccess(signer);
|
||||
* const receipt = tx.receipt();
|
||||
* ```
|
||||
*
|
||||
* @twfeature SmartWallet
|
||||
* @twfeature Account
|
||||
*/
|
||||
revokeAccess = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (signerAddress: AddressOrEns): Promise<Transaction> => {
|
||||
@@ -560,4 +598,204 @@ export class SmartWallet<TContract extends IAccountCore>
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
/**
|
||||
* Set the account's entire snapshot of permissions
|
||||
*
|
||||
* @remarks Sets the account's entire snapshot of permissions.
|
||||
*
|
||||
* @param permissionsSnapshot - the snapshot to set as the account's entire permission snapshot.
|
||||
*
|
||||
* @example
|
||||
* ```javascript
|
||||
* const tx = await contract.account.setAccess(permissionsSnapshot);
|
||||
* const receipt = tx.receipt();
|
||||
* ```
|
||||
*
|
||||
* @twfeature Account
|
||||
*/
|
||||
setAccess = /* @__PURE__ */ buildTransactionFunction(
|
||||
async (
|
||||
permissionsSnapshot: SignerWithRestrictionsBatchInput,
|
||||
): Promise<Transaction> => {
|
||||
/**
|
||||
* All cases
|
||||
*
|
||||
* - Add new admin :check:
|
||||
* - Remove current admin :check:
|
||||
* - Add new scoped :check:
|
||||
* - Remove current scoped :check:
|
||||
* - Update current scoped :check:
|
||||
* - Current admin -> new scoped :check:
|
||||
* - Current scoped -> new admin :check:
|
||||
**/
|
||||
|
||||
// No duplicate signers in input!
|
||||
if (this.hasDuplicateSigners(permissionsSnapshot)) {
|
||||
throw new Error("Duplicate signers found in input.");
|
||||
}
|
||||
|
||||
const currentPermissionsSnapshot =
|
||||
await this.getSignersWithRestrictions();
|
||||
|
||||
// Performing a multicall.
|
||||
const encoded: string[] = [];
|
||||
|
||||
// First make all calls related to admin access.
|
||||
const allCurrentAdmins = currentPermissionsSnapshot
|
||||
.filter((result) => result.isAdmin)
|
||||
.map((result) => result.signer);
|
||||
const allNewAdmins = permissionsSnapshot
|
||||
.filter((result) => result.isAdmin)
|
||||
.map((result) => result.signer);
|
||||
|
||||
// All remove-admin actions.
|
||||
for (const currentAdmin of allCurrentAdmins) {
|
||||
if (!allNewAdmins.includes(currentAdmin)) {
|
||||
encoded.push(
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"setAdmin",
|
||||
[currentAdmin, false],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// All add-admin actions.
|
||||
const toRemoveAsScoped: Record<string, string> = {};
|
||||
for (const newAdmin of allNewAdmins) {
|
||||
if (!allCurrentAdmins.includes(newAdmin)) {
|
||||
const data =
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"setAdmin",
|
||||
[newAdmin, true],
|
||||
);
|
||||
|
||||
// If the new admin is already a scoped account, we need to remove them as a scoped account first.
|
||||
const currentRole = (
|
||||
await this.contractWrapper.readContract.getRoleRestrictionsForAccount(
|
||||
newAdmin,
|
||||
)
|
||||
).role;
|
||||
if (currentRole === this.emptyRole) {
|
||||
encoded.push(data);
|
||||
} else {
|
||||
toRemoveAsScoped[newAdmin] = data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All scoped actions.
|
||||
const allCurrentScoped = currentPermissionsSnapshot
|
||||
.filter((result) => !result.isAdmin)
|
||||
.map((result) => result.signer);
|
||||
const allNewScoped = permissionsSnapshot
|
||||
.filter((result) => !result.isAdmin)
|
||||
.map((result) => result.signer);
|
||||
|
||||
// All remove-scoped actions.
|
||||
const newAdminsToRemoveAsScoped = Object.keys(toRemoveAsScoped);
|
||||
for (const currentScoped of allCurrentScoped) {
|
||||
if (!allNewScoped.includes(currentScoped)) {
|
||||
const { payload, signature } = await this.generatePayload(
|
||||
currentScoped,
|
||||
RoleAction.REVOKE,
|
||||
);
|
||||
|
||||
encoded.push(
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"changeRole",
|
||||
[payload, signature],
|
||||
),
|
||||
);
|
||||
|
||||
if (newAdminsToRemoveAsScoped.includes(currentScoped)) {
|
||||
encoded.push(toRemoveAsScoped[currentScoped]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// All add-scoped actions.
|
||||
for (const newScoped of allNewScoped) {
|
||||
if (!allCurrentScoped.includes(newScoped)) {
|
||||
// Derive role for target signer.
|
||||
const role = utils.solidityKeccak256(["string"], [newScoped]);
|
||||
|
||||
const parsedRestrictions = await AccessRestrictionsSchema.parseAsync(
|
||||
permissionsSnapshot.find((result) => result.signer === newScoped)
|
||||
?.restrictions,
|
||||
);
|
||||
|
||||
// Get role restrictions struct.
|
||||
const roleRestrictions: IAccountPermissions.RoleRestrictionsStruct = {
|
||||
role,
|
||||
approvedTargets: parsedRestrictions.approvedCallTargets,
|
||||
maxValuePerTransaction: utils.parseEther(
|
||||
parsedRestrictions.nativeTokenLimitPerTransaction,
|
||||
),
|
||||
startTimestamp: parsedRestrictions.startDate,
|
||||
endTimestamp: parsedRestrictions.expirationDate,
|
||||
};
|
||||
|
||||
encoded.push(
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"setRoleRestrictions",
|
||||
[roleRestrictions],
|
||||
),
|
||||
);
|
||||
|
||||
const { payload, signature } = await this.generatePayload(
|
||||
newScoped,
|
||||
RoleAction.GRANT,
|
||||
);
|
||||
|
||||
encoded.push(
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"changeRole",
|
||||
[payload, signature],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// All update-scoped actions.
|
||||
for (const currentScoped of allCurrentScoped) {
|
||||
if (allNewScoped.includes(currentScoped)) {
|
||||
// Derive role for target signer.
|
||||
const role = utils.solidityKeccak256(["string"], [currentScoped]);
|
||||
|
||||
const parsedRestrictions = await AccessRestrictionsSchema.parseAsync(
|
||||
permissionsSnapshot.find(
|
||||
(result) => result.signer === currentScoped,
|
||||
)?.restrictions,
|
||||
);
|
||||
|
||||
// Get role restrictions struct.
|
||||
const roleRestrictions: IAccountPermissions.RoleRestrictionsStruct = {
|
||||
role,
|
||||
approvedTargets: parsedRestrictions.approvedCallTargets,
|
||||
maxValuePerTransaction: utils.parseEther(
|
||||
parsedRestrictions.nativeTokenLimitPerTransaction,
|
||||
),
|
||||
startTimestamp: parsedRestrictions.startDate,
|
||||
endTimestamp: parsedRestrictions.expirationDate,
|
||||
};
|
||||
|
||||
encoded.push(
|
||||
this.contractWrapper.readContract.interface.encodeFunctionData(
|
||||
"setRoleRestrictions",
|
||||
[roleRestrictions],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Perform multicall
|
||||
return Transaction.fromContractWrapper({
|
||||
contractWrapper: this.contractWrapper,
|
||||
method: "multicall",
|
||||
args: [encoded],
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import { EventType } from "../../constants/events";
|
||||
import type { ContractEvent, EventQueryOptions } from "../../types/events";
|
||||
import { ContractWrapper } from "./contract-wrapper";
|
||||
import type { BaseContract, Event, providers } from "ethers";
|
||||
import type { EventFragment } from "ethers/lib/utils.js";
|
||||
import type { BaseContract, Event, providers, utils } from "ethers";
|
||||
import type { EventEmitter } from "eventemitter3";
|
||||
|
||||
/**
|
||||
@@ -325,7 +324,7 @@ export class ContractEvents<TContract extends BaseContract> {
|
||||
}
|
||||
|
||||
private toContractEvent<TEvent extends Record<string, any>>(
|
||||
event: EventFragment,
|
||||
event: utils.EventFragment,
|
||||
args: ReadonlyArray<any>,
|
||||
rawLog: providers.Log,
|
||||
): ContractEvent<TEvent> {
|
||||
|
||||
@@ -44,7 +44,6 @@ import {
|
||||
type Signer,
|
||||
constants,
|
||||
} from "ethers";
|
||||
import { ConnectionInfo } from "ethers/lib/utils.js";
|
||||
import invariant from "tiny-invariant";
|
||||
import { CONTRACT_ADDRESSES } from "../../constants/addresses/CONTRACT_ADDRESSES";
|
||||
import { getContractAddressByChainId } from "../../constants/addresses/getContractAddressByChainId";
|
||||
@@ -471,7 +470,7 @@ export class ContractWrapper<
|
||||
callOverrides: CallOverrides,
|
||||
) {
|
||||
const provider = this.getProvider() as providers.Provider & {
|
||||
connection?: ConnectionInfo;
|
||||
connection?: utils.ConnectionInfo;
|
||||
};
|
||||
|
||||
// Get metadata for transaction to populate into error
|
||||
|
||||
@@ -50,5 +50,5 @@ export * from "./contract-published-metadata";
|
||||
export * from "./contract-owner";
|
||||
export * from "./transactions";
|
||||
export * from "./contract-appuri";
|
||||
export * from "./smart-wallet";
|
||||
export * from "./smart-wallet-factory";
|
||||
export * from "./account";
|
||||
export * from "./account-factory";
|
||||
|
||||
@@ -30,8 +30,6 @@ import {
|
||||
constants,
|
||||
} from "ethers";
|
||||
import { BigNumber } from "ethers";
|
||||
import { FormatTypes } from "ethers/lib/utils.js";
|
||||
import type { ConnectionInfo } from "ethers/lib/utils.js";
|
||||
import invariant from "tiny-invariant";
|
||||
import EventEmitter from "eventemitter3";
|
||||
import type { DeployEvents } from "../../types/deploy";
|
||||
@@ -494,7 +492,7 @@ export class Transaction<
|
||||
try {
|
||||
// for dynamic contracts, add 30% to the gas limit to account for multiple delegate calls
|
||||
const abi = JSON.parse(
|
||||
this.contract.interface.format(FormatTypes.json) as string,
|
||||
this.contract.interface.format("json") as string,
|
||||
);
|
||||
if (isRouterContract(abi)) {
|
||||
overrides.gasLimit = overrides.gasLimit.mul(110).div(100);
|
||||
@@ -663,7 +661,7 @@ export class Transaction<
|
||||
*/
|
||||
private async transactionError(error: any) {
|
||||
const provider = this.provider as providers.Provider & {
|
||||
connection?: ConnectionInfo;
|
||||
connection?: utils.ConnectionInfo;
|
||||
};
|
||||
|
||||
// Get metadata for transaction to populate into error
|
||||
@@ -849,7 +847,7 @@ export class DeployTransaction extends TransactionContext {
|
||||
*/
|
||||
private async deployError(error: any) {
|
||||
const provider = this.provider as providers.Provider & {
|
||||
connection?: ConnectionInfo;
|
||||
connection?: utils.ConnectionInfo;
|
||||
};
|
||||
|
||||
// Get metadata for transaction to populate into error
|
||||
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
} from "ethers";
|
||||
import EventEmitter from "eventemitter3";
|
||||
import invariant from "tiny-invariant";
|
||||
import { BlockTag } from "@ethersproject/abstract-provider";
|
||||
import type { BlockTag } from "@ethersproject/abstract-provider";
|
||||
import { fetchCurrencyValue } from "../../common/currency/fetchCurrencyValue";
|
||||
import { isNativeToken } from "../../common/currency/isNativeToken";
|
||||
import { normalizePriceValue } from "../../common/currency/normalizePriceValue";
|
||||
|
||||
@@ -32,6 +32,17 @@ export type SignerWithRestrictions = {
|
||||
restrictions: AccessRestrictions;
|
||||
}
|
||||
|
||||
export const SignerWithRestrictionsSchema = /* @__PURE__ */ z.object({
|
||||
signer: AddressOrEnsSchema,
|
||||
isAdmin: /* @__PURE__ */ z.boolean(),
|
||||
restrictions: AccessRestrictionsSchema,
|
||||
});
|
||||
|
||||
export type SignerWithRestrictionsInput = z.input<typeof SignerWithRestrictionsSchema>;
|
||||
|
||||
export const SignerWithRestrictionsBatchSchema = /* @__PURE__ */ z.array(SignerWithRestrictionsSchema);
|
||||
export type SignerWithRestrictionsBatchInput = z.input<typeof SignerWithRestrictionsBatchSchema>;
|
||||
|
||||
export type SignedAccountPermissionsPayload = {
|
||||
payload: IAccountPermissions.RoleRequestStruct;
|
||||
signature: BytesLike;
|
||||
@@ -12,4 +12,4 @@ export * from "./multiwrap";
|
||||
export * from "./registry";
|
||||
export * from "./transactions";
|
||||
export * from "./contract";
|
||||
export * from "./smart-wallet";
|
||||
export * from "./account";
|
||||
|
||||
@@ -0,0 +1,821 @@
|
||||
import { sdk, signers } from "./before-setup";
|
||||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
|
||||
import { assert, expect } from "chai";
|
||||
import {
|
||||
SignerWithRestrictions,
|
||||
AccessRestrictions,
|
||||
Account,
|
||||
AccountFactory,
|
||||
SignerWithRestrictionsInput,
|
||||
SignerWithRestrictionsBatchInput,
|
||||
} from "../../src/evm";
|
||||
import { ContractFactory, utils } from "ethers";
|
||||
import EntrypointArtifact from "./mock/EntryPoint.json";
|
||||
import AccountFactoryArtifact from "./mock/AccountFactory.json";
|
||||
|
||||
// Target ABIs
|
||||
import IAccountCoreAbi from "@thirdweb-dev/contracts-js/dist/abis/IAccountCore.json";
|
||||
import {
|
||||
deployContractAndUploadMetadata,
|
||||
mockUploadContractMetadata,
|
||||
} from "./utils";
|
||||
import { IAccountCore, IAccountFactory } from "@thirdweb-dev/contracts-js";
|
||||
|
||||
global.fetch = /* @__PURE__ */ require("cross-fetch");
|
||||
|
||||
/* @__PURE__ */ describe("Accounts with account factory", function () {
|
||||
let accountFactory: AccountFactory<IAccountFactory>;
|
||||
let account: Account<IAccountCore>;
|
||||
|
||||
let adminWallet: SignerWithAddress;
|
||||
|
||||
let signer1Wallet: SignerWithAddress;
|
||||
let signer2Wallet: SignerWithAddress;
|
||||
let signer3Wallet: SignerWithAddress;
|
||||
let signer4Wallet: SignerWithAddress;
|
||||
let signer5Wallet: SignerWithAddress;
|
||||
let signer6Wallet: SignerWithAddress;
|
||||
let signer7Wallet: SignerWithAddress;
|
||||
let signer8Wallet: SignerWithAddress;
|
||||
let signer9Wallet: SignerWithAddress;
|
||||
|
||||
before(async () => {
|
||||
[
|
||||
adminWallet,
|
||||
signer1Wallet,
|
||||
signer2Wallet,
|
||||
signer3Wallet,
|
||||
signer4Wallet,
|
||||
signer5Wallet,
|
||||
signer6Wallet,
|
||||
signer7Wallet,
|
||||
signer8Wallet,
|
||||
signer9Wallet,
|
||||
] = signers;
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
const entrypoint = await new ContractFactory(
|
||||
EntrypointArtifact.abi,
|
||||
EntrypointArtifact.bytecode.object,
|
||||
adminWallet,
|
||||
).deploy();
|
||||
const factoryAddress = await deployContractAndUploadMetadata(
|
||||
AccountFactoryArtifact.abi,
|
||||
AccountFactoryArtifact.bytecode.object,
|
||||
adminWallet,
|
||||
[entrypoint.address],
|
||||
);
|
||||
accountFactory = (await sdk.getContract(factoryAddress)).accountFactory;
|
||||
});
|
||||
|
||||
describe("Test: AccountFactory actions", () => {
|
||||
it("Should create a new account for the admin", async () => {
|
||||
// Check before creating a account for `adminWallet`
|
||||
const isDeployed = await accountFactory.isAccountDeployed(
|
||||
adminWallet.address,
|
||||
);
|
||||
assert.isFalse(
|
||||
isDeployed,
|
||||
"Account is should not be deployed for admin.",
|
||||
);
|
||||
|
||||
const predictedAccountAddress: string =
|
||||
await accountFactory.predictAccountAddress(adminWallet.address);
|
||||
|
||||
const allAccountsBefore = (await accountFactory.getAllAccounts()).map(
|
||||
(wallet) => account.account,
|
||||
);
|
||||
assert.isFalse(
|
||||
allAccountsBefore.includes(predictedAccountAddress),
|
||||
"Account should not be deployed for admin already.",
|
||||
);
|
||||
|
||||
assert.isTrue(
|
||||
(await accountFactory.getAssociatedSigners(predictedAccountAddress))
|
||||
.length === 0,
|
||||
"Wallet should have no associated signers.",
|
||||
);
|
||||
assert.isTrue(
|
||||
(await accountFactory.getAssociatedAccounts(adminWallet.address))
|
||||
.length === 0,
|
||||
"Signer should have no associated accounts.",
|
||||
);
|
||||
|
||||
// Create account for `adminWallet`
|
||||
const tx = await accountFactory.createAccount(adminWallet.address);
|
||||
|
||||
// Checks after creating a account for `adminWallet`
|
||||
assert.strictEqual(
|
||||
utils.getAddress(tx.address),
|
||||
utils.getAddress(predictedAccountAddress),
|
||||
"Account address should match predicted address.",
|
||||
);
|
||||
assert.isTrue(
|
||||
await accountFactory.isAccountDeployed(adminWallet.address),
|
||||
"Account is should be deployed for admin.",
|
||||
);
|
||||
|
||||
const allAccountsAfter = await accountFactory.getAllAccounts();
|
||||
assert.isTrue(
|
||||
allAccountsAfter.length === 1,
|
||||
"Only one account should be created on the factory.",
|
||||
);
|
||||
|
||||
const { account, admin } = allAccountsAfter.filter(
|
||||
(wallet) =>
|
||||
utils.getAddress(wallet.account) ===
|
||||
utils.getAddress(predictedAccountAddress),
|
||||
)[0];
|
||||
assert.strictEqual(
|
||||
utils.getAddress(account),
|
||||
utils.getAddress(predictedAccountAddress),
|
||||
"Stored account address should match predicted address.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
utils.getAddress(admin),
|
||||
utils.getAddress(adminWallet.address),
|
||||
"Correct admin for account.",
|
||||
);
|
||||
|
||||
const associatedAccounts = await accountFactory.getAssociatedAccounts(
|
||||
admin,
|
||||
);
|
||||
const associatedSigner = await accountFactory.getAssociatedSigners(
|
||||
account,
|
||||
);
|
||||
|
||||
assert.isTrue(
|
||||
associatedAccounts.length === 1,
|
||||
"Wallet should have only the admin as an associated signer.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
utils.getAddress(account),
|
||||
utils.getAddress(associatedAccounts[0]),
|
||||
"Wallet should have only the admin as an associated signer.",
|
||||
);
|
||||
assert.isTrue(
|
||||
associatedSigner.length === 1,
|
||||
"Signer should have only the created account as an associated account.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
utils.getAddress(admin),
|
||||
utils.getAddress(associatedSigner[0]),
|
||||
"Signer should have only the created account as an associated account.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should throw if creating account for an admin who already has one", async () => {
|
||||
// Create a account for admin
|
||||
await accountFactory.createAccount(adminWallet.address);
|
||||
|
||||
// Try creating another account for the same admin
|
||||
try {
|
||||
await accountFactory.createAccount(adminWallet.address);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(
|
||||
`Account already deployed for admin: ${adminWallet.address}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("Test: Account actions", () => {
|
||||
beforeEach(async () => {
|
||||
// Create a account for admin
|
||||
const tx = await accountFactory.createAccount(adminWallet.address);
|
||||
const accountAddress = tx.address;
|
||||
|
||||
sdk.updateSignerOrProvider(adminWallet);
|
||||
await mockUploadContractMetadata(
|
||||
"smart-wallet",
|
||||
accountAddress,
|
||||
IAccountCoreAbi,
|
||||
);
|
||||
|
||||
account = (await sdk.getContract(accountAddress)).account;
|
||||
});
|
||||
|
||||
it("Should be able to add another admin to the account.", async () => {
|
||||
assert.isFalse(
|
||||
await account.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the account.",
|
||||
);
|
||||
|
||||
await account.grantAdminAccess(signer1Wallet.address);
|
||||
|
||||
assert.isTrue(
|
||||
await account.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should be an admin on the account.",
|
||||
);
|
||||
|
||||
const isAdmin = (
|
||||
(await account.getSignersWithRestrictions()).find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
) as SignerWithRestrictions
|
||||
).isAdmin;
|
||||
assert.isTrue(isAdmin, "New signer1 should be an admin on the account.");
|
||||
|
||||
assert.isTrue(
|
||||
(
|
||||
await accountFactory.getAssociatedSigners(account.getAddress())
|
||||
).includes(signer1Wallet.address),
|
||||
"New signer1 is an associated signer of the account.",
|
||||
);
|
||||
assert.isTrue(
|
||||
(
|
||||
await accountFactory.getAssociatedAccounts(signer1Wallet.address)
|
||||
).includes(account.getAddress()),
|
||||
"Wallet is an associated account of the signer.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should be able to remove an admin from the account.", async () => {
|
||||
await account.grantAdminAccess(signer1Wallet.address);
|
||||
assert.isTrue(
|
||||
await account.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should be an admin on the account.",
|
||||
);
|
||||
|
||||
await account.revokeAdminAccess(signer1Wallet.address);
|
||||
|
||||
assert.isFalse(
|
||||
await account.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the account.",
|
||||
);
|
||||
|
||||
assert.isFalse(
|
||||
(await account.getSignersWithRestrictions())
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the account.",
|
||||
);
|
||||
|
||||
assert.isFalse(
|
||||
(
|
||||
await accountFactory.getAssociatedSigners(account.getAddress())
|
||||
).includes(signer1Wallet.address),
|
||||
"New signer1 is not an associated signer of the account.",
|
||||
);
|
||||
assert.isFalse(
|
||||
(
|
||||
await accountFactory.getAssociatedAccounts(signer1Wallet.address)
|
||||
).includes(account.getAddress()),
|
||||
"Wallet is not an associated account of the signer.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should be able to grant restricted access to a new signer.", async () => {
|
||||
const signersWithRestrictions =
|
||||
await account.getSignersWithRestrictions();
|
||||
assert.isFalse(
|
||||
signersWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer should not already have access to the account.",
|
||||
);
|
||||
|
||||
// Grant access
|
||||
await account.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
assert.isFalse(
|
||||
await account.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the account.",
|
||||
);
|
||||
const newSignerWithRestrictions =
|
||||
await account.getSignersWithRestrictions();
|
||||
const restrictions = newSignerWithRestrictions.find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.isTrue(
|
||||
newSignerWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer1 should be a signer on the account.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.nativeTokenLimitPerTransaction.toString(),
|
||||
utils.parseEther("1").toString(),
|
||||
"New signer1 should have the expected native token limit.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"New signer1 should have one approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
|
||||
assert.isTrue(
|
||||
(
|
||||
await accountFactory.getAssociatedSigners(account.getAddress())
|
||||
).includes(signer1Wallet.address),
|
||||
"New signer1 is an associated signer of the account.",
|
||||
);
|
||||
assert.isTrue(
|
||||
(
|
||||
await accountFactory.getAssociatedAccounts(signer1Wallet.address)
|
||||
).includes(account.getAddress()),
|
||||
"Wallet is an associated account of the signer.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should not be able to grant restricted access to a signer who already has access.", async () => {
|
||||
// Grant access to signer1
|
||||
await account.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
// Try granting access to signer1 again
|
||||
try {
|
||||
await account.grantAccess(signer1Wallet.address, {
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(`Signer already has access`);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should be able to revoke restricted access from an authorized signer.", async () => {
|
||||
// Grant access to signer1
|
||||
await account.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
// Revoke access
|
||||
await account.revokeAccess(signer1Wallet.address);
|
||||
|
||||
const signersWithRestrictions =
|
||||
await account.getSignersWithRestrictions();
|
||||
assert.isFalse(
|
||||
signersWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer should not have access to the account.",
|
||||
);
|
||||
|
||||
assert.isFalse(
|
||||
await account.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the account.",
|
||||
);
|
||||
|
||||
assert.isFalse(
|
||||
(
|
||||
await accountFactory.getAssociatedSigners(account.getAddress())
|
||||
).includes(signer1Wallet.address),
|
||||
"New signer1 is not an associated signer of the account.",
|
||||
);
|
||||
assert.isFalse(
|
||||
(
|
||||
await accountFactory.getAssociatedAccounts(signer1Wallet.address)
|
||||
).includes(account.getAddress()),
|
||||
"Wallet is not an associated account of the signer.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should not be able to revoke restricted access from a signer who doesn't have access.", async () => {
|
||||
const signersWithRestrictions =
|
||||
await account.getSignersWithRestrictions();
|
||||
assert.isFalse(
|
||||
signersWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer should not already have access to the account.",
|
||||
);
|
||||
|
||||
// Try revoking access from signer1
|
||||
try {
|
||||
await account.revokeAccess(signer1Wallet.address);
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(`Signer does not have any access`);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should be able to update access of an authorized signer.", async () => {
|
||||
// Grant access
|
||||
await account.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
assert.isFalse(
|
||||
await account.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the account.",
|
||||
);
|
||||
|
||||
const signerWithRestrictions = await account.getSignersWithRestrictions();
|
||||
const restrictions = signerWithRestrictions.find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.isTrue(
|
||||
signerWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer1 should be a signer on the account.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.nativeTokenLimitPerTransaction.toString(),
|
||||
utils.parseEther("1").toString(),
|
||||
"New signer1 should have the expected native token limit.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"New signer1 should have one approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
|
||||
// Update access
|
||||
await account.updateAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "3",
|
||||
approvedCallTargets: [signer2Wallet.address],
|
||||
});
|
||||
|
||||
assert.isFalse(
|
||||
await account.isAdmin(signer1Wallet.address),
|
||||
"New signer1 should not be an admin on the account.",
|
||||
);
|
||||
|
||||
const newSignerWithRestrictions =
|
||||
await account.getSignersWithRestrictions();
|
||||
const newRestrictions = newSignerWithRestrictions.find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.isTrue(
|
||||
newSignerWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer1 should be a signer on the account.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.nativeTokenLimitPerTransaction.toString(),
|
||||
utils.parseEther("3").toString(),
|
||||
"New signer1 should have the expected native token limit.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"New signer1 should have one approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets[0],
|
||||
signer2Wallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should not be able to update access of a signer who doesn't have access.", async () => {
|
||||
const signersWithRestrictions =
|
||||
await account.getSignersWithRestrictions();
|
||||
assert.isFalse(
|
||||
signersWithRestrictions
|
||||
.map((result) => utils.getAddress(result.signer))
|
||||
.includes(signer1Wallet.address),
|
||||
"New signer should not already have access to the account.",
|
||||
);
|
||||
|
||||
// Try updating access of signer1
|
||||
try {
|
||||
await account.updateAccess(signer1Wallet.address, {
|
||||
approvedCallTargets: [signer2Wallet.address],
|
||||
});
|
||||
expect.fail();
|
||||
} catch (err: any) {
|
||||
expect(err.message).to.equal(`Signer does not have any access`);
|
||||
}
|
||||
});
|
||||
|
||||
it("Should be able to append an approved target for an authorized signer.", async () => {
|
||||
// Grant access
|
||||
await account.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
const restrictions = (await account.getSignersWithRestrictions()).find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"New signer1 should have one approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
|
||||
// Append approved target
|
||||
await account.approveTargetForSigner(
|
||||
signer1Wallet.address,
|
||||
signer2Wallet.address,
|
||||
);
|
||||
|
||||
const newRestrictions = (await account.getSignersWithRestrictions()).find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets.length,
|
||||
2,
|
||||
"New signer1 should have two approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets[1],
|
||||
signer2Wallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should be able to remove an approved target for an authorized signer.", async () => {
|
||||
// Grant access
|
||||
await account.grantAccess(signer1Wallet.address, {
|
||||
nativeTokenLimitPerTransaction: "1",
|
||||
approvedCallTargets: [adminWallet.address, signer2Wallet.address],
|
||||
});
|
||||
|
||||
const restrictions = (await account.getSignersWithRestrictions()).find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets.length,
|
||||
2,
|
||||
"New signer1 should have two approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.approvedCallTargets[1],
|
||||
signer2Wallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
|
||||
// Remove approved target
|
||||
await account.disapproveTargetForSigner(
|
||||
signer1Wallet.address,
|
||||
signer2Wallet.address,
|
||||
);
|
||||
|
||||
const newRestrictions = (await account.getSignersWithRestrictions()).find(
|
||||
(result) =>
|
||||
utils.getAddress(result.signer) ===
|
||||
utils.getAddress(signer1Wallet.address),
|
||||
)?.restrictions as AccessRestrictions;
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"New signer1 should have one approved call targets.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
newRestrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"New signer1 should have the expected approved call targets.",
|
||||
);
|
||||
});
|
||||
|
||||
it("Should be able to set access for the account in a batch.", async () => {
|
||||
/**
|
||||
* All cases to test
|
||||
*
|
||||
* - 1. Adding a new admin
|
||||
* - 2. Removing existing admin
|
||||
* - 3. Adding a new scoped signer
|
||||
* - 4. Removing an existing scoped signer
|
||||
* - 5. Updating the restrictions of an existing scoped signer
|
||||
* - 6. Existing admin -> new scoped signer (demote)
|
||||
* - 7. Existing scoped signer -> new admin :check: (promote)
|
||||
**/
|
||||
|
||||
const signersWithRestrictions: SignerWithRestrictionsBatchInput = [];
|
||||
|
||||
// Setup
|
||||
|
||||
const restrictionsForAdmin: SignerWithRestrictionsInput = {
|
||||
signer: adminWallet.address,
|
||||
isAdmin: true,
|
||||
restrictions: { approvedCallTargets: [] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsForAdmin);
|
||||
|
||||
// Adding a new admin: Signer3
|
||||
const restrictionsSigner3: SignerWithRestrictionsInput = {
|
||||
signer: signer3Wallet.address,
|
||||
isAdmin: true,
|
||||
restrictions: { approvedCallTargets: [] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner3);
|
||||
|
||||
// Removing existing admin
|
||||
await account.grantAdminAccess(signer4Wallet.address);
|
||||
|
||||
const restrictionsSigner4: SignerWithRestrictionsInput = {
|
||||
signer: signer4Wallet.address,
|
||||
isAdmin: false,
|
||||
restrictions: { approvedCallTargets: [] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner4);
|
||||
|
||||
// Adding a new scoped signer
|
||||
const restrictionsSigner5: SignerWithRestrictionsInput = {
|
||||
signer: signer5Wallet.address,
|
||||
isAdmin: false,
|
||||
restrictions: { approvedCallTargets: [adminWallet.address] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner5);
|
||||
|
||||
// Removing an existing scoped signer
|
||||
await account.grantAccess(signer6Wallet.address, {
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
const restrictionsSigner6: SignerWithRestrictionsInput = {
|
||||
signer: signer6Wallet.address,
|
||||
isAdmin: false,
|
||||
restrictions: { approvedCallTargets: [] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner6);
|
||||
|
||||
// Updating the restrictions of an existing scoped signer
|
||||
|
||||
await account.grantAccess(signer7Wallet.address, {
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
const restrictionsSigner7: SignerWithRestrictionsInput = {
|
||||
signer: signer7Wallet.address,
|
||||
isAdmin: false,
|
||||
restrictions: { approvedCallTargets: [signer1Wallet.address] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner7);
|
||||
|
||||
// Existing admin -> new scoped signer (demote)
|
||||
await account.grantAdminAccess(signer8Wallet.address);
|
||||
|
||||
const restrictionsSigner8: SignerWithRestrictionsInput = {
|
||||
signer: signer8Wallet.address,
|
||||
isAdmin: false,
|
||||
restrictions: { approvedCallTargets: [adminWallet.address] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner8);
|
||||
|
||||
// Existing scoped signer -> new admin (promote)
|
||||
await account.grantAccess(signer9Wallet.address, {
|
||||
approvedCallTargets: [adminWallet.address],
|
||||
});
|
||||
|
||||
const restrictionsSigner9: SignerWithRestrictionsInput = {
|
||||
signer: signer9Wallet.address,
|
||||
isAdmin: true,
|
||||
restrictions: { approvedCallTargets: [] },
|
||||
};
|
||||
signersWithRestrictions.push(restrictionsSigner9);
|
||||
|
||||
// Set access in batch
|
||||
await account.setAccess(signersWithRestrictions);
|
||||
|
||||
// Now checking if permissions are set correctly
|
||||
const signersWithRestrictionsAfter =
|
||||
await account.getSignersWithRestrictions();
|
||||
|
||||
for (const restrictions of signersWithRestrictionsAfter) {
|
||||
switch (restrictions.signer) {
|
||||
// `adminWallet` should be an admin
|
||||
case adminWallet.address:
|
||||
assert.isTrue(
|
||||
restrictions.isAdmin,
|
||||
"Admin account should be an admin.",
|
||||
);
|
||||
break;
|
||||
// `signer3Wallet` should be an admin
|
||||
case signer3Wallet.address:
|
||||
assert.isTrue(
|
||||
restrictions.isAdmin,
|
||||
"Signer3 account should be an admin.",
|
||||
);
|
||||
break;
|
||||
// `signer4Wallet` should not be admin or scoped signer
|
||||
case signer4Wallet.address:
|
||||
assert.isFalse(
|
||||
restrictions.isAdmin,
|
||||
"Signer4 account should not be an admin.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets.length,
|
||||
0,
|
||||
"Signer4 account should not have any approved call targets.",
|
||||
);
|
||||
break;
|
||||
// `signer5Wallet` should be a scoped signer
|
||||
case signer5Wallet.address:
|
||||
assert.isFalse(
|
||||
restrictions.isAdmin,
|
||||
"Signer5 account should not be an admin.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"Signer5 account should have one approved call target.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"Signer5 account should have the expected approved call targets.",
|
||||
);
|
||||
break;
|
||||
// `signer6Wallet` should not be admin or scoped signer
|
||||
case signer6Wallet.address:
|
||||
assert.isFalse(
|
||||
restrictions.isAdmin,
|
||||
"Signer6 account should not be an admin.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets.length,
|
||||
0,
|
||||
"Signer6 account should not have any approved call targets.",
|
||||
);
|
||||
break;
|
||||
// `signer7Wallet` should be a scoped signer with its updated restrictions
|
||||
case signer7Wallet.address:
|
||||
assert.isFalse(
|
||||
restrictions.isAdmin,
|
||||
"Signer7 account should not be an admin.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"Signer7 account should have one approved call target.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets[0],
|
||||
signer1Wallet.address,
|
||||
"Signer7 account should have the expected approved call targets.",
|
||||
);
|
||||
break;
|
||||
// `signer8Wallet` should be a scoped signer
|
||||
case signer8Wallet.address:
|
||||
assert.isFalse(
|
||||
restrictions.isAdmin,
|
||||
"Signer8 account should not be an admin.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets.length,
|
||||
1,
|
||||
"Signer8 account should have one approved call target.",
|
||||
);
|
||||
assert.strictEqual(
|
||||
restrictions.restrictions.approvedCallTargets[0],
|
||||
adminWallet.address,
|
||||
"Signer8 account should have the expected approved call targets.",
|
||||
);
|
||||
break;
|
||||
// `signer9Wallet` should be an admin
|
||||
case signer9Wallet.address:
|
||||
assert.isTrue(
|
||||
restrictions.isAdmin,
|
||||
"Signer9 account should be an admin.",
|
||||
);
|
||||
break;
|
||||
default:
|
||||
assert.fail("Unexpected signer.");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -82,6 +82,7 @@ let signers: SignerWithAddress[];
|
||||
let storage: ThirdwebStorage;
|
||||
let implementations: { [key in ContractType]?: string };
|
||||
let mock_weth_address: string;
|
||||
let thirdwebFactory: TWFactory;
|
||||
|
||||
const fastForwardTime = async (timeInSeconds: number): Promise<void> => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
@@ -133,6 +134,7 @@ export const mochaHooks = {
|
||||
.connect(signer)
|
||||
.deploy(trustedForwarderAddress, registry.address)) as TWFactory;
|
||||
|
||||
thirdwebFactory = await thirdwebFactoryDeployer.deployed();
|
||||
const deployTxFactory = thirdwebFactoryDeployer.deployTransaction;
|
||||
await deployTxFactory.wait();
|
||||
const thirdwebRegistryAddress = await thirdwebFactoryDeployer.registry();
|
||||
@@ -391,4 +393,5 @@ export {
|
||||
storage,
|
||||
implementations,
|
||||
hardhatEthers,
|
||||
thirdwebFactory,
|
||||
};
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { ThirdwebSDK } from "../../src/evm";
|
||||
import { expectError, sdk } from "./before-setup";
|
||||
import { expect } from "chai";
|
||||
import { ethers } from "ethers";
|
||||
import { Wallet } from "ethers";
|
||||
|
||||
describe("Error Handling", async () => {
|
||||
it("should throw proper error on account with no balance", async () => {
|
||||
const newSdk = ThirdwebSDK.fromSigner(
|
||||
ethers.Wallet.createRandom().connect(sdk.getProvider()),
|
||||
Wallet.createRandom().connect(sdk.getProvider()),
|
||||
);
|
||||
|
||||
try {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,85 @@
|
||||
// from SplitWallet published at: ipfs://Qmc5cQotuEnCo71ZztJk69wc8kuKbGmuCARL2FyAojoi9r/
|
||||
|
||||
const abi = [
|
||||
{
|
||||
inputs: [],
|
||||
stateMutability: "nonpayable",
|
||||
type: "constructor",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "Unauthorized",
|
||||
type: "error",
|
||||
},
|
||||
{
|
||||
anonymous: false,
|
||||
inputs: [
|
||||
{
|
||||
indexed: true,
|
||||
internalType: "address",
|
||||
name: "split",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
indexed: false,
|
||||
internalType: "uint256",
|
||||
name: "amount",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "ReceiveETH",
|
||||
type: "event",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "contract ERC20",
|
||||
name: "token",
|
||||
type: "address",
|
||||
},
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "amount",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "sendERC20ToMain",
|
||||
outputs: [],
|
||||
stateMutability: "payable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [
|
||||
{
|
||||
internalType: "uint256",
|
||||
name: "amount",
|
||||
type: "uint256",
|
||||
},
|
||||
],
|
||||
name: "sendETHToMain",
|
||||
outputs: [],
|
||||
stateMutability: "payable",
|
||||
type: "function",
|
||||
},
|
||||
{
|
||||
inputs: [],
|
||||
name: "splitMain",
|
||||
outputs: [
|
||||
{
|
||||
internalType: "contract ISplitMain",
|
||||
name: "",
|
||||
type: "address",
|
||||
},
|
||||
],
|
||||
stateMutability: "view",
|
||||
type: "function",
|
||||
},
|
||||
];
|
||||
|
||||
const bytecode =
|
||||
"0x60a060405234801561001057600080fd5b5033606081901b60805261035461004c60003960008181604b0152818160bc015281816101080152818161013c015261018601526103546000f3fe6080604052600436106100345760003560e01c80630e769b2b146100395780637c1f3ffe14610089578063ab0ebff41461009e575b600080fd5b34801561004557600080fd5b5061006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009c6100973660046102d0565b6100b1565b005b61009c6100ac366004610306565b610131565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100f9576040516282b42960e81b815260040160405180910390fd5b61012d6001600160a01b0383167f0000000000000000000000000000000000000000000000000000000000000000836101af565b5050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610179576040516282b42960e81b815260040160405180910390fd5b6101ac6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682610233565b50565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af19150506101ea81610289565b61022d5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064015b60405180910390fd5b50505050565b600080600080600085875af19050806102845760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610224565b505050565b60003d8261029b57806000803e806000fd5b80602081146102b35780156102c457600092506102c9565b816000803e600051151592506102c9565b600192505b5050919050565b600080604083850312156102e2578182fd5b82356001600160a01b03811681146102f8578283fd5b946020939093013593505050565b600060208284031215610317578081fd5b503591905056fea26469706673582212208e095a368bcb2efb2a8afd9b560ad94441e926086a4bc92edf16c33900df798e64736f6c63430008040033";
|
||||
|
||||
const deployedBytecode =
|
||||
"0x6080604052600436106100345760003560e01c80630e769b2b146100395780637c1f3ffe14610089578063ab0ebff41461009e575b600080fd5b34801561004557600080fd5b5061006d7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b03909116815260200160405180910390f35b61009c6100973660046102d0565b6100b1565b005b61009c6100ac366004610306565b610131565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146100f9576040516282b42960e81b815260040160405180910390fd5b61012d6001600160a01b0383167f0000000000000000000000000000000000000000000000000000000000000000836101af565b5050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610179576040516282b42960e81b815260040160405180910390fd5b6101ac6001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001682610233565b50565b600060405163a9059cbb60e01b81526001600160a01b03841660048201528260248201526000806044836000895af19150506101ea81610289565b61022d5760405162461bcd60e51b815260206004820152600f60248201526e1514905394d1915497d19052531151608a1b60448201526064015b60405180910390fd5b50505050565b600080600080600085875af19050806102845760405162461bcd60e51b815260206004820152601360248201527211551217d514905394d1915497d19052531151606a1b6044820152606401610224565b505050565b60003d8261029b57806000803e806000fd5b80602081146102b35780156102c457600092506102c9565b816000803e600051151592506102c9565b600192505b5050919050565b600080604083850312156102e2578182fd5b82356001600160a01b03811681146102f8578283fd5b946020939093013593505050565b600060208284031215610317578081fd5b503591905056fea26469706673582212208e095a368bcb2efb2a8afd9b560ad94441e926086a4bc92edf16c33900df798e64736f6c63430008040033";
|
||||
|
||||
export { abi, bytecode, deployedBytecode };
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -20,5 +20,13 @@ export async function mockUploadWithCID(
|
||||
file: FileOrBufferOrString,
|
||||
options?: IpfsUploadBatchOptions | undefined,
|
||||
) {
|
||||
storage[cid] = file;
|
||||
const [cidMain, id] = cid.split("/");
|
||||
|
||||
if (id) {
|
||||
storage[cidMain] = {
|
||||
[id]: file,
|
||||
};
|
||||
} else {
|
||||
storage[cid] = file;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
import { SignerWithAddress } from "@nomiclabs/hardhat-ethers/signers";
|
||||
import { jsonProvider, sdk, signers, thirdwebFactory } from "./before-setup";
|
||||
import { expect, assert } from "chai";
|
||||
import {
|
||||
Forwarder__factory,
|
||||
DropERC721__factory,
|
||||
ERC721Base__factory,
|
||||
} from "@thirdweb-dev/contracts-js";
|
||||
import {
|
||||
bytecode as SplitMainBytecode,
|
||||
deployedBytecode as SplitMainDeployedBytecode,
|
||||
abi as SplitMainAbi,
|
||||
} from "./metadata/SplitMain";
|
||||
import {
|
||||
bytecode as SplitWalletBytecode,
|
||||
deployedBytecode as SplitWalletDeployedBytecode,
|
||||
abi as SplitWalletAbi,
|
||||
} from "./metadata/SplitWallet";
|
||||
import {
|
||||
bytecode as TWCloneFactoryBytecode,
|
||||
abi as TWCloneFactoryAbi,
|
||||
} from "./metadata/TWCloneFactory";
|
||||
import { mockUploadMetadataWithBytecode } from "./utils";
|
||||
|
||||
const extendedMetadataMock = {
|
||||
name: "",
|
||||
metadataUri: "",
|
||||
bytecodeUri: "",
|
||||
analytics: {},
|
||||
version: "1.0.0",
|
||||
displayName: "",
|
||||
description: "",
|
||||
changelog: "",
|
||||
isDeployableViaFactory: false,
|
||||
isDeployableViaProxy: false,
|
||||
factoryDeploymentData: {
|
||||
implementationAddresses: {},
|
||||
implementationInitializerFunction: "initialize",
|
||||
factoryAddresses: {},
|
||||
},
|
||||
constructorParams: {},
|
||||
publisher: "",
|
||||
customFactoryInput: {
|
||||
factoryFunction: "",
|
||||
customFactoryAddresses: [],
|
||||
},
|
||||
};
|
||||
|
||||
describe("New Publish Flow", async () => {
|
||||
let adminWallet: SignerWithAddress,
|
||||
samWallet: SignerWithAddress,
|
||||
bobWallet: SignerWithAddress,
|
||||
w4: SignerWithAddress;
|
||||
|
||||
beforeEach(async () => {
|
||||
await jsonProvider.send("hardhat_reset", []);
|
||||
[adminWallet, samWallet, bobWallet, , , , , w4] = signers;
|
||||
});
|
||||
before("Mock upload infra contracts", async () => {
|
||||
// mock upload Forwarder
|
||||
await mockUploadMetadataWithBytecode(
|
||||
"Forwarder",
|
||||
Forwarder__factory.abi,
|
||||
Forwarder__factory.bytecode,
|
||||
"",
|
||||
{
|
||||
...extendedMetadataMock,
|
||||
deployType: "standard",
|
||||
networksForDeployment: {
|
||||
allNetworks: true,
|
||||
networksEnabled: [],
|
||||
},
|
||||
},
|
||||
"ipfs://Qmcu8FaqerUvQYb4qPg7PwkXa6dRtEe45LedLJPN42Jwqe/0",
|
||||
// ^ we use actual publish uri as mock uri here, because this contract's uri is fetched from publisher by contractName
|
||||
);
|
||||
|
||||
// mock upload TWCloneFactory
|
||||
await mockUploadMetadataWithBytecode(
|
||||
"Forwarder",
|
||||
TWCloneFactoryAbi,
|
||||
TWCloneFactoryBytecode,
|
||||
"",
|
||||
{
|
||||
...extendedMetadataMock,
|
||||
deployType: "standard",
|
||||
networksForDeployment: {
|
||||
allNetworks: true,
|
||||
networksEnabled: [],
|
||||
},
|
||||
},
|
||||
"ipfs://QmYfw13Zykqf9jAmJobNgYrEpatEF9waWcQPUHvJ7sctRb/0",
|
||||
// ^ we use actual publish uri as mock uri here, because this contract's uri is fetched from publisher by contractName
|
||||
);
|
||||
});
|
||||
|
||||
describe("Deploy newly published contract", async () => {
|
||||
it("should deploy regular contract", async () => {
|
||||
// mock publish as a standard-deploy contract
|
||||
const mockPublishUri = await mockUploadMetadataWithBytecode(
|
||||
"ERC721Base",
|
||||
ERC721Base__factory.abi,
|
||||
ERC721Base__factory.bytecode,
|
||||
"",
|
||||
{
|
||||
...extendedMetadataMock,
|
||||
deployType: "standard",
|
||||
networksForDeployment: {
|
||||
allNetworks: true,
|
||||
networksEnabled: [],
|
||||
},
|
||||
publisher: await adminWallet.getAddress(),
|
||||
},
|
||||
);
|
||||
|
||||
// deploy with mock uri
|
||||
const admin = await adminWallet.getAddress();
|
||||
const contractAddress = await sdk.deployer.deployContractFromUri(
|
||||
mockPublishUri,
|
||||
["Direct Deploy ERC721Base", "DDE", admin, 5],
|
||||
);
|
||||
const contract = await sdk.getContract(contractAddress);
|
||||
|
||||
const name = await contract.call("name");
|
||||
const owner = await contract.call("owner");
|
||||
|
||||
expect(name).to.equal("Direct Deploy ERC721Base");
|
||||
expect(owner).to.equal(admin);
|
||||
});
|
||||
|
||||
it("should deploy with custom factory", async () => {
|
||||
// mock publish SplitMain as a standard-deploy contract
|
||||
const splitMainMockUri = await mockUploadMetadataWithBytecode(
|
||||
"SplitMain",
|
||||
SplitMainAbi,
|
||||
SplitMainBytecode,
|
||||
SplitMainDeployedBytecode,
|
||||
{
|
||||
...extendedMetadataMock,
|
||||
deployType: "standard",
|
||||
networksForDeployment: {
|
||||
allNetworks: true,
|
||||
networksEnabled: [],
|
||||
},
|
||||
publisher: await adminWallet.getAddress(),
|
||||
},
|
||||
);
|
||||
|
||||
// deploy custom-factory `SplitMain`, with mock uri
|
||||
const splitMainAddress = await sdk.deployer.deployContractFromUri(
|
||||
splitMainMockUri,
|
||||
[],
|
||||
);
|
||||
|
||||
// mock publish SplitWallet as a custom-factory-deploy contract
|
||||
const splitWalletMockUri = await mockUploadMetadataWithBytecode(
|
||||
"SplitWallet",
|
||||
SplitWalletAbi,
|
||||
SplitWalletBytecode,
|
||||
SplitWalletDeployedBytecode,
|
||||
{
|
||||
...extendedMetadataMock,
|
||||
deployType: "customFactory",
|
||||
factoryDeploymentData: {
|
||||
...extendedMetadataMock.factoryDeploymentData,
|
||||
customFactoryInput: {
|
||||
factoryFunction: "createSplit",
|
||||
params: [],
|
||||
customFactoryAddresses: {
|
||||
"31337": splitMainAddress,
|
||||
},
|
||||
},
|
||||
},
|
||||
networksForDeployment: {
|
||||
allNetworks: true,
|
||||
networksEnabled: [],
|
||||
},
|
||||
publisher: await adminWallet.getAddress(),
|
||||
},
|
||||
);
|
||||
|
||||
// deploy contract via custom-factory, with mock uri
|
||||
const splitWalletAddress = await sdk.deployer.deployContractFromUri(
|
||||
splitWalletMockUri,
|
||||
[
|
||||
[await bobWallet.getAddress(), await adminWallet.getAddress()],
|
||||
[500000, 500000],
|
||||
0,
|
||||
await adminWallet.getAddress(),
|
||||
],
|
||||
);
|
||||
|
||||
const splitContract = await sdk.getContract(splitWalletAddress);
|
||||
const deployingAddress = await splitContract.call("splitMain");
|
||||
|
||||
expect(deployingAddress).to.equal(splitMainAddress);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Deploy re-published contract", async () => {
|
||||
it("should deploy with auto factory", async () => {
|
||||
const mockPublisher = process.env.contractPublisherAddress;
|
||||
process.env.contractPublisherAddress =
|
||||
"0x664244560eBa21Bf82d7150C791bE1AbcD5B4cd7";
|
||||
const adminAddress = await adminWallet.getAddress();
|
||||
|
||||
// mock publish as a autoFactory-deploy contract
|
||||
const mockPublishUri = await mockUploadMetadataWithBytecode(
|
||||
"DropERC721",
|
||||
DropERC721__factory.abi,
|
||||
DropERC721__factory.bytecode,
|
||||
"",
|
||||
{
|
||||
...extendedMetadataMock,
|
||||
deployType: "autoFactory",
|
||||
networksForDeployment: {
|
||||
allNetworks: true,
|
||||
networksEnabled: [],
|
||||
},
|
||||
publisher: adminAddress,
|
||||
},
|
||||
);
|
||||
|
||||
// deploy via autoFactory, with mock uri
|
||||
const contractAddress = await sdk.deployer.deployContractFromUri(
|
||||
mockPublishUri,
|
||||
[
|
||||
adminAddress,
|
||||
"DropERC721 Minimal Proxy",
|
||||
"DME",
|
||||
"",
|
||||
[],
|
||||
adminAddress,
|
||||
adminAddress,
|
||||
5,
|
||||
5,
|
||||
adminAddress,
|
||||
],
|
||||
);
|
||||
const contract = await sdk.getContract(contractAddress);
|
||||
|
||||
const name = await contract.call("name");
|
||||
const owner = await contract.call("owner");
|
||||
const code = await sdk.getProvider().getCode(contractAddress);
|
||||
|
||||
expect(name).to.equal("DropERC721 Minimal Proxy");
|
||||
expect(owner).to.equal(adminAddress);
|
||||
assert(code.startsWith("0x363d3d373d3d3d363d73"));
|
||||
|
||||
process.env.contractPublisherAddress = mockPublisher;
|
||||
});
|
||||
});
|
||||
|
||||
describe("Deploy old contract without re-publishing", async () => {
|
||||
it("should deploy regular contract", async () => {
|
||||
// mock publish as old style -- omit deployType, networksForDeployment etc
|
||||
const mockPublishUri = await mockUploadMetadataWithBytecode(
|
||||
"ERC721Base",
|
||||
ERC721Base__factory.abi,
|
||||
ERC721Base__factory.bytecode,
|
||||
"",
|
||||
extendedMetadataMock,
|
||||
);
|
||||
|
||||
// deploy with mock uri
|
||||
const admin = await adminWallet.getAddress();
|
||||
const contractAddress = await sdk.deployer.deployContractFromUri(
|
||||
mockPublishUri,
|
||||
["Direct Deploy ERC721Base", "DDE", admin, 5],
|
||||
);
|
||||
const contract = await sdk.getContract(contractAddress);
|
||||
|
||||
const name = await contract.call("name");
|
||||
const owner = await contract.call("owner");
|
||||
|
||||
expect(name).to.equal("Direct Deploy ERC721Base");
|
||||
expect(owner).to.equal(admin);
|
||||
});
|
||||
|
||||
it("should deploy via old factory", async () => {
|
||||
const mockPublisher = process.env.contractPublisherAddress;
|
||||
process.env.contractPublisherAddress =
|
||||
"0x664244560eBa21Bf82d7150C791bE1AbcD5B4cd7";
|
||||
const adminAddress = await adminWallet.getAddress();
|
||||
|
||||
// mock publish as old-style factory deployable -- omit deployType, networksForDeployment etc
|
||||
const mockPublishUri = await mockUploadMetadataWithBytecode(
|
||||
"DropERC721",
|
||||
DropERC721__factory.abi,
|
||||
DropERC721__factory.bytecode,
|
||||
"",
|
||||
{
|
||||
...extendedMetadataMock,
|
||||
isDeployableViaFactory: true,
|
||||
publisher: adminAddress,
|
||||
},
|
||||
);
|
||||
|
||||
// deploy implementation
|
||||
const implementationAddress = await sdk.deployer.deployContractFromUri(
|
||||
mockPublishUri,
|
||||
[],
|
||||
{
|
||||
forceDirectDeploy: true,
|
||||
},
|
||||
);
|
||||
await (
|
||||
await thirdwebFactory.addImplementation(implementationAddress)
|
||||
).wait();
|
||||
|
||||
// re-upload, with implementation address
|
||||
const mockPublishUriUpdated = await mockUploadMetadataWithBytecode(
|
||||
"DropERC721",
|
||||
DropERC721__factory.abi,
|
||||
DropERC721__factory.bytecode,
|
||||
"",
|
||||
{
|
||||
...extendedMetadataMock,
|
||||
isDeployableViaFactory: true,
|
||||
factoryDeploymentData: {
|
||||
...extendedMetadataMock?.factoryDeploymentData,
|
||||
implementationAddresses: {
|
||||
"31337": implementationAddress,
|
||||
},
|
||||
factoryAddresses: {
|
||||
"31337": process.env.factoryAddress,
|
||||
},
|
||||
},
|
||||
publisher: adminAddress,
|
||||
},
|
||||
);
|
||||
|
||||
// Deploy proxy DropERC721
|
||||
const contractAddress = await sdk.deployer.deployContractFromUri(
|
||||
mockPublishUriUpdated,
|
||||
[
|
||||
adminAddress,
|
||||
"Drop Proxy Old",
|
||||
"DPA",
|
||||
"",
|
||||
[],
|
||||
adminAddress,
|
||||
adminAddress,
|
||||
5,
|
||||
5,
|
||||
adminAddress,
|
||||
],
|
||||
);
|
||||
|
||||
const drop = await sdk.getContract(contractAddress);
|
||||
const bytecode = await sdk.getProvider().getCode(contractAddress);
|
||||
const name = await drop.call("name");
|
||||
|
||||
expect(name).to.equal("Drop Proxy Old");
|
||||
assert(bytecode.startsWith("0x363d3d373d3d3d363d73"));
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: test any-evm vs standard chain deploys with same publish-uri
|
||||
});
|
||||
@@ -1,4 +1,8 @@
|
||||
import { resolveContractUriFromAddress } from "../../src/evm";
|
||||
import {
|
||||
FullPublishMetadata,
|
||||
extractIPFSHashFromBytecode,
|
||||
resolveContractUriFromAddress,
|
||||
} from "../../src/evm";
|
||||
import { defaultProvider } from "./before-setup";
|
||||
import { mockUploadWithCID } from "./mock/MockStorage";
|
||||
import { ContractInterface, ethers } from "ethers";
|
||||
@@ -18,10 +22,12 @@ export const deployContractAndUploadMetadata = async (
|
||||
return deployed.address;
|
||||
};
|
||||
|
||||
const mockUploadContractMetadata = async (
|
||||
export const mockUploadContractMetadata = async (
|
||||
contractName: string,
|
||||
address: string,
|
||||
abi: any,
|
||||
extendedMetadata?: FullPublishMetadata | any,
|
||||
publishUri?: string,
|
||||
) => {
|
||||
const ipfsHash = (await resolveContractUriFromAddress(
|
||||
address,
|
||||
@@ -57,11 +63,68 @@ const mockUploadContractMetadata = async (
|
||||
|
||||
// mock raw-metadata
|
||||
const rawMeta = {
|
||||
...extendedMetadata,
|
||||
name: contractName,
|
||||
metadataUri: ipfsHash,
|
||||
bytecodeUri: bytecodeUri,
|
||||
};
|
||||
const rawMetaUri = ipfsHash.concat("rawMeta");
|
||||
const rawMetaUri = publishUri || ipfsHash.concat("rawMeta");
|
||||
const rawMetaCID = rawMetaUri.replace("ipfs://", "");
|
||||
await mockUploadWithCID(rawMetaCID, JSON.stringify(rawMeta));
|
||||
|
||||
return rawMetaUri;
|
||||
};
|
||||
|
||||
export const mockUploadMetadataWithBytecode = async (
|
||||
contractName: string,
|
||||
abi: any,
|
||||
bytecode: string,
|
||||
deployedBytecode?: string,
|
||||
extendedMetadata?: FullPublishMetadata | any,
|
||||
publishUri?: string,
|
||||
): Promise<string> => {
|
||||
const ipfsHash =
|
||||
deployedBytecode && deployedBytecode.length > 0
|
||||
? (extractIPFSHashFromBytecode(deployedBytecode) as string)
|
||||
: (extractIPFSHashFromBytecode(bytecode) as string);
|
||||
|
||||
const metadata = {
|
||||
compiler: {},
|
||||
output: {
|
||||
abi,
|
||||
devdoc: {},
|
||||
userdoc: {},
|
||||
},
|
||||
settings: {
|
||||
compilationTarget: {
|
||||
contract: contractName,
|
||||
},
|
||||
evmVersion: {},
|
||||
metadata: {},
|
||||
optimizer: {},
|
||||
remappings: [],
|
||||
},
|
||||
sources: {},
|
||||
version: 1,
|
||||
};
|
||||
const metadataCID = ipfsHash.replace("ipfs://", "");
|
||||
await mockUploadWithCID(metadataCID, JSON.stringify(metadata));
|
||||
|
||||
// mock bytecode
|
||||
const bytecodeUri = ipfsHash.concat("bytecode");
|
||||
const bytecodeCID = bytecodeUri.replace("ipfs://", "");
|
||||
await mockUploadWithCID(bytecodeCID, bytecode);
|
||||
|
||||
// mock raw-metadata
|
||||
const rawMeta = {
|
||||
...extendedMetadata,
|
||||
name: contractName,
|
||||
metadataUri: ipfsHash,
|
||||
bytecodeUri: bytecodeUri,
|
||||
};
|
||||
const rawMetaUri = publishUri || ipfsHash.concat("rawMeta");
|
||||
const rawMetaCID = rawMetaUri.replace("ipfs://", "");
|
||||
await mockUploadWithCID(rawMetaCID, JSON.stringify(rawMeta));
|
||||
|
||||
return rawMetaUri;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user