Skip to content

Commit 466ae2f

Browse files
committed
feat(chain): mach token on devnet, arweave metadata, env cleanup
1 parent 2fc684b commit 466ae2f

8 files changed

Lines changed: 1659 additions & 19 deletions

File tree

.env.example

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,10 @@ DISCORD_CI_WEBHOOK= # GitHub CI pass/fail notifications (set in G
171171

172172
# ─── Feature Flags ───────────────────────────────────────────────────────────
173173
NODE_ENV=development
174+
175+
# ─── App ─────────────────────────────────────────────────────────────────────
176+
APP_URL=http://localhost:3000 # public-facing URL for magic link emails etc.
177+
CORS_ORIGINS=http://localhost:5173 # comma-separated allowed origins
178+
PORT=3000 # API listen port (alias for API_PORT in some services)
179+
DAEMON_HEALTH_PORT=3002 # daemon health-check HTTP port
180+
RUST_LOG=info # Rust log level: error | warn | info | debug | trace

assets/mach-token-metadata.json

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"name": "Maschina",
3+
"symbol": "MACH",
4+
"description": "Maschina governance and utility token. Stake to participate in network governance, earn rewards, and access premium compute capacity on the agentic network.",
5+
"image": "https://arweave.net/At45mjn2d5h2VqcYVGrc9xNf4YAtSuMcaN5qChaH2VsU",
6+
"external_url": "https://maschina.dev",
7+
"attributes": [],
8+
"properties": {
9+
"files": [
10+
{
11+
"uri": "https://arweave.net/At45mjn2d5h2VqcYVGrc9xNf4YAtSuMcaN5qChaH2VsU",
12+
"type": "image/png"
13+
}
14+
],
15+
"category": "image"
16+
}
17+
}

assets/mach-token.png

7.81 KB
Loading

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@
185185
"@commitlint/cli": "^19.6.0",
186186
"@commitlint/config-conventional": "^19.6.0",
187187
"@discordjs/rest": "^2.6.1",
188+
"@irys/sdk": "^0.2.11",
188189
"@semantic-release/changelog": "^6",
189190
"@semantic-release/github": "^10",
190191
"@types/node": "^22",

pnpm-lock.yaml

Lines changed: 1492 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/setup-mach-token.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ const MACH_TOKEN = {
4444
name: "Maschina",
4545
symbol: "MACH",
4646
decimals: 6, // Match USDC — makes on-chain math simpler
47-
uri: "https://maschina.ai/token/mach-metadata.json", // TODO: host this
47+
uri: "https://arweave.net/FSdeaS34qV2Z5ij95wcm9QdnSHkuyfRrsMhFGJ65yq8T",
4848
// Initial supply minted to authority — 0 for now (minted on demand per distribution schedule)
4949
initialSupply: 0n,
5050
} as const;

scripts/setup-realms.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,9 @@ async function main() {
106106
process.exit(1);
107107
}
108108

109-
// Detect which version of the Realms program is deployed
110-
const programVersion = await getGovernanceProgramVersion(connection, GOVERNANCE_PROGRAM_ID);
111-
console.log(`\nRealms program version: ${programVersion}`);
109+
// Use v3 directly — getGovernanceProgramVersion fails on some RPC endpoints
110+
const programVersion = PROGRAM_VERSION_V3;
111+
console.log(`\nRealms program version: ${programVersion} (v3 pinned)`);
112112

113113
// Build create-realm instruction
114114
const instructions: Parameters<typeof withCreateRealm>[0] = [];

