Monorepo for Aesthetic.Computer aesthetic.computer
at main 182 lines 7.3 kB view raw
1#!/usr/bin/env node 2/** 3 * test-temple-keep.mjs - Test keeping a piece via Temple mobile wallet 4 * 5 * This script: 6 * 1. Connects to Temple via QR code (Beacon P2P) 7 * 2. Prepares the keep parameters 8 * 3. Sends the operation to Temple for signing 9 * 10 * Usage: 11 * node test-temple-keep.mjs <piece-code> 12 * node test-temple-keep.mjs puf 13 */ 14 15import { pairWallet, sendContractCall } from "./beacon-node.mjs"; 16import { connect } from "../system/backend/database.mjs"; 17import { TezosToolkit } from "@taquito/taquito"; 18 19// Contract and network config - Ghostnet v3 20const CONTRACT_ADDRESS = "KT1StXrQNvRd9dNPpHdCGEstcGiBV6neq79K"; 21const NETWORK = "ghostnet"; 22const RPC = "https://ghostnet.ecadinfra.com"; 23 24// Colors 25const RESET = "\x1b[0m"; 26const BOLD = "\x1b[1m"; 27const DIM = "\x1b[2m"; 28const CYAN = "\x1b[36m"; 29const GREEN = "\x1b[32m"; 30const YELLOW = "\x1b[33m"; 31const RED = "\x1b[31m"; 32 33// String to hex bytes (for Michelson) 34function stringToBytes(str) { 35 return Buffer.from(str, "utf8").toString("hex"); 36} 37 38async function main() { 39 const pieceCode = process.argv[2]; 40 41 if (!pieceCode) { 42 console.log(`${RED}Usage: node test-temple-keep.mjs <piece-code>${RESET}`); 43 console.log(`${DIM}Example: node test-temple-keep.mjs puf${RESET}\n`); 44 process.exit(1); 45 } 46 47 const cleanCode = pieceCode.replace(/^\$/, ''); 48 49 console.log(`\n${BOLD}${CYAN}╔════════════════════════════════════════════════════════════════╗${RESET}`); 50 console.log(`${BOLD}${CYAN}║ 🏺 Keep via Temple Wallet: $${cleanCode}${RESET.padEnd(30)}${BOLD}${CYAN}${RESET}`); 51 console.log(`${BOLD}${CYAN}╚════════════════════════════════════════════════════════════════╝${RESET}\n`); 52 53 // Step 1: Pair with Temple 54 console.log(`${CYAN}Step 1: Connect to Temple Wallet${RESET}\n`); 55 const pairResult = await pairWallet("Aesthetic Computer"); 56 57 if (!pairResult?.permissionResponse?.address) { 58 console.log(`${RED}❌ Failed to connect wallet${RESET}\n`); 59 process.exit(1); 60 } 61 62 const { client, permissionResponse } = pairResult; 63 const walletAddress = permissionResponse.address; 64 65 console.log(`\n${GREEN}✓ Wallet connected: ${walletAddress}${RESET}\n`); 66 67 // Step 2: Get piece metadata from MongoDB (optional - for display) 68 console.log(`${CYAN}Step 2: Preparing keep parameters${RESET}\n`); 69 70 // For testing, we'll create minimal metadata 71 // In production, this would come from the KidLisp piece in MongoDB 72 const testMetadata = { 73 artifactUri: stringToBytes(`ipfs://test-artifact-${cleanCode}`), 74 attributes: stringToBytes("[]"), 75 content_hash: stringToBytes(`test-hash-${cleanCode}-${Date.now()}`), 76 content_type: stringToBytes("text/kidlisp"), 77 creators: stringToBytes(`["${walletAddress}"]`), 78 decimals: stringToBytes("0"), 79 description: stringToBytes(`Test keep for $${cleanCode}`), 80 displayUri: stringToBytes(`https://aesthetic.computer/$${cleanCode}`), 81 formats: stringToBytes("[]"), 82 isBooleanAmount: stringToBytes("true"), 83 metadata_uri: stringToBytes(""), 84 name: stringToBytes(`$${cleanCode}`), 85 owner: walletAddress, 86 rights: stringToBytes(""), 87 shouldPreferSymbol: stringToBytes("false"), 88 symbol: stringToBytes(`$${cleanCode}`), 89 tags: stringToBytes(`["KidLisp"]`), 90 thumbnailUri: stringToBytes(`https://aesthetic.computer/$${cleanCode}/thumbnail`) 91 }; 92 93 console.log(`${DIM}Piece: $${cleanCode}${RESET}`); 94 console.log(`${DIM}Owner: ${walletAddress}${RESET}`); 95 console.log(`${DIM}Contract: ${CONTRACT_ADDRESS}${RESET}\n`); 96 97 // Step 3: Build Michelson parameters for the keep entrypoint 98 // The keep entrypoint expects a complex record type 99 const keepParams = { 100 prim: "Pair", 101 args: [ 102 { bytes: testMetadata.artifactUri }, // artifactUri 103 { prim: "Pair", args: [ 104 { bytes: testMetadata.attributes }, // attributes 105 { prim: "Pair", args: [ 106 { bytes: testMetadata.content_hash }, // content_hash 107 { prim: "Pair", args: [ 108 { bytes: testMetadata.content_type }, // content_type 109 { prim: "Pair", args: [ 110 { bytes: testMetadata.creators }, // creators 111 { prim: "Pair", args: [ 112 { bytes: testMetadata.decimals }, // decimals 113 { prim: "Pair", args: [ 114 { bytes: testMetadata.description }, // description 115 { prim: "Pair", args: [ 116 { bytes: testMetadata.displayUri }, // displayUri 117 { prim: "Pair", args: [ 118 { bytes: testMetadata.formats }, // formats 119 { prim: "Pair", args: [ 120 { bytes: testMetadata.isBooleanAmount }, // isBooleanAmount 121 { prim: "Pair", args: [ 122 { bytes: testMetadata.metadata_uri }, // metadata_uri 123 { prim: "Pair", args: [ 124 { bytes: testMetadata.name }, // name 125 { prim: "Pair", args: [ 126 { string: testMetadata.owner }, // owner (address) 127 { prim: "Pair", args: [ 128 { bytes: testMetadata.rights }, // rights 129 { prim: "Pair", args: [ 130 { bytes: testMetadata.shouldPreferSymbol }, // shouldPreferSymbol 131 { prim: "Pair", args: [ 132 { bytes: testMetadata.symbol }, // symbol 133 { prim: "Pair", args: [ 134 { bytes: testMetadata.tags }, // tags 135 { bytes: testMetadata.thumbnailUri } // thumbnailUri 136 ]} 137 ]} 138 ]} 139 ]} 140 ]} 141 ]} 142 ]} 143 ]} 144 ]} 145 ]} 146 ]} 147 ]} 148 ]} 149 ]} 150 ]} 151 ]} 152 ] 153 }; 154 155 // Step 4: Send the operation to Temple 156 console.log(`${CYAN}Step 3: Send operation to Temple for signing${RESET}\n`); 157 console.log(`${YELLOW}📱 Check your Temple wallet to approve the transaction...${RESET}\n`); 158 console.log(`${DIM}Keep fee: 5 XTZ${RESET}\n`); 159 160 try { 161 const response = await sendContractCall( 162 client, 163 CONTRACT_ADDRESS, 164 "keep", 165 keepParams, 166 "5000000" // Keep fee: 5 XTZ in mutez 167 ); 168 169 console.log(`\n${GREEN}🏺 Keep operation submitted!${RESET}\n`); 170 if (response.transactionHash) { 171 console.log(`${CYAN}View on TzKT:${RESET} https://ghostnet.tzkt.io/${response.transactionHash}`); 172 } 173 } catch (err) { 174 console.log(`\n${RED}❌ Keep failed: ${err.message}${RESET}\n`); 175 process.exit(1); 176 } 177} 178 179main().catch(err => { 180 console.error(`${RED}Error: ${err.message}${RESET}`); 181 process.exit(1); 182});