UNPKG

attest.so

Version:

<div align="center">

191 lines (165 loc) 7.5 kB
import { Address, Contract, TransactionBuilder, Keypair, Networks, xdr, SorobanRpc, Operation } from '@stellar/stellar-sdk'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; // Get __dirname in ES module scope const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // Function to parse .sh-style env file function parseShEnv(filePath) { const env = {}; try { const content = fs.readFileSync(filePath, { encoding: 'utf8' }); content.split('\n').forEach(line => { line = line.trim(); if (line && !line.startsWith('#')) { const match = line.match(/^export\s+([^=]+)=(.*)$/); if (match) { let key = match[1]; let value = match[2]; // Remove surrounding quotes if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { value = value.substring(1, value.length - 1); } env[key] = value; } } }); } catch (e) { console.error(`Error reading or parsing env file ${filePath}:`, e); } return env; } // Load environment variables from env.sh const envPath = path.resolve(__dirname, '../env.sh'); const envConfig = parseShEnv(envPath); // Configuration const RPC_URL = 'https://soroban-testnet.stellar.org'; const NETWORK_PASSPHRASE = Networks.TESTNET; const ADMIN_SECRET_KEY = envConfig.ADMIN_SECRET_KEY; const AUTHORITY_RESOLVER_CONTRACT_ID = envConfig.AUTHORITY_RESOLVER_CONTRACT_ID || 'CDQREK6BTPEVD4O56XR6TKLEEMNYTRJUG466J2ERNE5POIEKN2N6O7EL'; // Use latest contract ID const ADMIN_ADDRESS = envConfig.ADMIN_ADDRESS; const TOKEN_CONTRACT_ID = envConfig.TOKEN_CONTRACT_ID; console.log('Environment configuration loaded:'); console.log(`Contract ID: ${AUTHORITY_RESOLVER_CONTRACT_ID}`); console.log(`Admin Address: ${ADMIN_ADDRESS}`); console.log(`Token Contract ID: ${TOKEN_CONTRACT_ID}`); if (!ADMIN_SECRET_KEY) { console.error("Error: ADMIN_SECRET_KEY is required in env.sh"); process.exit(1); } // Initialize Soroban RPC client const server = new SorobanRpc.Server(RPC_URL, { allowHttp: RPC_URL.startsWith('http://') }); const sourceKeypair = Keypair.fromSecret(ADMIN_SECRET_KEY); const sourceAccountId = sourceKeypair.publicKey(); // Convert string address to contract Address function createContractAddress(contractId) { return new Address(contractId); } // Convert account string to account Address function createAccountAddress(accountId) { return Address.fromString(accountId); } async function initializeContract() { console.log(`Initializing contract: ${AUTHORITY_RESOLVER_CONTRACT_ID}`); console.log(`Using admin address: ${ADMIN_ADDRESS}`); console.log(`Using token contract: ${TOKEN_CONTRACT_ID}`); console.log(`Using source account: ${sourceAccountId}`); try { // Get source account console.log('Fetching source account...'); const account = await server.getAccount(sourceAccountId); console.log('Account found'); // Creating the contract instance console.log('Creating contract instance...'); const contractId = createContractAddress(AUTHORITY_RESOLVER_CONTRACT_ID); // Prepare parameters const adminAddr = createAccountAddress(ADMIN_ADDRESS); const tokenAddr = createContractAddress(TOKEN_CONTRACT_ID); // Construct the operation correctly const operation = Operation.invokeHostFunction({ func: xdr.HostFunction.hostFunctionTypeInvokeContract(new xdr.InvokeContractArgs({ contractAddress: contractId.toScAddress(), functionName: "initialize", args: [adminAddr.toScVal(), tokenAddr.toScVal()] })), auth: [] }); // Build transaction with higher fee const tx = new TransactionBuilder(account, { fee: "1000000", // 0.1 XLM networkPassphrase: NETWORK_PASSPHRASE, }) .addOperation(operation) .setTimeout(60) .build(); // Simulate transaction console.log('Simulating transaction...'); try { const sim = await server.simulateTransaction(tx); console.log('Simulation response:', JSON.stringify(sim, null, 2)); if (sim.error) { console.error('Simulation failed:', sim.error); return; } // If simulation succeeds, prepare and sign the transaction console.log('Preparing transaction...'); const preparedTx = SorobanRpc.assembleTransaction(tx, sim).build(); // Sign the transaction console.log('Signing transaction...'); preparedTx.sign(sourceKeypair); // Submit transaction console.log('Submitting transaction...'); const response = await server.sendTransaction(preparedTx); console.log('Transaction submitted:', response); if (response.status === 'PENDING') { console.log('Transaction is pending. Waiting for confirmation...'); // Wait for transaction to complete with longer timeout let status = response.status; let attempts = 30; // Increased from 10 to 30 let txResponse; while (status === 'PENDING' || status === 'NOT_FOUND' && attempts > 0) { await new Promise(resolve => setTimeout(resolve, 3000)); // Increased to 3 seconds txResponse = await server.getTransaction(response.hash); status = txResponse.status; console.log(`Transaction status check (${31-attempts}/30): ${status}`); attempts--; } if (status === 'SUCCESS') { console.log('Transaction was successful!'); console.log('Result:', txResponse.resultXdr); } else { console.error('Transaction failed or timed out:', status); if (txResponse && txResponse.resultXdr) { console.error('Result XDR:', txResponse.resultXdr); } } } else { console.error('Transaction submission failed:', response.status); if (response.errorResultXdr) { console.error('Error XDR:', response.errorResultXdr); } } } catch (error) { console.error('Simulation error:', error.message); if (error.response && error.response.data) { console.error('Error details:', JSON.stringify(error.response.data, null, 2)); } } } catch (error) { console.error('Error:', error.message); if (error.response && error.response.data) { console.error('Error details:', JSON.stringify(error.response.data, null, 2)); } } } // Main function async function main() { try { await initializeContract(); } catch (error) { console.error('Unhandled error:', error); } } // Run the main function main();