Compare commits

..
Author SHA1 Message Date
Jonas DanielsGitHubgithub-actions[bot] <github-actions[bot]@users.noreply.github.com>
b5bbecd182 Version Packages (#5173)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-10-25 21:26:53 +13:00
Joaquim VergesandGitHub bafa0e83c3 feat: set initial balance for Anvil proxy in tests (#5174) 2024-10-25 20:58:30 +13:00
kien-ngo 5dc1899541 [SDK] Improve Vote contract tests (#5156)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on enhancing validation for the `minVoteQuorumRequiredPercent` parameter in the `deploy-vote.ts` file and updating corresponding tests to ensure correct functionality.

### Detailed summary
- Added validation for `minVoteQuorumRequiredPercent` in `deploy-vote.ts`.
- Included checks for NaN, range (0-100), and integer-like values.
- Updated tests in `deploy-vote.test.ts` to handle new validation logic.
- Adjusted test descriptions and assertions in `vote.test.ts`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-10-25 03:59:18 +00:00
kien-ngo 4b183518af [SDK] Improve Split contract tests (#5155)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on adding tests for the `split` functionality of a smart contract in the `thirdweb` package, ensuring that the contract behaves as expected when deployed and queried for recipient addresses and their share percentages.

### Detailed summary
- Deleted several test files related to `deploy-split` and recipient functions.
- Introduced a new test suite for the `split` contract in `split.test.ts`.
- Added tests for:
  - Deployment of the split contract.
  - Retrieving all recipient addresses.
  - Retrieving all recipients and their share percentages.
  - Retrieving the split percentage for an individual recipient.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-10-25 03:59:17 +00:00
joaquim-verges e8f952a191 feat: always add URI to SIWE payload (#5172)
## Problem solved

Short description of the bug fixed or feature added

<!-- start pr-codex -->

---

## PR-Codex overview
This PR focuses on ensuring that a URI is always included in the SIWE payload by modifying the logic in the `generate-login-payload.ts` file and updating the corresponding test.

### Detailed summary
- In `generate-login-payload.ts`, the `uri` field is updated to default to `options.domain` if `options.login?.uri` is not provided.
- In `generate-login-payload.test.ts`, the test case for `uri` is changed to use `"example.com"` instead of `undefined`.

> ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}`

<!-- end pr-codex -->
2024-10-25 02:45:35 +00:00
14 changed files with 142 additions and 300 deletions
+6
View File
@@ -1,5 +1,11 @@
# thirdweb
## 5.64.2
### Patch Changes
- [#5172](https://github.com/thirdweb-dev/js/pull/5172) [`e8f952a`](https://github.com/thirdweb-dev/js/commit/e8f952a191d9180926d8d6b4e1317c683fe8a1e3) Thanks [@joaquim-verges](https://github.com/joaquim-verges)! - Always add URI to SIWE payload
## 5.64.1
### Patch Changes
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "thirdweb",
"version": "5.64.1",
"version": "5.64.2",
"repository": {
"type": "git",
"url": "git+https://github.com/thirdweb-dev/js.git#main"
@@ -89,7 +89,7 @@ describe("generateLoginPayload", () => {
"issued_at": "1970-01-01T00:00:00.000Z",
"resources": undefined,
"statement": "Please ensure that the domain above matches the URL of the current website.",
"uri": undefined,
"uri": "example.com",
"version": "1",
}
`);
@@ -46,7 +46,7 @@ export function generateLoginPayload(options: AuthOptions) {
statement: options.login?.statement || DEFAULT_LOGIN_STATEMENT,
version: options.login?.version || DEFAULT_LOGIN_VERSION,
resources: options.login?.resources,
uri: options.login?.uri,
uri: options.login?.uri || options.domain,
};
};
}
@@ -1,31 +0,0 @@
import { describe, expect, it } from "vitest";
import { ANVIL_CHAIN } from "~test/chains.js";
import { TEST_CLIENT } from "~test/test-clients.js";
import { TEST_ACCOUNT_D } from "~test/test-wallets.js";
import { isAddress } from "../../utils/address.js";
import { deploySplitContract } from "./deploy-split.js";
describe.runIf(process.env.TW_SECRET_KEY)("deploy-split contract", () => {
it("should deploy Split contract", async () => {
const address = await deploySplitContract({
account: TEST_ACCOUNT_D,
client: TEST_CLIENT,
chain: ANVIL_CHAIN,
params: {
name: "split-contract",
payees: [
"0x12345674b599ce99958242b3D3741e7b01841DF3",
"0xA6f11e47dE28B3dB934e945daeb6F538E9019694",
],
shares: [
5100n, // 51%
4900n, // 49%
],
},
});
expect(address).toBeDefined();
expect(isAddress(address)).toBe(true);
// Further tests to verify the functionality of this contract
// are done in other Split tests
});
});
@@ -3,57 +3,12 @@ import { ANVIL_CHAIN } from "~test/chains.js";
import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
import { TEST_CLIENT } from "~test/test-clients.js";
import { TEST_ACCOUNT_B } from "~test/test-wallets.js";
import { isAddress } from "../../utils/address.js";
import { deployERC20Contract } from "./deploy-erc20.js";
import { deployVoteContract } from "./deploy-vote.js";
const account = TEST_ACCOUNT_B;
describe.runIf(process.env.TW_SECRET_KEY)("deploy-voteERC20 contract", () => {
it("should deploy Vote contract", async () => {
const tokenAddress = await deployERC20Contract({
client: TEST_CLIENT,
chain: ANVIL_CHAIN,
account,
type: "TokenERC20",
params: {
name: "Token",
contractURI: TEST_CONTRACT_URI,
},
});
const address = await deployVoteContract({
account,
client: TEST_CLIENT,
chain: ANVIL_CHAIN,
params: {
name: "",
contractURI: TEST_CONTRACT_URI,
tokenAddress: tokenAddress,
// user needs 0.5 <token> to create proposal
initialProposalThreshold: "0.5",
// vote expires 10 blocks later
initialVotingPeriod: 10,
// Requires 51% of users who voted, voted "For", for this proposal to pass
minVoteQuorumRequiredPercent: 51,
},
});
expect(address).toBeDefined();
expect(isAddress(address)).toBe(true);
// Further tests to verify the functionality of this contract
// are done in other Vote tests
});
it("should throw if passed an non-integer-like value to minVoteQuorumRequiredPercent", async () => {
const tokenAddress = await deployERC20Contract({
client: TEST_CLIENT,
chain: ANVIL_CHAIN,
account,
type: "TokenERC20",
params: {
name: "Token",
contractURI: TEST_CONTRACT_URI,
},
});
await expect(() =>
deployVoteContract({
account,
@@ -62,7 +17,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("deploy-voteERC20 contract", () => {
params: {
name: "",
contractURI: TEST_CONTRACT_URI,
tokenAddress: tokenAddress,
tokenAddress: "doesnt matter here, code wont be reached",
initialProposalThreshold: "0.5",
initialVotingPeriod: 10,
minVoteQuorumRequiredPercent: 51.12,
@@ -136,6 +136,27 @@ async function getInitializeTransaction(options: {
external_link,
social_urls,
} = params;
// Validate initialVoteQuorumFraction
const _num = Number(minVoteQuorumRequiredPercent);
if (Number.isNaN(_num)) {
throw new Error(
`${minVoteQuorumRequiredPercent} is not a valid minVoteQuorumRequiredPercent`,
);
}
if (_num < 0 || _num > 100) {
throw new Error("minVoteQuorumRequiredPercent must be >= 0 and <= 100");
}
// Make sure if user is passing a float, it should only have 2 digit after the decimal point
if (!Number.isInteger(_num)) {
throw new Error(
`${_num} is an invalid value. Only integer-like values accepted`,
);
}
const initialVoteQuorumFraction = BigInt(_num);
const tokenErc20Contract = getContract({
address: tokenAddress,
client,
@@ -177,26 +198,6 @@ async function getInitializeTransaction(options: {
})) ||
"";
// Validate initialVoteQuorumFraction
const _num = Number(minVoteQuorumRequiredPercent);
if (Number.isNaN(_num)) {
throw new Error(
`${minVoteQuorumRequiredPercent} is not a valid minVoteQuorumRequiredPercent`,
);
}
if (_num < 0 || _num > 100) {
throw new Error("minVoteQuorumRequiredPercent must be >= 0 and <= 100");
}
// Make sure if user is passing a float, it should only have 2 digit after the decimal point
if (!Number.isInteger(_num)) {
throw new Error(
`${_num} is an invalid value. Only integer-like values accepted`,
);
}
const initialVoteQuorumFraction = BigInt(_num);
return initialize({
contract: implementationContract,
name,
@@ -1,41 +0,0 @@
import { describe, expect, it } from "vitest";
import { ANVIL_CHAIN } from "~test/chains.js";
import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
import { TEST_CLIENT } from "~test/test-clients.js";
import { TEST_ACCOUNT_C } from "~test/test-wallets.js";
import { getContract } from "../../../contract/contract.js";
import { deploySplitContract } from "../../../extensions/prebuilts/deploy-split.js";
import { getAllRecipientsAddresses } from "./getAllRecipientsAddresses.js";
const chain = ANVIL_CHAIN;
const client = TEST_CLIENT;
describe.runIf(process.env.TW_SECRET_KEY)("getAllRecipientsAddresses", () => {
it("should work", async () => {
const payees = [
"0x12345674b599ce99958242b3D3741e7b01841DF3",
"0xA6f11e47dE28B3dB934e945daeb6F538E9019694",
];
const address = await deploySplitContract({
account: TEST_ACCOUNT_C,
client: TEST_CLIENT,
chain: ANVIL_CHAIN,
params: {
name: "split-contract",
contractURI: TEST_CONTRACT_URI, // just to speed up the test
payees,
shares: [
5100n, // 51%
4900n, // 49%
],
},
});
const contract = getContract({
address,
chain,
client,
});
const result = await getAllRecipientsAddresses({ contract });
expect(result).toStrictEqual(payees);
});
});
@@ -1,50 +0,0 @@
import { describe, expect, it } from "vitest";
import { ANVIL_CHAIN } from "~test/chains.js";
import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
import { TEST_CLIENT } from "~test/test-clients.js";
import { TEST_ACCOUNT_C } from "~test/test-wallets.js";
import { getContract } from "../../../contract/contract.js";
import { deploySplitContract } from "../../../extensions/prebuilts/deploy-split.js";
import { getAllRecipientsPercentages } from "./getAllRecipientsPercentages.js";
const chain = ANVIL_CHAIN;
const client = TEST_CLIENT;
describe.runIf(process.env.TW_SECRET_KEY)("getAllRecipientsPercentages", () => {
it("should work", async () => {
const payees = [
"0x12345674b599ce99958242b3D3741e7b01841DF3",
"0xA6f11e47dE28B3dB934e945daeb6F538E9019694",
];
const address = await deploySplitContract({
account: TEST_ACCOUNT_C,
client: TEST_CLIENT,
chain: ANVIL_CHAIN,
params: {
name: "split-contract",
contractURI: TEST_CONTRACT_URI, // just to speed up the test
payees,
shares: [
5100n, // 51%
4900n, // 49%
],
},
});
const contract = getContract({
address,
chain,
client,
});
const result = await getAllRecipientsPercentages({ contract });
expect(result).toStrictEqual([
{
address: "0x12345674b599ce99958242b3D3741e7b01841DF3",
splitPercentage: 51,
},
{
address: "0xA6f11e47dE28B3dB934e945daeb6F538E9019694",
splitPercentage: 49,
},
]);
});
});
@@ -1,49 +0,0 @@
import { describe, expect, it } from "vitest";
import { ANVIL_CHAIN } from "~test/chains.js";
import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
import { TEST_CLIENT } from "~test/test-clients.js";
import { TEST_ACCOUNT_C } from "~test/test-wallets.js";
import { getContract } from "../../../contract/contract.js";
import { deploySplitContract } from "../../../extensions/prebuilts/deploy-split.js";
import { getRecipientSplitPercentage } from "./getRecipientSplitPercentage.js";
const chain = ANVIL_CHAIN;
const client = TEST_CLIENT;
const account = TEST_ACCOUNT_C;
describe.runIf(process.env.TW_SECRET_KEY)("getRecipientSplitPercentage", () => {
it("should work", async () => {
const payees = [
"0x12345674b599ce99958242b3D3741e7b01841DF3",
"0xA6f11e47dE28B3dB934e945daeb6F538E9019694",
];
const address = await deploySplitContract({
account,
client: TEST_CLIENT,
chain: ANVIL_CHAIN,
params: {
name: "split-contract",
contractURI: TEST_CONTRACT_URI, // just to speed up the test
payees,
shares: [
5100n, // 51%
4900n, // 49%
],
},
});
const contract = getContract({
address,
chain,
client,
});
const result = await getRecipientSplitPercentage({
contract,
recipientAddress: "0x12345674b599ce99958242b3D3741e7b01841DF3",
});
expect(result).toStrictEqual({
address: "0x12345674b599ce99958242b3D3741e7b01841DF3",
splitPercentage: 51,
});
});
});
@@ -0,0 +1,76 @@
import { beforeAll, describe, expect, it } from "vitest";
import { ANVIL_CHAIN } from "~test/chains.js";
import { TEST_CLIENT } from "~test/test-clients.js";
import { TEST_ACCOUNT_D } from "~test/test-wallets.js";
import { type ThirdwebContract, getContract } from "../../contract/contract.js";
import { isAddress } from "../../utils/address.js";
import { deploySplitContract } from "../prebuilts/deploy-split.js";
import { getAllRecipientsAddresses } from "./read/getAllRecipientsAddresses.js";
import { getAllRecipientsPercentages } from "./read/getAllRecipientsPercentages.js";
import { getRecipientSplitPercentage } from "./read/getRecipientSplitPercentage.js";
let contract: ThirdwebContract;
const chain = ANVIL_CHAIN;
const client = TEST_CLIENT;
describe.runIf(process.env.TW_SECRET_KEY)("Split contract tests", () => {
beforeAll(async () => {
const address = await deploySplitContract({
account: TEST_ACCOUNT_D,
client,
chain,
params: {
name: "split-contract",
payees: [
"0x12345674b599ce99958242b3D3741e7b01841DF3",
"0xA6f11e47dE28B3dB934e945daeb6F538E9019694",
],
shares: [
5100n, // 51%
4900n, // 49%
],
},
});
expect(address).toBeDefined();
expect(isAddress(address)).toBe(true);
contract = getContract({
address,
client,
chain,
});
}, 60_000);
it("should return all recipient addresses", async () => {
const result = await getAllRecipientsAddresses({ contract });
expect(result).toStrictEqual([
"0x12345674b599ce99958242b3D3741e7b01841DF3",
"0xA6f11e47dE28B3dB934e945daeb6F538E9019694",
]);
});
it("should return all recipients and their share percentages", async () => {
const result = await getAllRecipientsPercentages({ contract });
expect(result).toStrictEqual([
{
address: "0x12345674b599ce99958242b3D3741e7b01841DF3",
splitPercentage: 51,
},
{
address: "0xA6f11e47dE28B3dB934e945daeb6F538E9019694",
splitPercentage: 49,
},
]);
});
it("should return split percentage for individual recipient", async () => {
const result = await getRecipientSplitPercentage({
contract,
recipientAddress: "0x12345674b599ce99958242b3D3741e7b01841DF3",
});
expect(result).toStrictEqual({
address: "0x12345674b599ce99958242b3D3741e7b01841DF3",
splitPercentage: 51,
});
});
});
@@ -3,22 +3,22 @@ import { ANVIL_CHAIN } from "~test/chains.js";
import { TEST_CONTRACT_URI } from "~test/ipfs-uris.js";
import { TEST_CLIENT } from "~test/test-clients.js";
import { TEST_ACCOUNT_C } from "~test/test-wallets.js";
import { getContract } from "../../../contract/contract.js";
import { delegate } from "../../../extensions/erc20/__generated__/IVotes/write/delegate.js";
import { mintTo } from "../../../extensions/erc20/write/mintTo.js";
import { deployERC20Contract } from "../../../extensions/prebuilts/deploy-erc20.js";
import { deployVoteContract } from "../../../extensions/prebuilts/deploy-vote.js";
import { sendAndConfirmTransaction } from "../../../transaction/actions/send-and-confirm-transaction.js";
import { propose } from "../__generated__/Vote/write/propose.js";
import { getAll } from "./getAll.js";
import { proposalExists } from "./proposalExists.js";
import { getContract } from "../../contract/contract.js";
import { sendAndConfirmTransaction } from "../../transaction/actions/send-and-confirm-transaction.js";
import { delegate } from "../erc20/__generated__/IVotes/write/delegate.js";
import { mintTo } from "../erc20/write/mintTo.js";
import { deployERC20Contract } from "../prebuilts/deploy-erc20.js";
import { deployVoteContract } from "../prebuilts/deploy-vote.js";
import { propose } from "./__generated__/Vote/write/propose.js";
import { getAll } from "./read/getAll.js";
import { proposalExists } from "./read/proposalExists.js";
const account = TEST_ACCOUNT_C;
const client = TEST_CLIENT;
const chain = ANVIL_CHAIN;
describe.runIf(process.env.TW_SECRET_KEY)("proposal exists", () => {
it("should return false if Vote doesn't have any proposal", async () => {
it("`proposalExists` and `propose` should work", async () => {
const tokenAddress = await deployERC20Contract({
client: TEST_CLIENT,
chain: ANVIL_CHAIN,
@@ -42,47 +42,16 @@ describe.runIf(process.env.TW_SECRET_KEY)("proposal exists", () => {
minVoteQuorumRequiredPercent: 51,
},
});
const contract = getContract({
const voteContract = getContract({
address,
chain,
client,
});
const result = await proposalExists({ contract, proposalId: 0n });
const result = await proposalExists({
contract: voteContract,
proposalId: 0n,
});
expect(result).toBe(false);
});
it("should return true if Vote has the proposal (id)", async () => {
const tokenAddress = await deployERC20Contract({
client: TEST_CLIENT,
chain: ANVIL_CHAIN,
account,
type: "TokenERC20",
params: {
name: "Token",
contractURI: TEST_CONTRACT_URI,
},
});
const address = await deployVoteContract({
account,
client: TEST_CLIENT,
chain: ANVIL_CHAIN,
params: {
name: "",
contractURI: TEST_CONTRACT_URI,
tokenAddress: tokenAddress,
initialProposalThreshold: "0.5",
initialVotingPeriod: 10,
minVoteQuorumRequiredPercent: 51,
},
});
const contract = getContract({
address,
chain,
client,
});
const tokenContract = getContract({
address: tokenAddress,
@@ -105,19 +74,19 @@ describe.runIf(process.env.TW_SECRET_KEY)("proposal exists", () => {
// step 3: create a proposal
const transaction = propose({
contract,
contract: voteContract,
description: "first proposal",
targets: [contract.address],
targets: [voteContract.address],
values: [0n],
calldatas: ["0x"],
});
await sendAndConfirmTransaction({ transaction, account });
const allProposals = await getAll({ contract });
const allProposals = await getAll({ contract: voteContract });
expect(allProposals.length).toBe(1);
const result = await proposalExists({
contract,
const exists = await proposalExists({
contract: voteContract,
proposalId: allProposals[0]?.proposalId || -1n,
});
expect(result).toBe(true);
expect(exists).toBe(true);
});
});
@@ -20,6 +20,7 @@ import { sendAndConfirmTransaction } from "../../transaction/actions/send-and-co
import { sendBatchTransaction } from "../../transaction/actions/send-batch-transaction.js";
import { waitForReceipt } from "../../transaction/actions/wait-for-tx-receipt.js";
import { isContractDeployed } from "../../utils/bytecode/is-contract-deployed.js";
import { sleep } from "../../utils/sleep.js";
import type { Account, Wallet } from "../interfaces/wallet.js";
import { generateAccount } from "../utils/generateAccount.js";
import { smartWallet } from "./smart-wallet.js";
@@ -332,15 +333,17 @@ describe.runIf(process.env.TW_SECRET_KEY).sequential(
}),
account: newSmartAccount,
}),
sendAndConfirmTransaction({
transaction: claimTo({
contract,
quantity: 1n,
to: newSmartAccount.address,
tokenId: 0n,
sleep(1000).then(() =>
sendAndConfirmTransaction({
transaction: claimTo({
contract,
quantity: 1n,
to: newSmartAccount.address,
tokenId: 0n,
}),
account: newSmartAccount,
}),
account: newSmartAccount,
}),
),
]);
expect(txs.length).toEqual(2);
expect(txs.every((t) => t.transactionHash.length === 66)).toBe(true);
+3
View File
@@ -62,6 +62,9 @@ export default async function globalSetup() {
const shutdownAnvil = await startProxy({
port: 8648,
options: {
balance: 1000000000n,
},
});
// TODO re-enable thirdweb RPC for this fork