thirdweb 5.46.2-nightly-d3f43a757bf14b3329f1d0e413ee71f8f98e963a-20240816000358 → 5.47.0-nightly-f0d6e343eea28cd49863ba4794b89d6b070c52b2-20240818000714

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.
Files changed (124) hide show
  1. package/dist/cjs/auth/verify-hash.js +24 -0
  2. package/dist/cjs/auth/verify-hash.js.map +1 -1
  3. package/dist/cjs/exports/extensions/erc20.js +5 -1
  4. package/dist/cjs/exports/extensions/erc20.js.map +1 -1
  5. package/dist/cjs/exports/extensions/thirdweb.js +45 -0
  6. package/dist/cjs/exports/extensions/thirdweb.js.map +1 -0
  7. package/dist/cjs/exports/extensions/vote.js +14 -1
  8. package/dist/cjs/exports/extensions/vote.js.map +1 -1
  9. package/dist/cjs/exports/react.js +6 -1
  10. package/dist/cjs/exports/react.js.map +1 -1
  11. package/dist/cjs/extensions/prebuilts/deploy-split.js +1 -0
  12. package/dist/cjs/extensions/prebuilts/deploy-split.js.map +1 -1
  13. package/dist/cjs/extensions/vote/read/canExecute.js +28 -0
  14. package/dist/cjs/extensions/vote/read/canExecute.js.map +1 -0
  15. package/dist/cjs/extensions/vote/read/getAll.js +52 -0
  16. package/dist/cjs/extensions/vote/read/getAll.js.map +1 -0
  17. package/dist/cjs/extensions/vote/read/getProposalVoteCounts.js +32 -0
  18. package/dist/cjs/extensions/vote/read/getProposalVoteCounts.js.map +1 -0
  19. package/dist/cjs/extensions/vote/read/proposalExists.js +28 -0
  20. package/dist/cjs/extensions/vote/read/proposalExists.js.map +1 -0
  21. package/dist/cjs/extensions/vote/types.js +21 -0
  22. package/dist/cjs/extensions/vote/types.js.map +1 -0
  23. package/dist/cjs/extensions/vote/write/executeProposal.js +56 -0
  24. package/dist/cjs/extensions/vote/write/executeProposal.js.map +1 -0
  25. package/dist/cjs/react/core/utils/wallet.js +2 -2
  26. package/dist/cjs/react/core/utils/wallet.js.map +1 -1
  27. package/dist/cjs/react/web/ui/ConnectWallet/Blobbie.js +54 -0
  28. package/dist/cjs/react/web/ui/ConnectWallet/Blobbie.js.map +1 -0
  29. package/dist/cjs/react/web/ui/ConnectWallet/ConnectButton.js +8 -8
  30. package/dist/cjs/react/web/ui/ConnectWallet/ConnectButton.js.map +1 -1
  31. package/dist/cjs/react/web/ui/ConnectWallet/Details.js +23 -22
  32. package/dist/cjs/react/web/ui/ConnectWallet/Details.js.map +1 -1
  33. package/dist/cjs/react/web/ui/ConnectWallet/locale/en.js +2 -2
  34. package/dist/cjs/react/web/ui/ConnectWallet/locale/en.js.map +1 -1
  35. package/dist/cjs/react/web/ui/TransactionButton/index.js +1 -1
  36. package/dist/cjs/version.js +1 -1
  37. package/dist/esm/auth/verify-hash.js +24 -0
  38. package/dist/esm/auth/verify-hash.js.map +1 -1
  39. package/dist/esm/exports/extensions/erc20.js +2 -0
  40. package/dist/esm/exports/extensions/erc20.js.map +1 -1
  41. package/dist/esm/exports/extensions/thirdweb.js +28 -0
  42. package/dist/esm/exports/extensions/thirdweb.js.map +1 -0
  43. package/dist/esm/exports/extensions/vote.js +6 -0
  44. package/dist/esm/exports/extensions/vote.js.map +1 -1
  45. package/dist/esm/exports/react.js +4 -0
  46. package/dist/esm/exports/react.js.map +1 -1
  47. package/dist/esm/extensions/prebuilts/deploy-split.js +1 -0
  48. package/dist/esm/extensions/prebuilts/deploy-split.js.map +1 -1
  49. package/dist/esm/extensions/vote/read/canExecute.js +25 -0
  50. package/dist/esm/extensions/vote/read/canExecute.js.map +1 -0
  51. package/dist/esm/extensions/vote/read/getAll.js +49 -0
  52. package/dist/esm/extensions/vote/read/getAll.js.map +1 -0
  53. package/dist/esm/extensions/vote/read/getProposalVoteCounts.js +29 -0
  54. package/dist/esm/extensions/vote/read/getProposalVoteCounts.js.map +1 -0
  55. package/dist/esm/extensions/vote/read/proposalExists.js +25 -0
  56. package/dist/esm/extensions/vote/read/proposalExists.js.map +1 -0
  57. package/dist/esm/extensions/vote/types.js +18 -0
  58. package/dist/esm/extensions/vote/types.js.map +1 -0
  59. package/dist/esm/extensions/vote/write/executeProposal.js +52 -0
  60. package/dist/esm/extensions/vote/write/executeProposal.js.map +1 -0
  61. package/dist/esm/react/core/utils/wallet.js +2 -2
  62. package/dist/esm/react/core/utils/wallet.js.map +1 -1
  63. package/dist/esm/react/web/ui/ConnectWallet/Blobbie.js +51 -0
  64. package/dist/esm/react/web/ui/ConnectWallet/Blobbie.js.map +1 -0
  65. package/dist/esm/react/web/ui/ConnectWallet/ConnectButton.js +8 -8
  66. package/dist/esm/react/web/ui/ConnectWallet/ConnectButton.js.map +1 -1
  67. package/dist/esm/react/web/ui/ConnectWallet/Details.js +24 -23
  68. package/dist/esm/react/web/ui/ConnectWallet/Details.js.map +1 -1
  69. package/dist/esm/react/web/ui/ConnectWallet/locale/en.js +2 -2
  70. package/dist/esm/react/web/ui/ConnectWallet/locale/en.js.map +1 -1
  71. package/dist/esm/react/web/ui/TransactionButton/index.js +1 -1
  72. package/dist/esm/version.js +1 -1
  73. package/dist/types/auth/verify-hash.d.ts.map +1 -1
  74. package/dist/types/exports/extensions/erc20.d.ts +2 -0
  75. package/dist/types/exports/extensions/erc20.d.ts.map +1 -1
  76. package/dist/types/exports/extensions/thirdweb.d.ts +15 -0
  77. package/dist/types/exports/extensions/thirdweb.d.ts.map +1 -0
  78. package/dist/types/exports/extensions/vote.d.ts +6 -0
  79. package/dist/types/exports/extensions/vote.d.ts.map +1 -1
  80. package/dist/types/exports/react.d.ts +4 -0
  81. package/dist/types/exports/react.d.ts.map +1 -1
  82. package/dist/types/extensions/prebuilts/deploy-split.d.ts +2 -1
  83. package/dist/types/extensions/prebuilts/deploy-split.d.ts.map +1 -1
  84. package/dist/types/extensions/vote/read/canExecute.d.ts +17 -0
  85. package/dist/types/extensions/vote/read/canExecute.d.ts.map +1 -0
  86. package/dist/types/extensions/vote/read/getAll.d.ts +64 -0
  87. package/dist/types/extensions/vote/read/getAll.d.ts.map +1 -0
  88. package/dist/types/extensions/vote/read/getProposalVoteCounts.d.ts +27 -0
  89. package/dist/types/extensions/vote/read/getProposalVoteCounts.d.ts.map +1 -0
  90. package/dist/types/extensions/vote/read/proposalExists.d.ts +17 -0
  91. package/dist/types/extensions/vote/read/proposalExists.d.ts.map +1 -0
  92. package/dist/types/extensions/vote/types.d.ts +16 -0
  93. package/dist/types/extensions/vote/types.d.ts.map +1 -0
  94. package/dist/types/extensions/vote/write/executeProposal.d.ts +25 -0
  95. package/dist/types/extensions/vote/write/executeProposal.d.ts.map +1 -0
  96. package/dist/types/react/core/utils/wallet.d.ts.map +1 -1
  97. package/dist/types/react/web/ui/ConnectWallet/Blobbie.d.ts +12 -0
  98. package/dist/types/react/web/ui/ConnectWallet/Blobbie.d.ts.map +1 -0
  99. package/dist/types/react/web/ui/ConnectWallet/Details.d.ts.map +1 -1
  100. package/dist/types/version.d.ts +1 -1
  101. package/package.json +1 -1
  102. package/src/auth/verify-hash.ts +33 -0
  103. package/src/exports/extensions/erc20.ts +8 -0
  104. package/src/exports/extensions/thirdweb.ts +75 -0
  105. package/src/exports/extensions/vote.ts +14 -0
  106. package/src/exports/react.ts +5 -0
  107. package/src/extensions/prebuilts/deploy-split.ts +2 -1
  108. package/src/extensions/split/read/getAllRecipientsAddresses.test.ts +2 -0
  109. package/src/extensions/split/read/getAllRecipientsPercentages.test.ts +2 -0
  110. package/src/extensions/split/read/getRecipientSplitPercentage.test.ts +2 -0
  111. package/src/extensions/vote/read/canExecute.ts +27 -0
  112. package/src/extensions/vote/read/getAll.ts +106 -0
  113. package/src/extensions/vote/read/getProposalVoteCounts.ts +39 -0
  114. package/src/extensions/vote/read/proposalExists.ts +27 -0
  115. package/src/extensions/vote/types.ts +16 -0
  116. package/src/extensions/vote/write/executeProposal.ts +63 -0
  117. package/src/react/core/utils/wallet.ts +2 -2
  118. package/src/react/web/ui/ConnectWallet/Blobbie.tsx +134 -0
  119. package/src/react/web/ui/ConnectWallet/ConnectButton.tsx +8 -8
  120. package/src/react/web/ui/ConnectWallet/Details.tsx +54 -44
  121. package/src/react/web/ui/ConnectWallet/locale/en.ts +2 -2
  122. package/src/react/web/ui/TransactionButton/index.tsx +1 -1
  123. package/src/version.ts +1 -1
  124. package/src/wallets/smart/smart-wallet-zksync.test.ts +28 -1
