diff --git a/Anchor.toml b/Anchor.toml index e2e2d9f2..a616ad7a 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -48,6 +48,13 @@ v06-dump-daos-proposals = "yarn run tsx scripts/v0.6/dumpDaosProposals.ts" v06-migrate-daos-proposals = "yarn run tsx scripts/v0.6/migrateDaosProposals.ts" v06-create-dao = "yarn run tsx scripts/v0.6/createDao.ts" v06-provide-liquidity = "yarn run tsx scripts/v0.6/provideLiquidity.ts" +v07-launch-template = "yarn run tsx scripts/v0.7/launchTemplate.ts" +v07-start-launch = "yarn run tsx scripts/v0.7/startLaunch.ts" +v07-complete-launch = "yarn run tsx scripts/v0.7/completeLaunch.ts" +v07-claim-all-launch = "yarn run tsx scripts/v0.7/claimAllLaunch.ts" +v07-approve-points-based = "yarn run tsx scripts/v0.7/pointsBased/approveWithPointsWeightedPhase.ts" +v07-close-launch = "yarn run tsx scripts/v0.7/closeLaunch.ts" +v07-initialize-performance-package = "yarn run tsx scripts/v0.7/initializePerformancePackage.ts" [test] startup_wait = 5000 diff --git a/scripts/v0.7/claimAllLaunch.ts b/scripts/v0.7/claimAllLaunch.ts index 2aa5e7eb..68635a76 100644 --- a/scripts/v0.7/claimAllLaunch.ts +++ b/scripts/v0.7/claimAllLaunch.ts @@ -14,7 +14,7 @@ const provider = anchor.AnchorProvider.env(); const payer = provider.wallet["payer"]; const launchAddr = new PublicKey( - "9kx7UDFzFt7e2V4pFtawnupKKvRR3EhV7P1Pxmc5XCQj", + "FvQCwxmELEr7Dis8eQsij1F53wxgMohSiEZ9jMLMCapm", ); const launchpad: LaunchpadClient = LaunchpadClient.createClient({ provider }); @@ -54,29 +54,33 @@ async function main() { const tx = new Transaction(); // Add compute budget instruction to handle multiple claims - tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 })); + // tx.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 })); // Add claim instructions for each record in the batch for (const record of batch) { - const claimIx = await launchpad - .claimIx(launchAddr, launch.baseMint, record.account.funder) - .transaction(); + if (!record.account.isTokensClaimed) { + const claimIx = await launchpad + .claimIx(launchAddr, launch.baseMint, record.account.funder) + .transaction(); - tx.add(claimIx); + tx.add(claimIx); + } } await sendAndConfirmTransaction(tx, `Claim batch ${i / batchSize + 1}`); for (const record of batch) { - const refundIx = await launchpad - .refundIx({ - launch: launchAddr, - funder: record.account.funder, - quoteMint: launch.baseMint, - }) - .transaction(); - - tx.add(refundIx); + if (!record.account.isUsdcRefunded) { + const refundIx = await launchpad + .refundIx({ + launch: launchAddr, + funder: record.account.funder, + quoteMint: launch.quoteMint, + }) + .transaction(); + + tx.add(refundIx); + } } await sendAndConfirmTransaction(tx, `Refund batch ${i / batchSize + 1}`); diff --git a/scripts/v0.7/closeLaunch.ts b/scripts/v0.7/closeLaunch.ts index 8439d415..c34f55d1 100644 --- a/scripts/v0.7/closeLaunch.ts +++ b/scripts/v0.7/closeLaunch.ts @@ -7,12 +7,10 @@ const payer = provider.wallet["payer"]; const launchpad: LaunchpadClient = LaunchpadClient.createClient({ provider }); -export const closeLaunch = async () => { - const mintKp = new PublicKey("PRVT6TB7uss3FrUd2D9xs2zqDBsa3GbMJMwCQsgmeta"); - - const [launch] = getLaunchAddr(undefined, mintKp); +const launch = new PublicKey("FvQCwxmELEr7Dis8eQsij1F53wxgMohSiEZ9jMLMCapm"); - console.log(`Closing launch at address: ${launch.toString()}`); +export const closeLaunch = async () => { + console.log(`Closing launch at address: ${launch.toBase58()}`); await launchpad.closeLaunchIx({ launch }).rpc(); diff --git a/scripts/v0.7/completeLaunch.ts b/scripts/v0.7/completeLaunch.ts index 5be54a8b..a90486c4 100644 --- a/scripts/v0.7/completeLaunch.ts +++ b/scripts/v0.7/completeLaunch.ts @@ -7,30 +7,29 @@ import { } from "@solana/web3.js"; import { createLookupTableForTransaction } from "../utils/utils.js"; +const LAUNCH_TO_COMPLETE: PublicKey | undefined = new PublicKey( + "FvQCwxmELEr7Dis8eQsij1F53wxgMohSiEZ9jMLMCapm", +); + const provider = anchor.AnchorProvider.env(); const payer = provider.wallet["payer"]; const launchpad: LaunchpadClient = LaunchpadClient.createClient({ provider }); -const BID_WALL_FEE_RECIPIENT: PublicKey | undefined = undefined; - export const completeLaunch = async () => { - if (BID_WALL_FEE_RECIPIENT === undefined) { + if (LAUNCH_TO_COMPLETE === undefined) { throw new Error( - "BID_WALL_FEE_RECIPIENT is not set. Please set it in the script.", + "LAUNCH_TO_COMPLETE is not set. Please set it in the script.", ); } - const mintKp = new PublicKey("PRVT6TB7uss3FrUd2D9xs2zqDBsa3GbMJMwCQsgmeta"); - - const [launch] = getLaunchAddr(undefined, mintKp); + let launchAccount = await launchpad.fetchLaunch(LAUNCH_TO_COMPLETE); const tx = await launchpad .completeLaunchIx({ - launch, - baseMint: mintKp, + launch: LAUNCH_TO_COMPLETE, + baseMint: launchAccount.baseMint, launchAuthority: payer.publicKey, - feeRecipient: BID_WALL_FEE_RECIPIENT, }) .transaction(); @@ -51,9 +50,7 @@ export const completeLaunch = async () => { const vtx = new VersionedTransaction(message); vtx.sign([payer]); - const completeTxHash = await provider.connection.sendTransaction(vtx, { - skipPreflight: true, - }); + const completeTxHash = await provider.connection.sendTransaction(vtx); console.log(`Complete launch transaction sent: ${completeTxHash}`); @@ -61,10 +58,13 @@ export const completeLaunch = async () => { console.log("Setting up performance package..."); + // Refresh launch account to get the updated base mint + launchAccount = await launchpad.fetchLaunch(LAUNCH_TO_COMPLETE); + const initializePerformancePackageTxHash = await launchpad .initializePerformancePackageIx({ - launch, - baseMint: mintKp, + launch: LAUNCH_TO_COMPLETE, + baseMint: launchAccount.baseMint, payer: payer.publicKey, }) .rpc(); diff --git a/scripts/v0.7/initializePerformancePackage.ts b/scripts/v0.7/initializePerformancePackage.ts new file mode 100644 index 00000000..975b95f5 --- /dev/null +++ b/scripts/v0.7/initializePerformancePackage.ts @@ -0,0 +1,40 @@ +import * as anchor from "@coral-xyz/anchor"; +import { LaunchpadClient } from "@metadaoproject/futarchy/v0.7"; +import { PublicKey } from "@solana/web3.js"; + +const LAUNCH_TO_COMPLETE: PublicKey | undefined = new PublicKey( + "FvQCwxmELEr7Dis8eQsij1F53wxgMohSiEZ9jMLMCapm", +); + +const provider = anchor.AnchorProvider.env(); +const payer = provider.wallet["payer"]; + +const launchpad: LaunchpadClient = LaunchpadClient.createClient({ provider }); + +export const completeLaunch = async () => { + if (LAUNCH_TO_COMPLETE === undefined) { + throw new Error( + "LAUNCH_TO_COMPLETE is not set. Please set it in the script.", + ); + } + + const launchAccount = await launchpad.fetchLaunch(LAUNCH_TO_COMPLETE); + + console.log("Setting up performance package..."); + + const initializePerformancePackageTxHash = await launchpad + .initializePerformancePackageIx({ + launch: LAUNCH_TO_COMPLETE, + baseMint: launchAccount.baseMint, + payer: payer.publicKey, + }) + .rpc(); + + console.log( + `Initialize performance package transaction sent: ${initializePerformancePackageTxHash}`, + ); + + console.log("Performance package set up successfully!"); +}; + +completeLaunch().catch(console.error); diff --git a/scripts/v0.7/launchTemplate.ts b/scripts/v0.7/launchTemplate.ts index 3b41fa24..c0aaf271 100644 --- a/scripts/v0.7/launchTemplate.ts +++ b/scripts/v0.7/launchTemplate.ts @@ -77,7 +77,7 @@ export const launch = async () => { const txHash = await provider.connection.sendRawTransaction(tx.serialize()); await provider.connection.confirmTransaction(txHash, "confirmed"); - const launchIx = await launchpad + const initializeLaunchTxSignature = await launchpad .initializeLaunchIx({ tokenName: TOKEN_NAME, tokenSymbol: TOKEN_SYMBOL, @@ -101,7 +101,9 @@ export const launch = async () => { }) .rpc(); - console.log("Launch initialized", launchIx); + console.log("Launch initialized", initializeLaunchTxSignature); + + console.log("Launch address:", launch.toBase58()); // await launchpad.startLaunchIx({ launch }).rpc(); }; diff --git a/scripts/v0.7/pointsBased/.gitignore b/scripts/v0.7/pointsBased/.gitignore new file mode 100644 index 00000000..2a85ed5c --- /dev/null +++ b/scripts/v0.7/pointsBased/.gitignore @@ -0,0 +1 @@ +points.json \ No newline at end of file diff --git a/scripts/v0.7/pointsBased/approveOnlyPointsOwnersProRata.ts b/scripts/v0.7/pointsBased/approveWithPointsWeightedPhase.ts similarity index 89% rename from scripts/v0.7/pointsBased/approveOnlyPointsOwnersProRata.ts rename to scripts/v0.7/pointsBased/approveWithPointsWeightedPhase.ts index ce0147b5..46e1b99f 100644 --- a/scripts/v0.7/pointsBased/approveOnlyPointsOwnersProRata.ts +++ b/scripts/v0.7/pointsBased/approveWithPointsWeightedPhase.ts @@ -26,19 +26,22 @@ const payer = provider.wallet["payer"]; const launchpad: LaunchpadClient = LaunchpadClient.createClient({ provider }); // How many approvals to perform per transaction -const batchSize = 5; +const batchSize = 20; // The launch address const launchAddr = new PublicKey( - "9kx7UDFzFt7e2V4pFtawnupKKvRR3EhV7P1Pxmc5XCQj", + "FvQCwxmELEr7Dis8eQsij1F53wxgMohSiEZ9jMLMCapm", ); // The final raise amount (USDC, in atoms) -const finalRaiseAmount = 1_000_000_000000; +const finalRaiseAmount = 10_000000; async function main() { const pointsAllocations: PointsAllocation[] = JSON.parse( - fs.readFileSync(path.join(__dirname, "pointsAllocations.json"), "utf8"), + fs.readFileSync( + path.join(process.cwd(), "scripts/v0.7/pointsBased/points.json"), + "utf8", + ), ).map((x) => ({ user: new PublicKey(x.user), points: x.points, @@ -115,9 +118,12 @@ async function main() { // Assign amount to approve to each record for (const record of allFundingRecordsWithPointsOwners) { - record.amountToApprove = record.account.committedAmount - .mul(new BN(record.pointsOwner?.points ?? 0)) // In this phase, if there is no points owner, then they get no allocation, so we multiply by 0. - .div(totalPointsWithinLaunch); + record.amountToApprove = BN.min( + record.account.committedAmount, + new BN(finalRaiseAmount) + .mul(new BN(record.pointsOwner?.points ?? 0)) // In this phase, if there is no points owner, then they get no allocation, so we multiply by 0. + .div(totalPointsWithinLaunch), + ); } // Sum up total amount to approve @@ -152,15 +158,22 @@ async function main() { } } + // // IMPORTANT - PLEASE READ // // Uncomment this if we want the final raise amount to be a bit over the total committed amount // // This might be important if we want to ensure that the launch is successful in cases where the final raise amount is exactly equal to the minimum raise amount. - // // A small dust difference will occur due to rounding which could normally fail the launch, so we need to add 1 to all of the records that have an amount to approve that is not equal to the committed amount. + // // A small dust difference will occur due to rounding which could normally fail the launch, so we need to add 1 atom to all of the records that have an amount to approve that is not equal to the committed amount. // for (const record of allFundingRecordsWithPointsOwners) { // if (record.amountToApprove.lt(record.account.committedAmount)) { // record.amountToApprove = record.amountToApprove.add(new BN(1)); // } // } + for (const record of allFundingRecordsWithPointsOwners) { + console.log( + `${record.account.funder.toBase58()}:\t${record.amountToApprove.toString()}`, + ); + } + // Sum up total amount to approve and render it to the user const finalAmountToApprove = allFundingRecordsWithPointsOwners.reduce( (acc, curr) => acc.add(curr.amountToApprove), diff --git a/scripts/v0.7/pointsBased/points.json.example b/scripts/v0.7/pointsBased/points.json.example new file mode 100644 index 00000000..942b1385 --- /dev/null +++ b/scripts/v0.7/pointsBased/points.json.example @@ -0,0 +1,4 @@ +[ + { "user": "11111111111111111111111111111111", "points": 100 }, + { "user": "22222222222222222222222222222222", "points": 2 } +] diff --git a/scripts/v0.7/startLaunch.ts b/scripts/v0.7/startLaunch.ts new file mode 100644 index 00000000..21f773ca --- /dev/null +++ b/scripts/v0.7/startLaunch.ts @@ -0,0 +1,74 @@ +import { Keypair, PublicKey, Transaction } from "@solana/web3.js"; +import * as anchor from "@coral-xyz/anchor"; +import { LaunchpadClient } from "@metadaoproject/futarchy/v0.7"; + +import dotenv from "dotenv"; + +dotenv.config(); + +const provider = anchor.AnchorProvider.env(); +const payer = provider.wallet["payer"]; + +const LAUNCH_TO_START = new PublicKey( + "FvQCwxmELEr7Dis8eQsij1F53wxgMohSiEZ9jMLMCapm", +); + +const launchpad: LaunchpadClient = LaunchpadClient.createClient({ provider }); + +async function main() { + const launchAuthorityKeypair = payer; + + console.log( + "Launch authority public key:", + launchAuthorityKeypair.publicKey.toBase58(), + ); + + console.log("Starting launch..."); + + const tx = await launchpad + .startLaunchIx({ + launch: LAUNCH_TO_START, + launchAuthority: launchAuthorityKeypair.publicKey, + }) + .transaction(); + + await sendAndConfirmTransaction(tx, "Start launch", [launchAuthorityKeypair]); + + console.log("Launch started!"); + console.log("Launch address:", LAUNCH_TO_START.toBase58()); +} + +// Make sure the promise rejection is handled +main().catch((error) => { + console.error("Fatal error:", error); + process.exit(1); +}); + +async function sendAndConfirmTransaction( + tx: Transaction, + label: string, + signers: Keypair[] = [], +) { + tx.feePayer = payer.publicKey; + tx.recentBlockhash = ( + await provider.connection.getLatestBlockhash() + ).blockhash; + tx.partialSign(payer, ...signers); + const txHash = await provider.connection.sendRawTransaction(tx.serialize()); + console.log(`${label} transaction sent:`, txHash); + + await provider.connection.confirmTransaction(txHash, "confirmed"); + const txStatus = await provider.connection.getTransaction(txHash, { + maxSupportedTransactionVersion: 0, + commitment: "confirmed", + }); + if (txStatus?.meta?.err) { + throw new Error( + `Transaction failed: ${txHash}\nError: ${JSON.stringify( + txStatus?.meta?.err, + )}\n\n${txStatus?.meta?.logMessages?.join("\n")}`, + ); + } + console.log(`${label} transaction confirmed`); + return txHash; +}