Skip to content

Commit 13891f8

Browse files
authored
Hurupay launch (#411)
* adds huru token metadata * adds setup script for review * adds simulation for cus * update team address * updates investors and team carveout
1 parent bc7baef commit 13891f8

File tree

3 files changed

+171
-0
lines changed

3 files changed

+171
-0
lines changed

scripts/assets/HURU/HURU.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"name": "Hurupay",
3+
"symbol": "HURU",
4+
"description": "Hurupay is the global USD banking layer for workers and businesses inside and outside the U.S., built on stablecoins.",
5+
"image": "https://raw.githubusercontent.com/metaDAOproject/futarchy/refs/heads/develop/scripts/assets/HURU/HURU.png"
6+
}

scripts/assets/HURU/HURU.png

2.79 KB
Loading
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import * as anchor from "@coral-xyz/anchor";
2+
import {
3+
LaunchpadClient,
4+
getLaunchAddr,
5+
getLaunchSignerAddr,
6+
} from "@metadaoproject/futarchy/v0.7";
7+
import {
8+
ComputeBudgetProgram,
9+
PublicKey,
10+
SystemProgram,
11+
Transaction,
12+
} from "@solana/web3.js";
13+
import BN from "bn.js";
14+
import * as token from "@solana/spl-token";
15+
16+
const provider = anchor.AnchorProvider.env();
17+
const payer = provider.wallet["payer"];
18+
19+
const LAUNCH_AUTHORITY = payer.publicKey;
20+
21+
const TEAM_ADDRESS = new PublicKey(
22+
"5ZGh1VosZepRpTamvCNLVsRx9xPy8gykFTfRS27Du4H1",
23+
); // Hurupay team address
24+
25+
// Launch details
26+
const MIN_GOAL = 3_000_000; // 3M USDC
27+
28+
const SPENDING_MEMBERS = [
29+
new PublicKey("7BPZaiS2LMhQHF7Yt8Pj16YmnCpsdiwRPSatkYjtbJVp"),
30+
new PublicKey("Fa6CuD8JCy9wSkoqAVmY7LVNPvVo9fPGVoYtBSF5qQhg"),
31+
new PublicKey("CANWSTstBGBnQEhYQ7d1Tzg1wFWJoZnLBosVnF4GtMob"),
32+
];
33+
const SPENDING_LIMIT = 250_000; // 250k USDC
34+
35+
// Even without a performance package, defaults need to be set
36+
const PERFORMANCE_PACKAGE_GRANTEE = new PublicKey(
37+
"11111111111111111111111111111111",
38+
);
39+
const PERFORMANCE_PACKAGE_TOKEN_AMOUNT = 1; // 1 HURU
40+
const PERFORMANCE_PACKAGE_UNLOCK_MONTHS = 36; // 36 months
41+
42+
// Additional carveout details
43+
const ADDITIONAL_CARVEOUT = 12_725_000; // 12.725M HURU
44+
const ADDITIONAL_CARVEOUT_RECIPIENT = new PublicKey(
45+
"6awyHMshBGVjJ3ozdSJdyyDE1CTAXUwrpNMaRGMsb4sf",
46+
); // MetaDAO operational multisig vault
47+
48+
const TOKEN_SEED = "DrmUAbym6RUsMqs6";
49+
const TOKEN_NAME = "Hurupay";
50+
const TOKEN_SYMBOL = "HURU";
51+
const TOKEN_URI =
52+
"https://raw.githubusercontent.com/metaDAOproject/programs/refs/heads/develop/scripts/assets/HURU/HURU.json";
53+
54+
const secondsPerDay = 86_400;
55+
const numberOfDays = 4;
56+
const launchDurationSeconds = secondsPerDay * numberOfDays; // 4 days
57+
58+
const launchpad: LaunchpadClient = LaunchpadClient.createClient({ provider });
59+
60+
export const launch = async () => {
61+
const lamports = await provider.connection.getMinimumBalanceForRentExemption(
62+
token.MINT_SIZE,
63+
);
64+
65+
const TOKEN = await PublicKey.createWithSeed(
66+
payer.publicKey,
67+
TOKEN_SEED,
68+
token.TOKEN_PROGRAM_ID,
69+
);
70+
console.log("Token address:", TOKEN.toBase58());
71+
72+
const [launch] = getLaunchAddr(undefined, TOKEN);
73+
const [launchSigner] = getLaunchSignerAddr(undefined, launch);
74+
75+
const createTokenAccountIx = SystemProgram.createAccountWithSeed({
76+
fromPubkey: payer.publicKey,
77+
newAccountPubkey: TOKEN,
78+
basePubkey: payer.publicKey,
79+
seed: TOKEN_SEED,
80+
lamports: lamports,
81+
space: token.MINT_SIZE,
82+
programId: token.TOKEN_PROGRAM_ID,
83+
});
84+
85+
const initializeMintIx = token.createInitializeMint2Instruction(
86+
TOKEN,
87+
6,
88+
launchSigner,
89+
null,
90+
);
91+
92+
const launchIx = await launchpad
93+
.initializeLaunchIx({
94+
tokenName: TOKEN_NAME,
95+
tokenSymbol: TOKEN_SYMBOL,
96+
tokenUri: TOKEN_URI,
97+
minimumRaiseAmount: new BN(MIN_GOAL * 10 ** 6),
98+
baseMint: TOKEN,
99+
monthlySpendingLimitAmount: new BN(SPENDING_LIMIT * 10 ** 6),
100+
monthlySpendingLimitMembers: SPENDING_MEMBERS,
101+
performancePackageGrantee: PERFORMANCE_PACKAGE_GRANTEE,
102+
performancePackageTokenAmount: new BN(
103+
PERFORMANCE_PACKAGE_TOKEN_AMOUNT * 10 ** 6,
104+
),
105+
monthsUntilInsidersCanUnlock: PERFORMANCE_PACKAGE_UNLOCK_MONTHS,
106+
secondsForLaunch: launchDurationSeconds,
107+
teamAddress: TEAM_ADDRESS,
108+
additionalTokensAmount: ADDITIONAL_CARVEOUT
109+
? new BN(ADDITIONAL_CARVEOUT * 10 ** 6)
110+
: undefined,
111+
additionalTokensRecipient: ADDITIONAL_CARVEOUT_RECIPIENT,
112+
launchAuthority: LAUNCH_AUTHORITY,
113+
})
114+
.instruction();
115+
116+
// Build transaction without compute budget first
117+
const tx = new Transaction().add(
118+
createTokenAccountIx,
119+
initializeMintIx,
120+
launchIx,
121+
);
122+
123+
const { blockhash } = await provider.connection.getLatestBlockhash();
124+
tx.recentBlockhash = blockhash;
125+
tx.feePayer = payer.publicKey;
126+
127+
// Simulate transaction to get compute units used
128+
tx.sign(payer);
129+
const simulation = await provider.connection.simulateTransaction(tx);
130+
131+
if (simulation.value.err) {
132+
console.error("Transaction simulation failed:", simulation.value.err);
133+
throw new Error(
134+
`Simulation failed: ${JSON.stringify(simulation.value.err)}`,
135+
);
136+
}
137+
138+
const computeUnitsUsed = simulation.value.unitsConsumed || 200_000;
139+
// Add 20% buffer to the compute units
140+
const computeUnitsWithBuffer = Math.floor(computeUnitsUsed * 1.2);
141+
142+
console.log(`Simulated compute units: ${computeUnitsUsed}`);
143+
console.log(`Setting compute unit limit: ${computeUnitsWithBuffer}`);
144+
145+
// Rebuild transaction with compute budget
146+
const finalTx = new Transaction().add(
147+
ComputeBudgetProgram.setComputeUnitLimit({ units: computeUnitsWithBuffer }),
148+
createTokenAccountIx,
149+
initializeMintIx,
150+
launchIx,
151+
);
152+
153+
finalTx.recentBlockhash = blockhash;
154+
finalTx.feePayer = payer.publicKey;
155+
finalTx.sign(payer);
156+
157+
const txHash = await provider.connection.sendRawTransaction(
158+
finalTx.serialize(),
159+
);
160+
await provider.connection.confirmTransaction(txHash, "confirmed");
161+
162+
console.log("Launch initialized", txHash);
163+
};
164+
165+
launch().catch(console.error);

0 commit comments

Comments
 (0)