@@ -8,6 +8,8 @@ import {
8
8
  } from "viem";
9
9
  import type { Chain } from "../chains/types.js";
10
10
  import type { ThirdwebClient } from "../client/client.js";
11
+ import { type ThirdwebContract, getContract } from "../contract/contract.js";
12
+ import { isValidSignature } from "../extensions/erc1271/__generated__/isValidSignature/read/isValidSignature.js";
11
13
  import { eth_call } from "../rpc/actions/eth_call.js";
12
14
  import { getRpcClient } from "../rpc/rpc.js";
13
15
  import { fromBytes } from "../utils/encoding/from-bytes.js";
@@ -110,8 +112,39 @@ export async function verifyHash({
110
112
  const hexResult = isHex(result) ? toBytes(result) : result;
111
113
  return equalBytes(hexResult, toBytes("0x1"));
112
114
  } catch (error) {
115
+ // Some chains do not support the eth_call simulation and will fail, so we fall back to regular EIP1271 validation
116
+ const validEip1271 = await verifyEip1271Signature({
117
+ hash,
118
+ signature: signatureHex,
119
+ contract: getContract({
120
+ chain,
121
+ address,
122
+ client,
123
+ }),
124
+ }).catch(() => false);
125
+ if (validEip1271) {
126
+ return true;
127
+ }
113
128
  // TODO: Improve overall RPC error handling so we can tell if this was an actual verification failure or some other error
114
129
  // Verification failed somehow
115
130
  return false;
116
131
  }
117
132
  }