scripts/upload-arweave.ts

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/**
2+
* upload-arweave.ts
3+
*
4+
* Uploads the MACH token image and metadata JSON to Arweave via Irys.
5+
* Prints the metadata URI to paste into setup-mach-token.ts.
6+
*
7+
* Run:
8+
* SOLANA_CLUSTER=devnet npx tsx scripts/upload-arweave.ts
9+
*
10+
* Prerequisites:
11+
* - pnpm add -D @irys/sdk
12+
* - Keypair at ~/.config/solana/id.json (or ANCHOR_WALLET)
13+
* - Devnet: funded automatically via airdrop
14+
* - Mainnet: wallet needs real SOL (upload costs ~$0.01 total)
15+
*
16+
* Output:
17+
* Image URI — paste into assets/mach-token-metadata.json
18+
* Metadata URI — paste into scripts/setup-mach-token.ts uri field
19+
*/
20+
21+
import fs from "node:fs";
22+
import os from "node:os";
23+
import path from "node:path";
24+
import Irys from "@irys/sdk";
25+
26+
const CLUSTER = process.env.SOLANA_CLUSTER ?? "devnet";
27+
28+
const ASSETS_DIR = path.join(path.dirname(new URL(import.meta.url).pathname), "..", "assets");
29+
const IMAGE_PATH = path.join(ASSETS_DIR, "mach-token.png");
30+
const METADATA_PATH = path.join(ASSETS_DIR, "mach-token-metadata.json");
31+
32+
function getIrysUrl(): string {
33+
return CLUSTER === "mainnet-beta" ? "https://node1.irys.xyz" : "https://devnet.irys.xyz";
34+
}
35+
36+
function getRpcUrl(): string {
37+
if (CLUSTER === "localnet") {
38+
console.error("Arweave uploads are not supported on localnet. Use devnet or mainnet-beta.");
39+
process.exit(1);
40+
}
41+
const apiKey = process.env.HELIUS_API_KEY;
42+
if (apiKey) {
43+
return CLUSTER === "mainnet-beta"
44+
? `https://mainnet.helius-rpc.com/?api-key=${apiKey}`
45+
: `https://devnet.helius-rpc.com/?api-key=${apiKey}`;
46+
}
47+
return CLUSTER === "mainnet-beta"
48+
? "https://api.mainnet-beta.solana.com"
49+
: "https://api.devnet.solana.com";
50+
}
51+
52+
function loadKeypairPath(): string {
53+
return process.env.ANCHOR_WALLET ?? path.join(os.homedir(), ".config", "solana", "id.json");
54+
}
55+
56+
async function main() {
57+
console.log(`Cluster: ${CLUSTER}`);
58+
console.log(`Irys node: ${getIrysUrl()}\n`);
59+
60+
if (!fs.existsSync(IMAGE_PATH)) {
61+
console.error(`Image not found: ${IMAGE_PATH}`);
62+
process.exit(1);
63+
}
64+
if (!fs.existsSync(METADATA_PATH)) {
65+
console.error(`Metadata not found: ${METADATA_PATH}`);
66+
process.exit(1);
67+
}
68+
69+
const keypairPath = loadKeypairPath();
70+
const keypairBytes = JSON.parse(fs.readFileSync(keypairPath, "utf-8")) as number[];
71+
const secretKey = Uint8Array.from(keypairBytes);
72+
73+
const irys = new Irys({
74+
url: getIrysUrl(),
75+
token: "solana",
76+
key: secretKey,
77+
config: { providerUrl: getRpcUrl() },
78+
});
79+
80+
// Fund if on devnet (devnet Irys will airdrop automatically)
81+
if (CLUSTER !== "mainnet-beta") {
82+
console.log("Funding Irys node (devnet)...");
83+
try {
84+
await irys.fund(irys.utils.toAtomic(0.05));
85+
console.log(" Funded 0.05 SOL\n");
86+
} catch {
87+
// May already be funded — continue
88+
console.log(" Already funded or airdrop pending — continuing\n");
89+
}
90+
}
91+
92+
// ── Upload image ─────────────────────────────────────────────────────────────
93+
console.log("Uploading mach-token.png...");
94+
const imageData = fs.readFileSync(IMAGE_PATH);
95+
const imageReceipt = await irys.upload(imageData, {
96+
tags: [
97+
{ name: "Content-Type", value: "image/png" },
98+
{ name: "App-Name", value: "Maschina" },
99+
],
100+
});
101+
const imageUri = `https://arweave.net/${imageReceipt.id}`;
102+
console.log(` Image URI: ${imageUri}\n`);
103+
104+
// ── Patch metadata with real image URI ───────────────────────────────────────
105+
const metadataRaw = fs.readFileSync(METADATA_PATH, "utf-8");
106+
const metadata = JSON.parse(metadataRaw);
107+
metadata.image = imageUri;
108+
metadata.properties.files[0].uri = imageUri;
109+
const metadataPatched = JSON.stringify(metadata, null, 2);
110+
111+
// ── Upload metadata ──────────────────────────────────────────────────────────
112+
console.log("Uploading mach-token-metadata.json...");
113+
const metaReceipt = await irys.upload(Buffer.from(metadataPatched, "utf-8"), {
114+
tags: [
115+
{ name: "Content-Type", value: "application/json" },
116+
{ name: "App-Name", value: "Maschina" },
117+
],
118+
});
119+
const metadataUri = `https://arweave.net/${metaReceipt.id}`;
120+
console.log(` Metadata URI: ${metadataUri}\n`);
121+
122+
// ── Write patched metadata back to disk ──────────────────────────────────────
123+
fs.writeFileSync(METADATA_PATH, metadataPatched);
124+
console.log(" Updated assets/mach-token-metadata.json with real image URI\n");
125+
126+
// ── Summary ──────────────────────────────────────────────────────────────────
127+
console.log("─────────────────────────────────────────────");
128+
console.log("Next steps:");
129+
console.log(" 1. In scripts/setup-mach-token.ts, set:");
130+
console.log(` uri: "${metadataUri}",`);
131+
console.log(" 2. Run: SOLANA_CLUSTER=devnet npx tsx scripts/setup-mach-token.ts");
132+
console.log("─────────────────────────────────────────────");
133+
}
134+
135+
main().catch((err) => {
136+
console.error(err);
137+
process.exit(1);
138+
});

0 commit comments

Comments
 (0)