thirdweb 5.56.0-nightly-07b949dd8c07ffdeda40a5549c31ad4b09abbbf1-20240916000437 → 5.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/contract/deployment/publisher.js +4 -4
- package/dist/cjs/contract/deployment/publisher.js.map +1 -1
- package/dist/cjs/exports/extensions/thirdweb.js +4 -3
- package/dist/cjs/exports/extensions/thirdweb.js.map +1 -1
- package/dist/cjs/exports/modules.js +4 -1
- package/dist/cjs/exports/modules.js.map +1 -1
- package/dist/cjs/extensions/modules/common/checkModulesCompatibility.js +95 -0
- package/dist/cjs/extensions/modules/common/checkModulesCompatibility.js.map +1 -0
- package/dist/cjs/extensions/thirdweb/write/publish.js +106 -0
- package/dist/cjs/extensions/thirdweb/write/publish.js.map +1 -0
- package/dist/cjs/react/core/hooks/pay/useBuyWithCryptoStatus.js +7 -1
- package/dist/cjs/react/core/hooks/pay/useBuyWithCryptoStatus.js.map +1 -1
- package/dist/cjs/react/core/hooks/pay/useBuyWithFiatStatus.js +15 -1
- package/dist/cjs/react/core/hooks/pay/useBuyWithFiatStatus.js.map +1 -1
- package/dist/cjs/react/core/providers/invalidateWalletBalance.js +1 -1
- package/dist/cjs/react/core/providers/invalidateWalletBalance.js.map +1 -1
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +7 -2
- package/dist/cjs/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
- package/dist/cjs/transaction/resolve-method.js +8 -1
- package/dist/cjs/transaction/resolve-method.js.map +1 -1
- package/dist/cjs/utils/arrays.js +23 -0
- package/dist/cjs/utils/arrays.js.map +1 -0
- package/dist/cjs/utils/semver.js +67 -0
- package/dist/cjs/utils/semver.js.map +1 -0
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/version.js.map +1 -1
- package/dist/esm/contract/deployment/publisher.js +1 -1
- package/dist/esm/contract/deployment/publisher.js.map +1 -1
- package/dist/esm/exports/extensions/thirdweb.js +1 -1
- package/dist/esm/exports/extensions/thirdweb.js.map +1 -1
- package/dist/esm/exports/modules.js +2 -1
- package/dist/esm/exports/modules.js.map +1 -1
- package/dist/esm/extensions/modules/common/checkModulesCompatibility.js +93 -0
- package/dist/esm/extensions/modules/common/checkModulesCompatibility.js.map +1 -0
- package/dist/esm/extensions/thirdweb/write/publish.js +102 -0
- package/dist/esm/extensions/thirdweb/write/publish.js.map +1 -0
- package/dist/esm/react/core/hooks/pay/useBuyWithCryptoStatus.js +7 -1
- package/dist/esm/react/core/hooks/pay/useBuyWithCryptoStatus.js.map +1 -1
- package/dist/esm/react/core/hooks/pay/useBuyWithFiatStatus.js +15 -1
- package/dist/esm/react/core/hooks/pay/useBuyWithFiatStatus.js.map +1 -1
- package/dist/esm/react/core/providers/invalidateWalletBalance.js +1 -1
- package/dist/esm/react/core/providers/invalidateWalletBalance.js.map +1 -1
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js +7 -2
- package/dist/esm/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.js.map +1 -1
- package/dist/esm/transaction/resolve-method.js +8 -1
- package/dist/esm/transaction/resolve-method.js.map +1 -1
- package/dist/esm/utils/arrays.js +20 -0
- package/dist/esm/utils/arrays.js.map +1 -0
- package/dist/esm/utils/semver.js +62 -0
- package/dist/esm/utils/semver.js.map +1 -0
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/types/contract/deployment/publisher.d.ts +1 -0
- package/dist/types/contract/deployment/publisher.d.ts.map +1 -1
- package/dist/types/exports/extensions/thirdweb.d.ts +1 -1
- package/dist/types/exports/extensions/thirdweb.d.ts.map +1 -1
- package/dist/types/exports/modules.d.ts +2 -1
- package/dist/types/exports/modules.d.ts.map +1 -1
- package/dist/types/exports/utils.d.ts +1 -0
- package/dist/types/exports/utils.d.ts.map +1 -1
- package/dist/types/extensions/modules/common/checkModulesCompatibility.d.ts +9 -0
- package/dist/types/extensions/modules/common/checkModulesCompatibility.d.ts.map +1 -0
- package/dist/types/extensions/thirdweb/write/publish.d.ts +29 -0
- package/dist/types/extensions/thirdweb/write/publish.d.ts.map +1 -0
- package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts +7 -14
- package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts.map +1 -1
- package/dist/types/react/core/hooks/pay/useBuyWithCryptoStatus.d.ts.map +1 -1
- package/dist/types/react/core/hooks/pay/useBuyWithFiatStatus.d.ts.map +1 -1
- package/dist/types/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.d.ts.map +1 -1
- package/dist/types/transaction/resolve-method.d.ts +2 -2
- package/dist/types/transaction/resolve-method.d.ts.map +1 -1
- package/dist/types/utils/any-evm/deploy-metadata.d.ts +18 -1
- package/dist/types/utils/any-evm/deploy-metadata.d.ts.map +1 -1
- package/dist/types/utils/arrays.d.ts +5 -0
- package/dist/types/utils/arrays.d.ts.map +1 -0
- package/dist/types/utils/semver.d.ts +25 -0
- package/dist/types/utils/semver.d.ts.map +1 -0
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/package.json +23 -23
- package/src/contract/deployment/publisher.ts +2 -1
- package/src/exports/extensions/thirdweb.ts +6 -4
- package/src/exports/modules.ts +5 -1
- package/src/exports/utils.ts +9 -0
- package/src/extensions/erc721/lazyMinting/write/createAndReveal.test.ts +1 -1
- package/src/extensions/modules/MintableERC1155/mintableERC1155.test.ts +1 -1
- package/src/extensions/modules/MintableERC20/mintableERC20.test.ts +1 -1
- package/src/extensions/modules/MintableERC721/mintableERC721.test.ts +1 -1
- package/src/extensions/modules/common/checkModulesCompatibility.test.ts +46 -0
- package/src/extensions/modules/common/checkModulesCompatibility.ts +123 -0
- package/src/extensions/thirdweb/write/publish.test.ts +162 -0
- package/src/extensions/thirdweb/write/publish.ts +131 -0
- package/src/react/core/hooks/connection/ConnectButtonProps.ts +7 -14
- package/src/react/core/hooks/pay/useBuyWithCryptoStatus.ts +7 -1
- package/src/react/core/hooks/pay/useBuyWithFiatStatus.ts +17 -1
- package/src/react/core/providers/invalidateWalletBalance.test.ts +1 -1
- package/src/react/core/providers/invalidateWalletBalance.ts +1 -1
- package/src/react/web/ui/ConnectWallet/screens/Buy/BuyScreen.tsx +8 -2
- package/src/transaction/resolve-method.test.ts +78 -0
- package/src/transaction/resolve-method.ts +14 -3
- package/src/utils/any-evm/deploy-metadata.ts +18 -4
- package/src/utils/arrays.ts +23 -0
- package/src/utils/semver.ts +76 -0
- package/src/version.ts +1 -1
@@ -0,0 +1,162 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import { FORKED_POLYGON_CHAIN } from "../../../../test/src/chains.js";
|
3
|
+
import { TEST_CLIENT } from "../../../../test/src/test-clients.js";
|
4
|
+
import { TEST_ACCOUNT_D } from "../../../../test/src/test-wallets.js";
|
5
|
+
import { getContract } from "../../../contract/contract.js";
|
6
|
+
import { CONTRACT_PUBLISHER_ADDRESS } from "../../../contract/deployment/publisher.js";
|
7
|
+
import { parseEventLogs } from "../../../event/actions/parse-logs.js";
|
8
|
+
import { download } from "../../../storage/download.js";
|
9
|
+
import { sendAndConfirmTransaction } from "../../../transaction/actions/send-and-confirm-transaction.js";
|
10
|
+
import { fetchDeployMetadata } from "../../../utils/any-evm/deploy-metadata.js";
|
11
|
+
import { contractPublishedEvent } from "../__generated__/IContractPublisher/events/ContractPublished.js";
|
12
|
+
import { getAllPublishedContracts } from "../__generated__/IContractPublisher/read/getAllPublishedContracts.js";
|
13
|
+
import { getPublishedContractVersions } from "../__generated__/IContractPublisher/read/getPublishedContractVersions.js";
|
14
|
+
import { publishContract } from "./publish.js";
|
15
|
+
|
16
|
+
describe.runIf(process.env.TW_SECRET_KEY)("publishContract", () => {
|
17
|
+
it("should publish a contract successfully", async () => {
|
18
|
+
const publisherContract = getContract({
|
19
|
+
client: TEST_CLIENT,
|
20
|
+
chain: FORKED_POLYGON_CHAIN,
|
21
|
+
address: CONTRACT_PUBLISHER_ADDRESS,
|
22
|
+
});
|
23
|
+
|
24
|
+
let publishedContracts = await getAllPublishedContracts({
|
25
|
+
contract: publisherContract,
|
26
|
+
publisher: TEST_ACCOUNT_D.address,
|
27
|
+
});
|
28
|
+
|
29
|
+
expect(publishedContracts.length).toBe(0);
|
30
|
+
|
31
|
+
const catAttackDeployMetadata = await fetchDeployMetadata({
|
32
|
+
client: TEST_CLIENT,
|
33
|
+
uri: "ipfs://QmWcAMvBy49WRrzZeK4EQeVnkdmyb5H4STz4gUQwnt1kzC",
|
34
|
+
});
|
35
|
+
|
36
|
+
const tx = publishContract({
|
37
|
+
contract: publisherContract,
|
38
|
+
account: TEST_ACCOUNT_D,
|
39
|
+
metadata: {
|
40
|
+
...catAttackDeployMetadata,
|
41
|
+
version: "0.0.1",
|
42
|
+
description: "Cat Attack NFT",
|
43
|
+
changelog: "Initial release",
|
44
|
+
},
|
45
|
+
});
|
46
|
+
const result = await sendAndConfirmTransaction({
|
47
|
+
transaction: tx,
|
48
|
+
account: TEST_ACCOUNT_D,
|
49
|
+
});
|
50
|
+
expect(result.transactionHash.length).toBeGreaterThan(0);
|
51
|
+
const logs = parseEventLogs({
|
52
|
+
events: [contractPublishedEvent()],
|
53
|
+
logs: result.logs,
|
54
|
+
});
|
55
|
+
expect(logs?.[0]?.args.publishedContract.contractId).toBe("CatAttackNFT");
|
56
|
+
expect(logs?.[0]?.args.publishedContract.publishMetadataUri).toBeDefined();
|
57
|
+
const rawMeta = await download({
|
58
|
+
client: TEST_CLIENT,
|
59
|
+
uri: logs?.[0]?.args.publishedContract.publishMetadataUri ?? "",
|
60
|
+
}).then((r) => r.json());
|
61
|
+
expect(rawMeta).toMatchInlineSnapshot(`
|
62
|
+
{
|
63
|
+
"bytecodeUri": "ipfs://QmVyB9qAs7XdZYNGPcNbff43BX1tyZFJkqdfp1eXiNS8AG/0",
|
64
|
+
"changelog": "Initial release",
|
65
|
+
"compilers": {
|
66
|
+
"solc": [
|
67
|
+
{
|
68
|
+
"bytecodeUri": "ipfs://QmVyB9qAs7XdZYNGPcNbff43BX1tyZFJkqdfp1eXiNS8AG/0",
|
69
|
+
"compilerVersion": "",
|
70
|
+
"evmVersion": "",
|
71
|
+
"metadataUri": "ipfs://Qmd2Ef29NzCjomqYXZbWa8ZdF1AESDAS1HDAonmAnTgHPs",
|
72
|
+
},
|
73
|
+
],
|
74
|
+
},
|
75
|
+
"description": "Cat Attack NFT",
|
76
|
+
"metadataUri": "ipfs://Qmd2Ef29NzCjomqYXZbWa8ZdF1AESDAS1HDAonmAnTgHPs",
|
77
|
+
"name": "CatAttackNFT",
|
78
|
+
"publisher": "0x90F79bf6EB2c4f870365E785982E1f101E93b906",
|
79
|
+
"routerType": "none",
|
80
|
+
"version": "0.0.1",
|
81
|
+
}
|
82
|
+
`);
|
83
|
+
const publishedData = await fetchDeployMetadata({
|
84
|
+
client: TEST_CLIENT,
|
85
|
+
uri: logs?.[0]?.args.publishedContract.publishMetadataUri ?? "",
|
86
|
+
});
|
87
|
+
expect(publishedData.abi).toBeDefined();
|
88
|
+
expect(publishedData.bytecode).toBeDefined();
|
89
|
+
expect(publishedData.version).toBe("0.0.1");
|
90
|
+
expect(publishedData.changelog).toBe("Initial release");
|
91
|
+
expect(publishedData.name).toBe("CatAttackNFT");
|
92
|
+
expect(publishedData.description).toBe("Cat Attack NFT");
|
93
|
+
expect(publishedData.publisher).toBe(TEST_ACCOUNT_D.address);
|
94
|
+
expect(publishedData.routerType).toBe("none");
|
95
|
+
|
96
|
+
publishedContracts = await getAllPublishedContracts({
|
97
|
+
contract: publisherContract,
|
98
|
+
publisher: TEST_ACCOUNT_D.address,
|
99
|
+
});
|
100
|
+
|
101
|
+
expect(publishedContracts.length).toBe(1);
|
102
|
+
|
103
|
+
expect(
|
104
|
+
sendAndConfirmTransaction({
|
105
|
+
account: TEST_ACCOUNT_D,
|
106
|
+
transaction: publishContract({
|
107
|
+
contract: publisherContract,
|
108
|
+
account: TEST_ACCOUNT_D,
|
109
|
+
previousMetadata: publishedData,
|
110
|
+
metadata: {
|
111
|
+
...publishedData,
|
112
|
+
version: "0.0.1",
|
113
|
+
changelog: "Initial release 2",
|
114
|
+
},
|
115
|
+
}),
|
116
|
+
}),
|
117
|
+
).rejects.toThrow("Version 0.0.1 is not greater than 0.0.1");
|
118
|
+
|
119
|
+
const tx2 = publishContract({
|
120
|
+
contract: publisherContract,
|
121
|
+
account: TEST_ACCOUNT_D,
|
122
|
+
previousMetadata: publishedData,
|
123
|
+
metadata: {
|
124
|
+
...publishedData,
|
125
|
+
version: "0.0.2",
|
126
|
+
changelog: "Initial release 2",
|
127
|
+
},
|
128
|
+
});
|
129
|
+
const result2 = await sendAndConfirmTransaction({
|
130
|
+
transaction: tx2,
|
131
|
+
account: TEST_ACCOUNT_D,
|
132
|
+
});
|
133
|
+
|
134
|
+
expect(result2.transactionHash.length).toBeGreaterThan(0);
|
135
|
+
const logs2 = parseEventLogs({
|
136
|
+
events: [contractPublishedEvent()],
|
137
|
+
logs: result2.logs,
|
138
|
+
});
|
139
|
+
expect(logs2?.[0]?.args.publishedContract.contractId).toBe("CatAttackNFT");
|
140
|
+
expect(logs2?.[0]?.args.publishedContract.publishMetadataUri).toBeDefined();
|
141
|
+
const publishedData2 = await fetchDeployMetadata({
|
142
|
+
client: TEST_CLIENT,
|
143
|
+
uri: logs2?.[0]?.args.publishedContract.publishMetadataUri ?? "",
|
144
|
+
});
|
145
|
+
expect(publishedData2.version).toBe("0.0.2");
|
146
|
+
|
147
|
+
publishedContracts = await getAllPublishedContracts({
|
148
|
+
contract: publisherContract,
|
149
|
+
publisher: TEST_ACCOUNT_D.address,
|
150
|
+
});
|
151
|
+
|
152
|
+
expect(publishedContracts.length).toBe(1);
|
153
|
+
|
154
|
+
const versions = await getPublishedContractVersions({
|
155
|
+
contract: publisherContract,
|
156
|
+
contractId: "CatAttackNFT",
|
157
|
+
publisher: TEST_ACCOUNT_D.address,
|
158
|
+
});
|
159
|
+
|
160
|
+
expect(versions.length).toEqual(2);
|
161
|
+
}, 120000);
|
162
|
+
});
|
@@ -0,0 +1,131 @@
|
|
1
|
+
import type { Abi } from "abitype";
|
2
|
+
import { encodePacked, keccak256, toFunctionSelector } from "viem/utils";
|
3
|
+
import { polygon } from "../../../chains/chain-definitions/polygon.js";
|
4
|
+
import type { ThirdwebClient } from "../../../client/client.js";
|
5
|
+
import { ZERO_ADDRESS } from "../../../constants/addresses.js";
|
6
|
+
import { getContract } from "../../../contract/contract.js";
|
7
|
+
import { CONTRACT_PUBLISHER_ADDRESS } from "../../../contract/deployment/publisher.js";
|
8
|
+
import { download } from "../../../storage/download.js";
|
9
|
+
import { upload } from "../../../storage/upload.js";
|
10
|
+
import type { BaseTransactionOptions } from "../../../transaction/types.js";
|
11
|
+
import type {
|
12
|
+
ExtendedMetadata,
|
13
|
+
FetchDeployMetadataResult,
|
14
|
+
} from "../../../utils/any-evm/deploy-metadata.js";
|
15
|
+
import { ensureBytecodePrefix } from "../../../utils/bytecode/prefix.js";
|
16
|
+
import { isIncrementalVersion } from "../../../utils/semver.js";
|
17
|
+
import type { Account } from "../../../wallets/interfaces/wallet.js";
|
18
|
+
import { isGetInstalledModulesSupported } from "../../modules/__generated__/IModularCore/read/getInstalledModules.js";
|
19
|
+
import { publishContract as generatedPublishContract } from "../__generated__/IContractPublisher/write/publishContract.js";
|
20
|
+
|
21
|
+
export type PublishContractParams = {
|
22
|
+
account: Account;
|
23
|
+
metadata: FetchDeployMetadataResult & {
|
24
|
+
version: string;
|
25
|
+
};
|
26
|
+
previousMetadata?: FetchDeployMetadataResult;
|
27
|
+
};
|
28
|
+
|
29
|
+
/**
|
30
|
+
* Publish a contract to the contract publisher.
|
31
|
+
*
|
32
|
+
* @param options - The options for publishing the contract.
|
33
|
+
* @returns The transaction to publish the contract.
|
34
|
+
* @example
|
35
|
+
* ```ts
|
36
|
+
* const tx = publishContract({
|
37
|
+
* contract,
|
38
|
+
* account,
|
39
|
+
* metadata,
|
40
|
+
* });
|
41
|
+
* ```
|
42
|
+
* @extension thirdweb
|
43
|
+
*/
|
44
|
+
export function publishContract(
|
45
|
+
options: BaseTransactionOptions<PublishContractParams>,
|
46
|
+
) {
|
47
|
+
return generatedPublishContract({
|
48
|
+
contract: options.contract,
|
49
|
+
async asyncParams() {
|
50
|
+
const currentVersion = options.previousMetadata?.version;
|
51
|
+
// check if the version is greater than the current version
|
52
|
+
if (
|
53
|
+
currentVersion &&
|
54
|
+
!isIncrementalVersion(currentVersion, options.metadata.version)
|
55
|
+
) {
|
56
|
+
throw Error(
|
57
|
+
`Version ${options.metadata.version} is not greater than ${currentVersion}`,
|
58
|
+
);
|
59
|
+
}
|
60
|
+
// hash the bytecode
|
61
|
+
const bytecode = await download({
|
62
|
+
client: options.contract.client,
|
63
|
+
uri: options.metadata.bytecodeUri,
|
64
|
+
}).then((r) => r.text());
|
65
|
+
const bytecodeHash = keccak256(
|
66
|
+
encodePacked(["bytes"], [ensureBytecodePrefix(bytecode)]),
|
67
|
+
);
|
68
|
+
|
69
|
+
const abi = options.metadata.abi;
|
70
|
+
const routerType = getRouterType(abi);
|
71
|
+
// not spreading here, we don't want to re-upload the fetched data like bytecode
|
72
|
+
const newMetadata: ExtendedMetadata = {
|
73
|
+
bytecodeUri: options.metadata.bytecodeUri,
|
74
|
+
metadataUri: options.metadata.metadataUri,
|
75
|
+
name: options.metadata.name,
|
76
|
+
version: options.metadata.version,
|
77
|
+
audit: options.metadata.audit,
|
78
|
+
changelog: options.metadata.changelog,
|
79
|
+
compositeAbi: options.metadata.compositeAbi,
|
80
|
+
constructorParams: options.metadata.constructorParams,
|
81
|
+
defaultExtensions: options.metadata.defaultExtensions,
|
82
|
+
defaultModules: options.metadata.defaultModules,
|
83
|
+
deployType: options.metadata.deployType,
|
84
|
+
description: options.metadata.description,
|
85
|
+
displayName: options.metadata.displayName,
|
86
|
+
factoryDeploymentData: options.metadata.factoryDeploymentData,
|
87
|
+
isDeployableViaFactory: options.metadata.isDeployableViaFactory,
|
88
|
+
isDeployableViaProxy: options.metadata.isDeployableViaProxy,
|
89
|
+
logo: options.metadata.logo,
|
90
|
+
networksForDeployment: options.metadata.networksForDeployment,
|
91
|
+
readme: options.metadata.readme,
|
92
|
+
tags: options.metadata.tags,
|
93
|
+
compilers: options.metadata.compilers,
|
94
|
+
publisher: options.account.address,
|
95
|
+
routerType,
|
96
|
+
};
|
97
|
+
|
98
|
+
// upload the new metadata
|
99
|
+
const newMetadataUri = await upload({
|
100
|
+
client: options.contract.client,
|
101
|
+
files: [newMetadata],
|
102
|
+
});
|
103
|
+
|
104
|
+
return {
|
105
|
+
publisher: options.account.address,
|
106
|
+
contractId: options.metadata.name,
|
107
|
+
publishMetadataUri: newMetadataUri,
|
108
|
+
compilerMetadataUri: options.metadata.metadataUri,
|
109
|
+
bytecodeHash,
|
110
|
+
implementation: ZERO_ADDRESS,
|
111
|
+
};
|
112
|
+
},
|
113
|
+
});
|
114
|
+
}
|
115
|
+
|
116
|
+
export function getContractPublisher(client: ThirdwebClient) {
|
117
|
+
return getContract({
|
118
|
+
client,
|
119
|
+
chain: polygon,
|
120
|
+
address: CONTRACT_PUBLISHER_ADDRESS,
|
121
|
+
});
|
122
|
+
}
|
123
|
+
|
124
|
+
function getRouterType(abi: Abi) {
|
125
|
+
const fnSelectors = abi
|
126
|
+
.filter((f) => f.type === "function")
|
127
|
+
.map((f) => toFunctionSelector(f));
|
128
|
+
const isModule = isGetInstalledModulesSupported(fnSelectors);
|
129
|
+
// TODO add dynamic detection
|
130
|
+
return isModule ? "modular" : "none";
|
131
|
+
}
|
@@ -113,6 +113,13 @@ export type PayUIOptions = Prettify<
|
|
113
113
|
status: BuyWithFiatStatus;
|
114
114
|
},
|
115
115
|
) => void;
|
116
|
+
/**
|
117
|
+
* Customize the display of the PayEmbed UI.
|
118
|
+
*/
|
119
|
+
metadata?: {
|
120
|
+
name?: string;
|
121
|
+
image?: string;
|
122
|
+
};
|
116
123
|
} & (FundWalletOptions | DirectPaymentOptions | TranasctionOptions)
|
117
124
|
>;
|
118
125
|
|
@@ -145,13 +152,6 @@ export type DirectPaymentOptions = {
|
|
145
152
|
* The payment information
|
146
153
|
*/
|
147
154
|
paymentInfo: PaymentInfo;
|
148
|
-
/**
|
149
|
-
* Customize the display of the PayEmbed UI.
|
150
|
-
*/
|
151
|
-
metadata?: {
|
152
|
-
name?: string;
|
153
|
-
image?: string;
|
154
|
-
};
|
155
155
|
};
|
156
156
|
|
157
157
|
export type TranasctionOptions = {
|
@@ -160,13 +160,6 @@ export type TranasctionOptions = {
|
|
160
160
|
* The transaction to be executed.
|
161
161
|
*/
|
162
162
|
transaction: PreparedTransaction;
|
163
|
-
/**
|
164
|
-
* Customize the display of the PayEmbed UI.
|
165
|
-
*/
|
166
|
-
metadata?: {
|
167
|
-
name?: string;
|
168
|
-
image?: string;
|
169
|
-
};
|
170
163
|
};
|
171
164
|
|
172
165
|
/**
|
@@ -64,7 +64,13 @@ export function useBuyWithCryptoStatus(params?: BuyWithCryptoTransaction) {
|
|
64
64
|
return getBuyWithCryptoStatus(params);
|
65
65
|
},
|
66
66
|
enabled: !!params,
|
67
|
-
refetchInterval:
|
67
|
+
refetchInterval: (query) => {
|
68
|
+
const status = (query.state.data as BuyWithCryptoStatus)?.status;
|
69
|
+
if (status === "COMPLETED" || status === "FAILED") {
|
70
|
+
return false;
|
71
|
+
}
|
72
|
+
return 5000;
|
73
|
+
},
|
68
74
|
refetchIntervalInBackground: true,
|
69
75
|
retry: true,
|
70
76
|
});
|
@@ -45,7 +45,23 @@ export function useBuyWithFiatStatus(
|
|
45
45
|
return getBuyWithFiatStatus(params);
|
46
46
|
},
|
47
47
|
enabled: !!params,
|
48
|
-
refetchInterval:
|
48
|
+
refetchInterval: (query) => {
|
49
|
+
const data = query.state.data as BuyWithFiatStatus;
|
50
|
+
const status = data?.status;
|
51
|
+
if (
|
52
|
+
status === "ON_RAMP_TRANSFER_FAILED" ||
|
53
|
+
status === "PAYMENT_FAILED" ||
|
54
|
+
status === "CRYPTO_SWAP_COMPLETED" ||
|
55
|
+
// onRampToken and toToken being the same means there is no additional swap step
|
56
|
+
(status === "ON_RAMP_TRANSFER_COMPLETED" &&
|
57
|
+
data?.quote.toToken.chainId === data?.quote.onRampToken.chainId &&
|
58
|
+
data?.quote.toToken.tokenAddress.toLowerCase() ===
|
59
|
+
data?.quote.onRampToken.tokenAddress.toLowerCase())
|
60
|
+
) {
|
61
|
+
return false;
|
62
|
+
}
|
63
|
+
return 5000;
|
64
|
+
},
|
49
65
|
refetchIntervalInBackground: true,
|
50
66
|
retry: true,
|
51
67
|
});
|
@@ -25,7 +25,7 @@ describe("invalidateWalletBalance", () => {
|
|
25
25
|
invalidateWalletBalance(queryClient);
|
26
26
|
|
27
27
|
expect(queryClient.invalidateQueries).toHaveBeenCalledWith({
|
28
|
-
queryKey: ["walletBalance"
|
28
|
+
queryKey: ["walletBalance"] as const,
|
29
29
|
});
|
30
30
|
});
|
31
31
|
});
|
@@ -7,6 +7,6 @@ export function invalidateWalletBalance(
|
|
7
7
|
return queryClient.invalidateQueries({
|
8
8
|
// invalidate any walletBalance queries for this chainId
|
9
9
|
// TODO: add wallet address in here if we can get it somehow
|
10
|
-
queryKey: ["walletBalance", chainId]
|
10
|
+
queryKey: chainId ? ["walletBalance", chainId] : ["walletBalance"],
|
11
11
|
});
|
12
12
|
}
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import { IdCardIcon } from "@radix-ui/react-icons";
|
2
|
+
import { useQueryClient } from "@tanstack/react-query";
|
2
3
|
import { useCallback, useMemo, useState } from "react";
|
3
4
|
import { trackPayEvent } from "../../../../../../analytics/track.js";
|
4
5
|
import type { Chain } from "../../../../../../chains/types.js";
|
@@ -24,6 +25,7 @@ import { useWalletBalance } from "../../../../../core/hooks/others/useWalletBala
|
|
24
25
|
import { useBuyWithCryptoQuote } from "../../../../../core/hooks/pay/useBuyWithCryptoQuote.js";
|
25
26
|
import { useBuyWithFiatQuote } from "../../../../../core/hooks/pay/useBuyWithFiatQuote.js";
|
26
27
|
import { useActiveAccount } from "../../../../../core/hooks/wallets/useActiveAccount.js";
|
28
|
+
import { invalidateWalletBalance } from "../../../../../core/providers/invalidateWalletBalance.js";
|
27
29
|
import type { SupportedTokens } from "../../../../../core/utils/defaultTokens.js";
|
28
30
|
import { LoadingScreen } from "../../../../wallets/shared/LoadingScreen.js";
|
29
31
|
import type { PayEmbedConnectOptions } from "../../../PayEmbed.js";
|
@@ -226,14 +228,17 @@ function BuyScreenContent(props: BuyScreenContentProps) {
|
|
226
228
|
|
227
229
|
// screens ----------------------------
|
228
230
|
|
231
|
+
const queryClient = useQueryClient();
|
232
|
+
|
229
233
|
const onSwapSuccess = useCallback(
|
230
234
|
(_status: BuyWithCryptoStatus) => {
|
231
235
|
props.payOptions.onPurchaseSuccess?.({
|
232
236
|
type: "crypto",
|
233
237
|
status: _status,
|
234
238
|
});
|
239
|
+
invalidateWalletBalance(queryClient);
|
235
240
|
},
|
236
|
-
[props.payOptions.onPurchaseSuccess],
|
241
|
+
[props.payOptions.onPurchaseSuccess, queryClient],
|
237
242
|
);
|
238
243
|
|
239
244
|
const onFiatSuccess = useCallback(
|
@@ -242,8 +247,9 @@ function BuyScreenContent(props: BuyScreenContentProps) {
|
|
242
247
|
type: "fiat",
|
243
248
|
status: _status,
|
244
249
|
});
|
250
|
+
invalidateWalletBalance(queryClient);
|
245
251
|
},
|
246
|
-
[props.payOptions.onPurchaseSuccess],
|
252
|
+
[props.payOptions.onPurchaseSuccess, queryClient],
|
247
253
|
);
|
248
254
|
|
249
255
|
if (screen.id === "connect-payer-wallet") {
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
2
|
+
import {
|
3
|
+
USDT_CONTRACT,
|
4
|
+
USDT_CONTRACT_WITH_ABI,
|
5
|
+
} from "../../test/src/test-contracts.js";
|
6
|
+
import { resolveMethod } from "./resolve-method.js";
|
7
|
+
|
8
|
+
describe.runIf(process.env.TW_SECRET_KEY)("resolveMethod", () => {
|
9
|
+
it("should return parseAbiItem result for function signature", async () => {
|
10
|
+
const result = await resolveMethod(
|
11
|
+
"function transfer(address to, uint256 amount)",
|
12
|
+
)(USDT_CONTRACT);
|
13
|
+
expect(result).toMatchInlineSnapshot(`
|
14
|
+
{
|
15
|
+
"inputs": [
|
16
|
+
{
|
17
|
+
"name": "to",
|
18
|
+
"type": "address",
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"name": "amount",
|
22
|
+
"type": "uint256",
|
23
|
+
},
|
24
|
+
],
|
25
|
+
"name": "transfer",
|
26
|
+
"outputs": [],
|
27
|
+
"stateMutability": "nonpayable",
|
28
|
+
"type": "function",
|
29
|
+
}
|
30
|
+
`);
|
31
|
+
});
|
32
|
+
|
33
|
+
it("should return parseAbiItem result for abi", async () => {
|
34
|
+
const result = await resolveMethod("transfer")(USDT_CONTRACT_WITH_ABI);
|
35
|
+
expect(result).toMatchInlineSnapshot(`
|
36
|
+
{
|
37
|
+
"inputs": [
|
38
|
+
{
|
39
|
+
"name": "_to",
|
40
|
+
"type": "address",
|
41
|
+
},
|
42
|
+
{
|
43
|
+
"name": "_value",
|
44
|
+
"type": "uint256",
|
45
|
+
},
|
46
|
+
],
|
47
|
+
"name": "transfer",
|
48
|
+
"outputs": [],
|
49
|
+
"stateMutability": "nonpayable",
|
50
|
+
"type": "function",
|
51
|
+
}
|
52
|
+
`);
|
53
|
+
});
|
54
|
+
|
55
|
+
it("should return parseAbiItem result for abi", async () => {
|
56
|
+
const result = await resolveMethod("transfer")(USDT_CONTRACT);
|
57
|
+
expect(result).toMatchInlineSnapshot(`
|
58
|
+
{
|
59
|
+
"constant": false,
|
60
|
+
"inputs": [
|
61
|
+
{
|
62
|
+
"name": "_to",
|
63
|
+
"type": "address",
|
64
|
+
},
|
65
|
+
{
|
66
|
+
"name": "_value",
|
67
|
+
"type": "uint256",
|
68
|
+
},
|
69
|
+
],
|
70
|
+
"name": "transfer",
|
71
|
+
"outputs": [],
|
72
|
+
"payable": false,
|
73
|
+
"stateMutability": "nonpayable",
|
74
|
+
"type": "function",
|
75
|
+
}
|
76
|
+
`);
|
77
|
+
});
|
78
|
+
});
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import type { Abi, AbiFunction } from "abitype";
|
2
|
+
import { parseAbiItem } from "abitype";
|
2
3
|
import { resolveContractAbi } from "../contract/actions/resolve-abi.js";
|
3
4
|
import type { ThirdwebContract } from "../contract/contract.js";
|
4
5
|
|
@@ -22,9 +23,19 @@ import type { ThirdwebContract } from "../contract/contract.js";
|
|
22
23
|
* ```
|
23
24
|
* @contract
|
24
25
|
*/
|
25
|
-
export function resolveMethod<
|
26
|
-
|
27
|
-
|
26
|
+
export function resolveMethod<
|
27
|
+
abiFn extends AbiFunction,
|
28
|
+
TAbi extends Abi = Abi,
|
29
|
+
>(method: string) {
|
30
|
+
return async (contract: ThirdwebContract<TAbi>) => {
|
31
|
+
if (typeof method === "string" && method.startsWith("function ")) {
|
32
|
+
// we know it will be an abi function so we can cast it
|
33
|
+
return parseAbiItem(method) as AbiFunction;
|
34
|
+
}
|
35
|
+
|
36
|
+
const resolvedAbi = contract.abi?.length
|
37
|
+
? contract.abi
|
38
|
+
: await resolveContractAbi<Abi>(contract);
|
28
39
|
// we try to find the abiFunction in the abi
|
29
40
|
const abiFunction = resolvedAbi.find((item) => {
|
30
41
|
// if the item is not a function we can ignore it
|
@@ -75,7 +75,7 @@ async function fetchAndParseCompilerMetadata(
|
|
75
75
|
|
76
76
|
// types
|
77
77
|
|
78
|
-
type RawCompilerMetadata = {
|
78
|
+
export type RawCompilerMetadata = {
|
79
79
|
name: string;
|
80
80
|
metadataUri: string;
|
81
81
|
bytecodeUri: string;
|
@@ -130,9 +130,10 @@ type ParsedCompilerMetadata = {
|
|
130
130
|
};
|
131
131
|
|
132
132
|
export type CompilerMetadata = Prettify<
|
133
|
-
|
134
|
-
|
135
|
-
|
133
|
+
RawCompilerMetadata &
|
134
|
+
ParsedCompilerMetadata & {
|
135
|
+
bytecode: Hex;
|
136
|
+
}
|
136
137
|
>;
|
137
138
|
|
138
139
|
export type ExtendedMetadata = {
|
@@ -195,5 +196,18 @@ export type ExtendedMetadata = {
|
|
195
196
|
}
|
196
197
|
>;
|
197
198
|
compositeAbi?: Abi;
|
199
|
+
compilers?: Record<
|
200
|
+
"solc" | "zksolc",
|
201
|
+
{
|
202
|
+
evmVersion: string;
|
203
|
+
compilerVersion: string;
|
204
|
+
metadataUri: string;
|
205
|
+
bytecodeUri: string;
|
206
|
+
}[]
|
207
|
+
>;
|
208
|
+
externalLinks?: Array<{
|
209
|
+
name: string;
|
210
|
+
url: string;
|
211
|
+
}>;
|
198
212
|
[key: string]: unknown;
|
199
213
|
};
|
@@ -0,0 +1,23 @@
|
|
1
|
+
/**
|
2
|
+
* @internal
|
3
|
+
*/
|
4
|
+
export function hasDuplicates<T>(
|
5
|
+
arr: T[],
|
6
|
+
fn: (a: T | undefined, b: T | undefined) => boolean,
|
7
|
+
): boolean {
|
8
|
+
if (arr.length === 0 || arr.length === 1) {
|
9
|
+
return false;
|
10
|
+
}
|
11
|
+
if (!fn) {
|
12
|
+
throw new Error("Comparison function required");
|
13
|
+
}
|
14
|
+
|
15
|
+
for (let i = 0; i < arr.length; i++) {
|
16
|
+
for (let j = i + 1; j < arr.length; j++) {
|
17
|
+
if (fn(arr[i], arr[j])) {
|
18
|
+
return true;
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
22
|
+
return false;
|
23
|
+
}
|
@@ -0,0 +1,76 @@
|
|
1
|
+
const MAX_LENGTH = 256;
|
2
|
+
const NUMERIC_IDENTIFIER = "0|[1-9]\\d*";
|
3
|
+
const MAIN_VERSION_IDENTIFIER = `(${NUMERIC_IDENTIFIER})\\.(${NUMERIC_IDENTIFIER})\\.(${NUMERIC_IDENTIFIER})`;
|
4
|
+
const REGEX_MAIN_VERSION = new RegExp(MAIN_VERSION_IDENTIFIER);
|
5
|
+
|
6
|
+
/**
|
7
|
+
* @internal
|
8
|
+
*/
|
9
|
+
export type Semver = {
|
10
|
+
major: number;
|
11
|
+
minor: number;
|
12
|
+
patch: number;
|
13
|
+
versionString: string;
|
14
|
+
};
|
15
|
+
|
16
|
+
/**
|
17
|
+
* @internal
|
18
|
+
* @param version - The version to convert to a Semver
|
19
|
+
*/
|
20
|
+
export function toSemver(version: string): Semver {
|
21
|
+
if (version.length > MAX_LENGTH) {
|
22
|
+
throw new Error(`version is longer than ${MAX_LENGTH} characters`);
|
23
|
+
}
|
24
|
+
const matches = version.trim().match(REGEX_MAIN_VERSION);
|
25
|
+
if (!matches || matches?.length !== 4) {
|
26
|
+
throw new Error(
|
27
|
+
`${version} is not a valid semantic version. Should be in the format of major.minor.patch. Ex: 0.4.1`,
|
28
|
+
);
|
29
|
+
}
|
30
|
+
const major = Number(matches[1]);
|
31
|
+
const minor = Number(matches[2]);
|
32
|
+
const patch = Number(matches[3]);
|
33
|
+
const versionString = [major, minor, patch].join(".");
|
34
|
+
return {
|
35
|
+
major,
|
36
|
+
minor,
|
37
|
+
patch,
|
38
|
+
versionString,
|
39
|
+
};
|
40
|
+
}
|
41
|
+
|
42
|
+
/**
|
43
|
+
* @internal
|
44
|
+
* @param current - The current version
|
45
|
+
* @param next - The next version
|
46
|
+
*/
|
47
|
+
export function isIncrementalVersion(current: string, next: string) {
|
48
|
+
const currentSemver = toSemver(current);
|
49
|
+
const nextSemver = toSemver(next);
|
50
|
+
if (nextSemver.major > currentSemver.major) {
|
51
|
+
return true;
|
52
|
+
}
|
53
|
+
const eqMajor = nextSemver.major === currentSemver.major;
|
54
|
+
if (eqMajor && nextSemver.minor > currentSemver.minor) {
|
55
|
+
return true;
|
56
|
+
}
|
57
|
+
const eqMinor = nextSemver.minor === currentSemver.minor;
|
58
|
+
return eqMajor && eqMinor && nextSemver.patch > currentSemver.patch;
|
59
|
+
}
|
60
|
+
|
61
|
+
/**
|
62
|
+
* @internal
|
63
|
+
*/
|
64
|
+
export function isDowngradeVersion(current: string, next: string) {
|
65
|
+
const currentSemver = toSemver(current);
|
66
|
+
const nextSemver = toSemver(next);
|
67
|
+
if (nextSemver.major < currentSemver.major) {
|
68
|
+
return true;
|
69
|
+
}
|
70
|
+
const eqMajor = nextSemver.major === currentSemver.major;
|
71
|
+
if (eqMajor && nextSemver.minor < currentSemver.minor) {
|
72
|
+
return true;
|
73
|
+
}
|
74
|
+
const eqMinor = nextSemver.minor === currentSemver.minor;
|
75
|
+
return eqMajor && eqMinor && nextSemver.patch < currentSemver.patch;
|
76
|
+
}
|