133
+
134
+ const EIP_1271_MAGIC_VALUE = "0x1626ba7e";
135
+ async function verifyEip1271Signature({
136
+ hash,
137
+ signature,
138
+ contract,
139
+ }: {
140
+ hash: Hex;
141
+ signature: Hex;
142
+ contract: ThirdwebContract;
143
+ }): Promise<boolean> {
144
+ const result = await isValidSignature({
145
+ hash,
146
+ signature,
147
+ contract,
148
+ });
149
+ return result === EIP_1271_MAGIC_VALUE;
150
+ }
@@ -10,6 +10,10 @@ export {
10
10
  type BalanceOfParams,
11
11
  } from "../../extensions/erc20/__generated__/IERC20/read/balanceOf.js";
12
12
  export { decimals } from "../../extensions/erc20/read/decimals.js";
13
+ export {
14
+ delegates,
15
+ type DelegatesParams,
16
+ } from "../../extensions/erc20/__generated__/IVotes/read/delegates.js";
13
17
  export { totalSupply } from "../../extensions/erc20/__generated__/IERC20/read/totalSupply.js";
14
18
  export {
15
19
  allowance,
@@ -113,3 +117,7 @@ export {
113
117
  getApprovalForTransaction,
114
118
  type GetApprovalForTransactionParams,
115
119
  } from "../../extensions/erc20/write/getApprovalForTransaction.js";
120
+ export {
121
+ delegate,
122
+ type DelegateParams,
123
+ } from "../../extensions/erc20/__generated__/IVotes/write/delegate.js";
@@ -0,0 +1,75 @@
1
+ // --------------------------------------------------------
2
+ // Publisher contract
3
+ // --------------------------------------------------------
4
+
5
+ // Read
6
+ export {
7
+ getPublisherProfileUri,
8
+ type GetPublisherProfileUriParams,
9
+ } from "../../extensions/thirdweb/__generated__/IContractPublisher/read/getPublisherProfileUri.js";
10
+ export {
11
+ getPublishedUriFromCompilerUri,
12
+ type GetPublishedUriFromCompilerUriParams,
13
+ } from "../../extensions/thirdweb/__generated__/IContractPublisher/read/getPublishedUriFromCompilerUri.js";
14
+ export {
15
+ getAllPublishedContracts,
16
+ type GetAllPublishedContractsParams,
17
+ } from "../../extensions/thirdweb/__generated__/IContractPublisher/read/getAllPublishedContracts.js";
18
+ export {
19
+ getPublishedContract,
20
+ type GetPublishedContractParams,
21
+ } from "../../extensions/thirdweb/__generated__/IContractPublisher/read/getPublishedContract.js";
22
+ export {
23
+ getPublishedContractVersions,
24
+ type GetPublishedContractVersionsParams,
25
+ } from "../../extensions/thirdweb/__generated__/IContractPublisher/read/getPublishedContractVersions.js";
26
+
27
+ // Write
28
+ export {
29
+ publishContract,
30
+ type PublishContractParams,
31
+ } from "../../extensions/thirdweb/__generated__/IContractPublisher/write/publishContract.js";
32
+ export {
33
+ setPublisherProfileUri,
34
+ type SetPublisherProfileUriParams,
35
+ } from "../../extensions/thirdweb/__generated__/IContractPublisher/write/setPublisherProfileUri.js";
36
+ export {
37
+ unpublishContract,
38
+ type UnpublishContractParams,
39
+ } from "../../extensions/thirdweb/__generated__/IContractPublisher/write/unpublishContract.js";
40
+
41
+ // --------------------------------------------------------
42
+ // Multichain Registry
43
+ // --------------------------------------------------------
44
+
45
+ // Read
46
+ export {
47
+ count,
48
+ type CountParams,
49
+ } from "../../extensions/thirdweb/__generated__/ITWMultichainRegistry/read/count.js";
50
+ export {
51
+ getAll,
52
+ type GetAllParams,
53
+ } from "../../extensions/thirdweb/__generated__/ITWMultichainRegistry/read/getAll.js";
54
+ export {
55
+ getMetadataUri,
56
+ type GetMetadataUriParams,
57
+ } from "../../extensions/thirdweb/__generated__/ITWMultichainRegistry/read/getMetadataUri.js";
58
+
59
+ // Write
60
+ export {
61
+ add,
62
+ type AddParams,
63
+ } from "../../extensions/thirdweb/__generated__/ITWMultichainRegistry/write/add.js";
64
+ export {
65
+ remove,
66
+ type RemoveParams,
67
+ } from "../../extensions/thirdweb/__generated__/ITWMultichainRegistry/write/remove.js";
68
+
69
+ // --------------------------------------------------------
70
+ // Contract Factory
71
+ // --------------------------------------------------------
72
+ export {
73
+ deployProxyByImplementation,
74
+ type DeployProxyByImplementationParams,
75
+ } from "../../extensions/thirdweb/__generated__/IContractFactory/write/deployProxyByImplementation.js";
@@ -67,6 +67,19 @@ export { votingDelay } from "../../extensions/vote/__generated__/Vote/read/votin
67
67
 
68
68
  export { votingPeriod } from "../../extensions/vote/__generated__/Vote/read/votingPeriod.js";
69
69
 
70
+ export { proposalExists } from "../../extensions/vote/read/proposalExists.js";
71
+
72
+ export { VoteType, ProposalState } from "../../extensions/vote/types.js";
73
+
74
+ export { getProposalVoteCounts } from "../../extensions/vote/read/getProposalVoteCounts.js";
75
+
76
+ export {
77
+ getAll,
78
+ type ProposalItem,
79
+ } from "../../extensions/vote/read/getAll.js";
80
+
81
+ export { canExecute } from "../../extensions/vote/read/canExecute.js";
82
+
70
83
  /**
71
84
  * WRITE Methods
72
85
  */
@@ -129,3 +142,4 @@ export {
129
142
  updateQuorumNumerator,
130
143
  type UpdateQuorumNumeratorParams,
131
144
  } from "../../extensions/vote/__generated__/Vote/write/updateQuorumNumerator.js";
145
+ export { executeProposal } from "../../extensions/vote/write/executeProposal.js";
@@ -172,3 +172,8 @@ export {
172
172
  } from "../react/web/ui/prebuilt/thirdweb/CreateDirectListingButton/index.js";
173
173
 
174
174
  export { useConnectionManager } from "../react/core/providers/connection-manager.js";
175
+
176
+ /**
177
+ * Blobbie
178
+ */
179
+ export { Blobbie } from "../react/web/ui/ConnectWallet/Blobbie.js";
@@ -9,7 +9,7 @@ import type { ClientAndChainAndAccount } from "../../utils/types.js";
9
9
  import { initialize } from "./__generated__/Split/write/initialize.js";
10
10
 
11
11
  /**
12
- * @extension PREBUILT
12
+ * @extension DEPLOY
13
13
  */
14
14
  export type SplitContractParams = {
15
15
  name: string;
@@ -71,6 +71,7 @@ export type DeploySplitContractOptions = Prettify<
71
71
  * name: "Split contract",
72
72
  * payees: ["0x...123", "0x...456"],
73
73
  * shares: [5100, 4900], // See type `SplitContractParams` for more context
74
+ * },
74
75
  * });
