Skip to content

Commit 73adb8a

Browse files
mattgloryclaude
andcommitted
Add deploy script for ALEX arb receiver
Deploys alex-arb-receiver and whitelists in flashstack-stx-core. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 15a66a8 commit 73adb8a

1 file changed

Lines changed: 117 additions & 0 deletions

File tree

scripts/deploy-alex-receiver.mjs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* FlashStack -- Deploy ALEX STX/ALEX Arbitrage Receiver
3+
*
4+
* Deploys alex-arb-receiver and whitelists it in flashstack-stx-core.
5+
*
6+
* Usage:
7+
* DEPLOYER_MNEMONIC="word1 ... word24" node scripts/deploy-alex-receiver.mjs
8+
*/
9+
10+
import { makeContractDeploy, makeContractCall, PostConditionMode, ClarityVersion, Cl } from "@stacks/transactions";
11+
import networkPkg from "@stacks/network";
12+
const { STACKS_MAINNET } = networkPkg;
13+
import walletPkg from "@stacks/wallet-sdk";
14+
const { generateWallet } = walletPkg;
15+
import { readFileSync } from "fs";
16+
17+
const MNEMONIC = process.env.DEPLOYER_MNEMONIC;
18+
const DEPLOYER = process.env.DEPLOYER_ADDRESS ?? "SP20XD46NGAX05ZQZDKFYCCX49A3852BQABNP0VG5";
19+
const API = "https://api.hiro.so";
20+
const EXPLORER = "https://explorer.hiro.so/txid";
21+
const network = STACKS_MAINNET;
22+
23+
if (!MNEMONIC) { console.error("ERROR: Set DEPLOYER_MNEMONIC"); process.exit(1); }
24+
25+
async function getPrivateKey() {
26+
const wallet = await generateWallet({ secretKey: MNEMONIC, password: "" });
27+
return wallet.accounts[0].stxPrivateKey;
28+
}
29+
async function getNonce() {
30+
const res = await fetch(`${API}/v2/accounts/${DEPLOYER}?proof=0`);
31+
return (await res.json()).nonce;
32+
}
33+
async function waitForConfirm(txid, label) {
34+
process.stdout.write(` Waiting for "${label}"`);
35+
for (let i = 0; i < 80; i++) {
36+
await new Promise(r => setTimeout(r, 8000));
37+
const res = await fetch(`${API}/extended/v1/tx/0x${txid}`);
38+
const data = await res.json();
39+
if (data.tx_status === "success") { console.log(" confirmed."); return; }
40+
if (data.tx_status?.startsWith("abort")) {
41+
console.log(`\n FAILED: ${data.tx_result?.repr ?? "unknown"}`);
42+
throw new Error(`"${label}" failed`);
43+
}
44+
process.stdout.write(".");
45+
}
46+
throw new Error(`Timeout: "${label}"`);
47+
}
48+
async function broadcast(tx) {
49+
const raw = tx.serialize();
50+
const body = typeof raw === "string" ? Buffer.from(raw.replace(/^0x/, ""), "hex") : raw;
51+
const res = await fetch(`${API}/v2/transactions`, {
52+
method: "POST", headers: { "Content-Type": "application/octet-stream" }, body,
53+
});
54+
const text = await res.text();
55+
let data; try { data = JSON.parse(text); } catch { throw new Error(`Non-JSON: ${text.slice(0, 200)}`); }
56+
if (data?.error) throw new Error(`${data.error} -- ${data.reason ?? ""}`);
57+
const txid = typeof data === "string" ? data : data.txid;
58+
if (!txid) throw new Error(`No txid: ${text.slice(0, 200)}`);
59+
return txid;
60+
}
61+
62+
async function main() {
63+
console.log("=======================================================");
64+
console.log(" FlashStack -- Deploy ALEX STX/ALEX Arb Receiver ");
65+
console.log("=======================================================");
66+
console.log(` Deployer: ${DEPLOYER}\n`);
67+
68+
const pk = await getPrivateKey();
69+
let nonce = await getNonce();
70+
console.log(` Starting nonce: ${nonce}\n`);
71+
72+
const NAME = "alex-arb-receiver";
73+
const PATH = "contracts/alex-arb-receiver.clar";
74+
const receiver = `${DEPLOYER}.${NAME}`;
75+
76+
// Step 1: Deploy
77+
console.log("Step 1 -- Deploy alex-arb-receiver");
78+
const deployTx = await makeContractDeploy({
79+
contractName: NAME, codeBody: readFileSync(PATH, "utf8"),
80+
senderKey: pk, network, clarityVersion: ClarityVersion.Clarity3,
81+
postConditionMode: PostConditionMode.Allow, anchorMode: 1, fee: 500_000, nonce: nonce++,
82+
});
83+
const deployTxid = await broadcast(deployTx);
84+
console.log(` Broadcast: ${deployTxid}`);
85+
console.log(` Explorer: ${EXPLORER}/${deployTxid}?chain=mainnet`);
86+
await waitForConfirm(deployTxid, "deploy alex-arb-receiver");
87+
console.log();
88+
89+
// Step 2: Whitelist in flashstack-stx-core
90+
console.log("Step 2 -- Whitelist in flashstack-stx-core");
91+
const wlTx = await makeContractCall({
92+
contractAddress: DEPLOYER, contractName: "flashstack-stx-core",
93+
functionName: "add-approved-receiver", functionArgs: [Cl.principal(receiver)],
94+
senderKey: pk, network, postConditionMode: PostConditionMode.Allow,
95+
anchorMode: 1, fee: 100_000, nonce: nonce++,
96+
});
97+
const wlTxid = await broadcast(wlTx);
98+
console.log(` Broadcast: ${wlTxid}`);
99+
console.log(` Explorer: ${EXPLORER}/${wlTxid}?chain=mainnet`);
100+
await waitForConfirm(wlTxid, "whitelist in flashstack-stx-core");
101+
console.log();
102+
103+
console.log("=======================================================");
104+
console.log(" DEPLOYMENT COMPLETE ");
105+
console.log("=======================================================");
106+
console.log(` Contract: ${receiver}`);
107+
console.log(` Deploy: ${EXPLORER}/${deployTxid}?chain=mainnet`);
108+
console.log(` Whitelist: ${EXPLORER}/${wlTxid}?chain=mainnet`);
109+
console.log();
110+
console.log(" Next steps:");
111+
console.log(" 1. Contact ALEX team to confirm contract is not blocklisted");
112+
console.log(" 2. Test with simulate() read-only before live execution");
113+
console.log(" 3. Run a live flash loan when STX/ALEX spread is profitable");
114+
console.log("=======================================================");
115+
}
116+
117+
main().catch(e => { console.error("\nFAILED:", e.message); process.exit(1); });

0 commit comments

Comments
 (0)