75
76
  * ```
76
77
  */
@@ -1,5 +1,6 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { ANVIL_CHAIN } from "~test/chains.js";
3
+ import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
3
4
  import { TEST_CLIENT } from "~test/test-clients.js";
4
5
  import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
5
6
  import { getContract } from "../../../contract/contract.js";
@@ -21,6 +22,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("getAllRecipientsAddresses", () => {
21
22
  chain: ANVIL_CHAIN,
22
23
  params: {
23
24
  name: "split-contract",
25
+ contractURI: TEST_CONTRACT_URI, // just to speed up the test
24
26
  payees,
25
27
  shares: [
26
28
  5100n, // 51%
@@ -1,5 +1,6 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { ANVIL_CHAIN } from "~test/chains.js";
3
+ import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
3
4
  import { TEST_CLIENT } from "~test/test-clients.js";
4
5
  import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
5
6
  import { getContract } from "../../../contract/contract.js";
@@ -21,6 +22,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("getAllRecipientsPercentages", () => {
21
22
  chain: ANVIL_CHAIN,
22
23
  params: {
23
24
  name: "split-contract",
25
+ contractURI: TEST_CONTRACT_URI, // just to speed up the test
24
26
  payees,
25
27
  shares: [
26
28
  5100n, // 51%
@@ -1,5 +1,6 @@
1
1
  import { describe, expect, it } from "vitest";
2
2
  import { ANVIL_CHAIN } from "~test/chains.js";
3
+ import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
3
4
  import { TEST_CLIENT } from "~test/test-clients.js";
4
5
  import { TEST_ACCOUNT_A } from "~test/test-wallets.js";
5
6
  import { getContract } from "../../../contract/contract.js";
@@ -20,6 +21,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("getRecipientSplitPercentage", () => {
20
21
  chain: ANVIL_CHAIN,
21
22
  params: {
22
23
  name: "split-contract",
24
+ contractURI: TEST_CONTRACT_URI, // just to speed up the test
23
25
  payees,
24
26
  shares: [
25
27
  5100n, // 51%
@@ -0,0 +1,27 @@
1
+ import { simulateTransaction } from "../../../transaction/actions/simulate.js";
2
+ import type { BaseTransactionOptions } from "../../../transaction/types.js";
3
+ import { executeProposal } from "../write/executeProposal.js";
4
+
5
+ /**
6
+ * Simulate the `execute` method of the Vote contract, to check if you can execute a proposal
7
+ * @extension VOTE
8
+ * @returns boolean - `true` if the proposal is executable, else `false`
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * import { canExecute } from "thirdweb/extensions/vote";
13
+ *
14
+ * const executable = await canExecute({ contract, proposalId });
15
+ * ```
16
+ */
17
+ export async function canExecute(
18
+ options: BaseTransactionOptions<{ proposalId: bigint }>,
19
+ ) {
20
+ try {
21
+ const transaction = await executeProposal(options);
22
+ await simulateTransaction({ transaction });
23
+ return true;
24
+ } catch {
25
+ return false;
26
+ }
27
+ }
@@ -0,0 +1,106 @@
1
+ import type { BaseTransactionOptions } from "../../../transaction/types.js";
2
+ import type { Hex } from "../../../utils/encoding/hex.js";
3
+ import { getAllProposals } from "../__generated__/Vote/read/getAllProposals.js";
4
+ import { state } from "../__generated__/Vote/read/state.js";
5
+ import { ProposalState } from "../types.js";
6
+ import {
7
+ type ProposalVoteInfo,
8
+ getProposalVoteCounts,
9
+ } from "./getProposalVoteCounts.js";
10
+
11
+ /**
12
+ * @extension VOTE
13
+ */
14
+ export type ProposalItem = {
15
+ /**
16
+ * ID of the proposal
17
+ */
18
+ proposalId: bigint;
19
+ /**
20
+ * The wallet address of the proposer
21
+ */
22
+ proposer: string;
23
+ /**
24
+ * Description of the proposal
25
+ */
26
+ description: string;
27
+ /**
28
+ * The block number at which the proposal is open for voting
29
+ */
30
+ startBlock: bigint;
31
+ /**
32
+ * The block number where the proposal concludes its voting phase
33
+ */
34
+ endBlock: bigint;
35
+ /**
36
+ * The current state of the proposal, represented in number
37
+ */
38
+ state: number;
39
+ /**
40
+ * The current state of the proposal, represented in a user-friendly string
41
+ * Example: "pending" | "active" | "canceled"
42
+ */
43
+ stateLabel: string | undefined;
44
+ /**
45
+ * The current vote info. See type ProposalVoteInfo for more context
46
+ */
47
+ votes: ProposalVoteInfo;
48
+ /**
49
+ * The array of containing info about the set of actions that will be executed onchain,
50
+ * should the proposal pass
51
+ */
52
+ executions: Array<{
53
+ toAddress: string | undefined;
54
+ nativeTokenValue: bigint | undefined;
55
+ transactionData: Hex | undefined;
56
+ }>;
57
+ };
58
+
59
+ /**
60
+ * Get all proposals from a Vote contract with some extra info attached for each proposal (current state and votes)
61
+ * @extension VOTE
62
+ * @returns An array containing proposals data
63
+ *
64
+ * @example
65
+ * ```ts
66
+ * import { getAll } from "thirdweb/extension/getAll";
67
+ *
68
+ * const allProposals = await getAll({ contract });
69
+ * ```
70
+ */
71
+ export async function getAll(
72
+ options: BaseTransactionOptions,
73
+ ): Promise<ProposalItem[]> {
74
+ const _proposals = await getAllProposals(options);
75
+ const _extraData = await Promise.all(
76
+ _proposals.map((proposal) => {
77
+ const params = {
78
+ contract: options.contract,
79
+ proposalId: proposal.proposalId,
80
+ };
81
+ return Promise.all([state(params), getProposalVoteCounts(params)]);
82
+ }),
83
+ );
84
+ return _extraData.map(([state, votes], index) => {
85
+ const data = _proposals[index];
86
+ // We know `data` SHOULD exist but adding the error-throw below to make typescript happy
87
+ if (!data) {
88
+ throw new Error(`Proposal not found for index: ${index}`);
89
+ }
90
+ return {
91
+ proposalId: data.proposalId,
92
+ proposer: data.proposer,
93
+ description: data.description,
94
+ startBlock: data.startBlock,
95
+ endBlock: data.endBlock,
96
+ state: state,
97
+ stateLabel: ProposalState[state],
98
+ votes: votes,
99
+ executions: data.targets.map((_, index) => ({
100
+ toAddress: data.targets[index],
101
+ nativeTokenValue: data.values[index],
102
+ transactionData: data.calldatas[index],
103
+ })),
104
+ };
105
+ });
106
+ }
@@ -0,0 +1,39 @@
1
+ import type { BaseTransactionOptions } from "../../../transaction/types.js";
2
+ import {
3
+ type ProposalVotesParams,
4
+ proposalVotes,
5
+ } from "../__generated__/Vote/read/proposalVotes.js";
6
+ import type { VoteType } from "../types.js";
7
+
8
+ // @internal
9
+ export type ProposalVoteInfo = { [K in keyof typeof VoteType]: bigint };
10
+
11
+ /**
12
+ * Get the info about Against, For and Abstain votes of a proposal
13
+ * @param options
14
+ * @returns the object containing the info about Against, For and Abstain votes of a proposal
15
+ * @extension VOTE
16
+ * @example
17
+ * ```ts
18
+ * import { getProposalVoteCounts } from "thirdweb/extensions/vote";
19
+ *
20
+ * const data = await getProposalVoteCounts({ contract, proposalId });
21
+ *
22
+ * // Example result
23
+ * {
24
+ * against: 12n, // 12 users voted against the proposal
25
+ * for: 104n, // 104 users support the proposal
26
+ * abstain: 3n, // 3 users voted abstain on this proposal
27
+ * }
28
+ * ```
29
+ */
30
+ export async function getProposalVoteCounts(
31
+ options: BaseTransactionOptions<ProposalVotesParams>,
32
+ ): Promise<ProposalVoteInfo> {
33
+ const votes = await proposalVotes(options);
34
+ return {
35
+ against: votes[0],
36
+ for: votes[1],
37
+ abstain: votes[2],
38
+ };
39
+ }
@@ -0,0 +1,27 @@
1
+ import type { BaseTransactionOptions } from "../../../transaction/types.js";
2
+ import { type StateParams, state } from "../__generated__/Vote/read/state.js";
3
+
4
+ /**
5
+ * Check if a proposal exists based on a given proposalId
6
+ * @returns `true` if the proposal exists, else `false`
7
+ * @extension VOTE
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { proposalExists } from "thirdweb/extensions/vote";
12
+ *
13
+ * // Check if the proposal with proposalId `4` exists
14
+ * const exists = await proposalExists({ contract, proposalId: 4n }); // either `true` or `false`
15
+ * ```
16
+ */
17
+ export async function proposalExists(
18
+ options: BaseTransactionOptions<StateParams>,
19
+ ) {
20
+ try {
21
+ await state(options);
22
+ return true;
23
+ } catch (e) {
24
+ // If it throws an error then the proposal(id) doesn't exist
25
+ return false;
26
+ }
27
+ }
@@ -0,0 +1,16 @@
1
+ export enum VoteType {
2
+ against = 0,
3
+ for = 1,
4
+ abstain = 2,
5
+ }
6
+
7
+ export enum ProposalState {
8
+ pending = 0,
9
+ active = 1,
10
+ canceled = 2,
11
+ defeated = 3,
12
+ succeeded = 4,
13
+ queued = 5,
14
+ expired = 6,
15
+ executed = 7,
16
+ }
@@ -0,0 +1,63 @@
1
+ import type { BaseTransactionOptions } from "../../../transaction/types.js";
2
+ import {
3
+ type ExecuteParams,
4
+ execute,
5
+ } from "../__generated__/Vote/write/execute.js";
6
+ import { proposalExists } from "../read/proposalExists.js";
7
+
8
+ /**
9
+ * Execute a Proposal
10
+ * @extension VOTE
11
+ * @returns a prepared transaction for the `execute` method
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * import { executeProposal } from "thirdweb/extensions/vote";
16
+ *
17
+ * const transaction = executeProposal({ contract, proposalId });
18
+ * const tx = await sendTransaction({ transaction, account });
19
+ * ```
20
+ */
21
+ export function executeProposal(
22
+ options: BaseTransactionOptions<{ proposalId: bigint }>,
23
+ ) {
24
+ return execute({
25
+ contract: options.contract,
26
+ asyncParams: async () => getExecuteParams(options),
27
+ });
28
+ }
29
+
30
+ /**
31
+ * @internal
32
+ */
33
+ export async function getExecuteParams(
34
+ options: BaseTransactionOptions<{ proposalId: bigint }>,
35
+ ): Promise<ExecuteParams> {
36
+ const { proposalId } = options;
37
+ const exists = await proposalExists(options);
38
+ if (!exists) {
39
+ throw new Error(`Proposal ID: ${proposalId} does not exists`);
40
+ }
41
+ const [{ getAllProposals }, { keccak256 }, { stringToBytes }] =
42
+ await Promise.all([
43
+ import("../__generated__/Vote/read/getAllProposals.js"),
44
+ import("../../../utils/hashing/keccak256.js"),
45
+ import("../../../utils/encoding/to-bytes.js"),
46
+ import("../__generated__/Vote/write/execute.js"),
47
+ ]);
48
+
49
+ // Sadly there isn't a way to fetch a single proposal so we have to load them all
50
+ const _proposals = await getAllProposals(options);
51
+ const proposal = _proposals.find((p) => p.proposalId === proposalId);
52
+ if (!proposal) {
53
+ throw new Error(`Could not find proposalId: ${proposalId}`);
54
+ }
55
+ const { targets, values, calldatas, description } = proposal;
56
+ const descriptionHash = keccak256(stringToBytes(description));
57
+ return {
58
+ descriptionHash,
59
+ targets,
60
+ values,
61
+ calldatas,
62
+ };
63
+ }
@@ -4,12 +4,12 @@ import type { Chain } from "../../../chains/types.js";
4
4
  import type { ThirdwebClient } from "../../../client/client.js";
5
5
  import { resolveAvatar } from "../../../extensions/ens/resolve-avatar.js";
6
6
  import { resolveName } from "../../../extensions/ens/resolve-name.js";
7
+ import { shortenAddress } from "../../../utils/address.js";
7
8
  import { getWalletInfo } from "../../../wallets/__generated__/getWalletInfo.js";
8
9
  import type { Account, Wallet } from "../../../wallets/interfaces/wallet.js";
9
10
  import type { WalletInfo } from "../../../wallets/wallet-info.js";
10
11
  import type { WalletId } from "../../../wallets/wallet-types.js";
11
12
  import { useWalletBalance } from "../hooks/others/useWalletBalance.js";
12
- import { shortenString } from "./addresses.js";
13
13
 
14
14
  /**
15
15
  * Get the ENS name and avatar for an address
@@ -99,7 +99,7 @@ export function useConnectedWalletDetails(
99
99
  });
100
100
 
101
101
  const shortAddress = activeAccount?.address
102
- ? shortenString(activeAccount.address, false)
102
+ ? shortenAddress(activeAccount.address, 4)
103
103
  : "";
104
104
 
105
105
  const balanceQuery = useWalletBalance({
@@ -0,0 +1,134 @@
1
+ "use client";
2
+ import { hexToNumber } from "@noble/curves/abstract/utils";
3
+ import { useId, useMemo } from "react";
4
+ import { type Address, numberToHex } from "viem";
5
+
6
+ // Distance between 2 colors (in RGB)
7
+ type Color = [number, number, number];
8
+ function hexToRgb(hex: string) {
9
+ return [
10
+ Number(hexToNumber(hex.slice(0, 2))),
11
+ Number(hexToNumber(hex.slice(2, 4))),
12
+ Number(hexToNumber(hex.slice(4, 6))),
13
+ ] satisfies [number, number, number];
14
+ }
15
+
16
+ /**
17
+ * A unique gradient avatar based on the provided address.
18
+ * @param props The component props.
19
+ * @param props.address The address to generate the gradient with.
20
+ * @param props.size The size of each side of the square avatar (in pixels)
21
+ */
22
+ export function Blobbie(props: { address: Address; size: number }) {
23
+ const id = useId();
24
+ const colors: [string, string, string] = useMemo(() => {
25
+ const color = props.address.slice(2, 8);
26
+ const rgb = hexToRgb(color);
27
+
28
+ // To get well-paired colors, we use the first rgb hex sequence as our main color then find its two best pairs (split color wheel into thirds)
29
+ // To prevent extremely dark colors, which tend to clash, we don't allow values less than 55
30
+ const pairing1 = rgb.map((n) => (n + 85 > 255 ? n + 85 - 200 : n + 85));
31
+ const pairing2 = rgb.map((n) => (n - 85 < 55 ? n - 85 + 200 : n - 85));
32
+ return [
33
+ color,
34
+ pairing1.map((n) => numberToHex(n).replace("0x", "")).join(""),
35
+ pairing2.map((n) => numberToHex(n).replace("0x", "")).join(""),
36
+ ];
37
+ }, [props.address]);
38
+
39
+ const positions: [Color, Color, Color, Color, Color] = useMemo(() => {
40
+ const _positions: Color[] = [];
41
+ let i = 8;
42
+ while (i < 44) {
43
+ const values = hexToRgb(props.address.slice(i, i + 6));
44
+ _positions.push(values);
45
+ i += 6;
46
+ }
47
+ return _positions as [Color, Color, Color, Color, Color];
48
+ }, [props.address]);
49
+
50
+ console.log(colors);
51
+
52
+ return (
53
+ <svg
54
+ height={`${props.size}px`}
55
+ style={{ background: "#FFFFFF" }}
56
+ width={`${props.size}px`}
57
+ role="presentation"
58
+ viewBox="0 0 500 500"
59
+ xmlns="http://www.w3.org/2000/svg"
60
+ >
61
+ <defs>
62
+ {colors.map((color, idx) => {
63
+ return (
64
+ <radialGradient
65
+ id={`${id}_grad${idx + 1}`}
66
+ cx="50%"
67
+ cy="50%"
68
+ r="50%"
69
+ key={`grad${
70
+ // biome-ignore lint/suspicious/noArrayIndexKey: Jonas said so
71
+ idx
72
+ }`}
73
+ >
74
+ <stop
75
+ offset="0%"
76
+ style={{ stopColor: `#${color}`, stopOpacity: 0.9 }}
77
+ />
78
+ <stop
79
+ offset="100%"
80
+ style={{ stopColor: `#${color}`, stopOpacity: 0 }}
81
+ />
82
+ </radialGradient>
83
+ );
84
+ })}
85
+ </defs>
86
+
87
+ <ellipse
88
+ cx="250"
89
+ cy="250"
90
+ rx="500"
91
+ ry="500"
92
+ fill={`url(#${id}_grad1)`}
93
+ opacity={0.5}
94
+ />
95
+ <ellipse
96
+ cx={400 + positions[0][0]}
97
+ cy={400 + positions[0][1]}
98
+ rx={350 + positions[0][2]}
99
+ ry={350 + positions[0][2]}
100
+ fill={`url(#${id}_grad1)`}
101
+ />
102
+ <ellipse
103
+ cx={positions[1][0]}
104
+ cy={positions[1][1]}
105
+ rx={350 + positions[1][2]}
106
+ ry={350 + positions[1][2]}
107
+ fill={`url(#${id}_grad2)`}
108
+ />
109
+ <ellipse
110
+ cx={400 + positions[2][0]}
111
+ cy={positions[2][1]}
112
+ rx={350 + positions[2][2]}
113
+ ry={350 + positions[2][2]}
114
+ fill={`url(#${id}_grad3)`}
115
+ />
116
+ <ellipse
117
+ cx={positions[3][0]}
118
+ cy={positions[3][1]}
119
+ rx={100 + positions[3][2]}
120
+ ry={100 + positions[3][2]}
121
+ fill={`url(#${id}_grad2)`}
122
+ opacity={0.5}
123
+ />
124
+ <ellipse
125
+ cx={positions[4][0]}
126
+ cy={positions[4][1]}
127
+ rx={100 + positions[4][2]}
128
+ ry={100 + positions[4][2]}
129
+ fill={`url(#${id}_grad3)`}
130
+ opacity={0.5}
131
+ />
132
+ </svg>
133
+ );
134
+ }