# stablecoin:execute — Ammora SDK 0.3.8 Check the source for arguments and transaction requirements. [Read in Docs](https://docs.ammora.org/examples?command=stablecoin%3Aexecute) · [Detailed guide](https://docs.ammora.org/guides/stablecoin-quickstart) · [Local setup](https://docs.ammora.org/guides/example-setup) ## Context and execution GIWA Sepolia 91342. Public SDK 0.3.8, Math 0.3.0. Source revision: `a9b3fd798fa51495e8defec99a25de59e4d70672`. Install the SDK in your app, or prepare the example project using the local setup guide for its npm commands. Review the entry source and guide for required arguments, roles and deployment selection. `AMMORA_SEND=0` does not turn send-only commands into previews. Never put CLI keys in a browser or resend an uncertain transaction. Command: `npm run stablecoin:execute -- ` (`tsx src/stablecoin/execute.ts`). Omit `--` and arguments when the source accepts none. ## Entry file: `src/stablecoin/execute.ts` ```typescript import { readFileSync } from "node:fs"; import { join } from "node:path"; import { encodeFunctionData, erc20Abi, keccak256, parseAbi, type Address } from "viem"; import { planERC20Approvals, type AmmoraTransaction } from "@ammora-protocol/sdk"; import { signer } from "../shared/env.js"; import { main } from "../shared/run.js"; import { context } from "./context.js"; import { digest, json, load, same, type Manifest } from "./manifest.js"; import { makePlan, type Plan } from "./plans.js"; import { reserve } from "./journal.js"; import { receiptProof } from "./proof.js"; export async function executeReviewed(file:string,plan:Plan,reviewHash:string) { const {reviewHash:stored,...payload}=plan; if(stored!==reviewHash||digest(payload)!==reviewHash||!/^[a-f0-9]{64}$/.test(reviewHash)||plan.sdkVersion!=="0.3.8"||plan.schemaVersion!==1)throw new Error("Review hash/schema mismatch"); if(process.env.AMMORA_SEND!=="1")throw new Error("Execution needs AMMORA_SEND=1; planning is always unsigned"); const refreshed=await makePlan(plan.operation,file,plan.request,plan.expiresAt),binding=(p:Plan)=>({operation:p.operation,manifestDigest:p.manifestDigest,caller:p.caller,assets:p.assets,request:p.request,transactions:p.transactions,approvals:p.approvals,expectation:p.expectation}); if(digest(binding(refreshed))!==digest(binding(plan)))throw new Error("Plan changed with current state; review a NEW plan, never reuse the old hash"); const exposure=["swap","add","seed-almm","create-arl","create-almm","create-almm-preset"].includes(plan.operation),c=await context(file,exposure,plan.expectation.kind==="create-pool"?undefined:plan.expectation.pool); if(digest(c.m)!==plan.manifestDigest||!same(c.caller,plan.caller))throw new Error("Manifest/caller changed"); const canonical=await c.client.getBlock({blockNumber:BigInt(plan.snapshot.number)});if(canonical.hash!==plan.snapshot.hash)throw new Error("Original plan block no longer canonical"); const tokens=[c.m.base.address!,c.m.quote.address!],targets=[c.factory,c.registry,c.manager,...(c.m.model==="almm"?[c.rewardManager]:[]),...(c.pool?[c.pool]:[])]; for(const t of plan.transactions)if(!targets.some(a=>same(a,t.to))||BigInt(t.value??0)!==0n)throw new Error("Transaction outside authenticated targets or nonzero native value"); for(const a of plan.approvals)if(!tokens.some(t=>same(t,a.token))||!targets.some(t=>same(t,a.spender)))throw new Error("Approval outside pair/authenticated spender"); const initialNonce=await c.client.getTransactionCount({address:c.caller,blockTag:"latest"});if(initialNonce!==await c.client.getTransactionCount({address:c.caller,blockTag:"pending"}))throw new Error("Pending nonce must be reconciled before signing"); const approvals=await planERC20Approvals(c.c,c.caller,plan.approvals),baselines=[]; for(const a of plan.approvals)baselines.push({...a,baseline:await c.c.readContract({address:a.token,abi:erc20Abi,functionName:"allowance",args:[c.caller,a.spender]})}); const directory=process.env.AMMORA_STABLECOIN_STATE_DIR??join(process.cwd(),".validation/stablecoin-journal"),journal=reserve(directory,c.caller,reviewHash,plan.operation); // No key is read until identity, limits, current planner and pending nonce checks plus durable reservation pass. const {wallet,account}=signer();if(!same(account.address,c.caller))throw new Error("Signer mismatch; journal retained"); let nonce=initialNonce,reservedGas=0n;const cap=BigInt(c.m.policy.maxGasWei),results:Awaited>[]=[]; const transmit=async(tx:AmmoraTransaction,phase:string,actionIndex?:number)=>{ if(await c.client.getTransactionCount({address:c.caller,blockTag:"pending"})!==nonce||await c.client.getTransactionCount({address:c.caller,blockTag:"latest"})!==nonce)throw new Error("Nonce changed; stop and reconcile journal"); const request={to:tx.to,data:tx.data,value:BigInt(tx.value??0)}; await c.client.call({account:c.caller,...request}); const gas=(await c.client.estimateGas({account:c.caller,...request}))*12n/10n,maxFeePerGas=(await c.client.getGasPrice())*2n+1n; reservedGas+=gas*maxFeePerGas;if(reservedGas>cap||reservedGas>await c.client.getBalance({address:c.caller}))throw new Error("Reviewed native gas budget exceeded"); const entry={...request,value:String(request.value),phase:"SIGNING_OR_UNKNOWN",actionIndex,nonce,hash:undefined as `0x${string}`|undefined,blockNumber:undefined as string|undefined,blockHash:undefined as `0x${string}`|undefined};journal.value.entries.push(entry);journal.value.status=phase;journal.save(); const signed=await wallet.signTransaction({...request,chain:wallet.chain,account,nonce,gas,maxFeePerGas,maxPriorityFeePerGas:0n}),hash=keccak256(signed);entry.hash=hash;entry.phase="SIGNED_NOT_CONFIRMED";journal.save(); console.log(json({hash,nonce,phase,journal:journal.file})); // Hash is durable before RPC. A lost response MUST NOT cause another submission. const returned=await c.client.sendRawTransaction({serializedTransaction:signed});if(returned!==hash)throw new Error("RPC returned a different hash"); const receipt=await c.client.waitForTransactionReceipt({hash,confirmations:13,retryCount:0,timeout:120000,pollingInterval:3000}); if(receipt.status!=="success"||(await c.client.getBlock({blockNumber:receipt.blockNumber})).hash!==receipt.blockHash)throw new Error("Unsuccessful/noncanonical receipt; reconcile"); entry.phase="CONFIRMED";entry.blockNumber=String(receipt.blockNumber);entry.blockHash=receipt.blockHash;journal.save(); if(actionIndex!==undefined)results.push(await receiptProof(c.client,hash,plan,actionIndex,nonce));nonce++;return receipt; }; for(const p of approvals)for(const tx of p.transactions)await transmit(tx,"APPROVAL"); // Recheck issuer/runtime/reference/price after approval latency; exits don't require a fresh peg reference. await context(file,exposure,plan.expectation.kind==="create-pool"?undefined:plan.expectation.pool); for(let i=0;i=plan.expiresAt)throw new Error("Plan expired; preserve approvals and journal for reconciliation");await transmit(plan.transactions[i]!,"ACTION",i);} for(const a of baselines){const current=await c.client.readContract({address:a.token,abi:erc20Abi,functionName:"allowance",args:[c.caller,a.spender]});if(current>a.baseline)await transmit({to:a.token,data:encodeFunctionData({abi:erc20Abi,functionName:"approve",args:[a.spender,a.baseline]})},"RESTORE_ALLOWANCE");} journal.complete();console.log(json({operation:plan.operation,journal:journal.file,executionConfirmed:true,payoutVerified:false,note:"Read operation-specific receipt proof; successful execution alone is not a fee payout",results})); } main(async()=>{const[file,planFile,reviewHash,...extra]=process.argv.slice(2);if(!file||!planFile||!reviewHash||extra.length)throw new Error("usage: ");await executeReviewed(file,load(planFile) as Plan,reviewHash);}); ``` ## Supporting files Keep relative paths intact. Local imports are listed recursively; JSON templates are choices to review, not approved inputs. Runtime-selected files and wallet/environment setup still follow the detailed guide. - [src/quickstart/runtime-pins.giwa.json](https://docs.ammora.org/examples/source/src/quickstart/runtime-pins.giwa.json.txt) - [src/shared/env.ts](https://docs.ammora.org/examples/source/src/shared/env.ts.txt) - [src/shared/fee-payment.ts](https://docs.ammora.org/examples/source/src/shared/fee-payment.ts.txt) - [src/shared/input.ts](https://docs.ammora.org/examples/source/src/shared/input.ts.txt) - [src/shared/retry.ts](https://docs.ammora.org/examples/source/src/shared/retry.ts.txt) - [src/shared/rpc.ts](https://docs.ammora.org/examples/source/src/shared/rpc.ts.txt) - [src/shared/run.ts](https://docs.ammora.org/examples/source/src/shared/run.ts.txt) - [src/stablecoin/almm-deployment.ts](https://docs.ammora.org/examples/source/src/stablecoin/almm-deployment.ts.txt) - [src/stablecoin/almm-readiness-compat.ts](https://docs.ammora.org/examples/source/src/stablecoin/almm-readiness-compat.ts.txt) - [src/stablecoin/almm-readiness.ts](https://docs.ammora.org/examples/source/src/stablecoin/almm-readiness.ts.txt) - [src/stablecoin/context.ts](https://docs.ammora.org/examples/source/src/stablecoin/context.ts.txt) - [src/stablecoin/fixtures/almm-lowfee-giwa-v1.json](https://docs.ammora.org/examples/source/src/stablecoin/fixtures/almm-lowfee-giwa-v1.json.txt) - [src/stablecoin/journal.ts](https://docs.ammora.org/examples/source/src/stablecoin/journal.ts.txt) - [src/stablecoin/manifest.ts](https://docs.ammora.org/examples/source/src/stablecoin/manifest.ts.txt) - [src/stablecoin/plans.ts](https://docs.ammora.org/examples/source/src/stablecoin/plans.ts.txt) - [src/stablecoin/proof.ts](https://docs.ammora.org/examples/source/src/stablecoin/proof.ts.txt) - [src/stablecoin/fixtures/almm-lowfee-preset-request.json](https://docs.ammora.org/examples/source/src/stablecoin/fixtures/almm-lowfee-preset-request.json.txt) - [src/stablecoin/fixtures/almm-readiness-source.json](https://docs.ammora.org/examples/source/src/stablecoin/fixtures/almm-readiness-source.json.txt) - [src/stablecoin/manifests/almm-lowfee.synthetic.json](https://docs.ammora.org/examples/source/src/stablecoin/manifests/almm-lowfee.synthetic.json.txt) - [src/stablecoin/manifests/cusd.template.json](https://docs.ammora.org/examples/source/src/stablecoin/manifests/cusd.template.json.txt) - [src/stablecoin/manifests/fdusd.template.json](https://docs.ammora.org/examples/source/src/stablecoin/manifests/fdusd.template.json.txt) - [src/stablecoin/manifests/native-issuer.template.json](https://docs.ammora.org/examples/source/src/stablecoin/manifests/native-issuer.template.json.txt) - [src/stablecoin/requests/add.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/add.template.json.txt) - [src/stablecoin/requests/claim-lp-fees.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/claim-lp-fees.template.json.txt) - [src/stablecoin/requests/close-almm.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/close-almm.template.json.txt) - [src/stablecoin/requests/create-almm.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/create-almm.template.json.txt) - [src/stablecoin/requests/create-arl.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/create-arl.template.json.txt) - [src/stablecoin/requests/fee-delegate.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/fee-delegate.template.json.txt) - [src/stablecoin/requests/liquidity-policy.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/liquidity-policy.template.json.txt) - [src/stablecoin/requests/probe.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/probe.template.json.txt) - [src/stablecoin/requests/remove.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/remove.template.json.txt) - [src/stablecoin/requests/seed-almm.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/seed-almm.template.json.txt) - [src/stablecoin/requests/swap.template.json](https://docs.ammora.org/examples/source/src/stablecoin/requests/swap.template.json.txt) - [package.json](https://docs.ammora.org/examples/source/package.json.txt) - [package-lock.json](https://docs.ammora.org/examples/source/package-lock.json.txt) - [tsconfig.json](https://docs.ammora.org/examples/source/tsconfig.json.txt) - [.env.giwa.example](https://docs.ammora.org/examples/source/file.env.giwa.example.txt) - [.nvmrc](https://docs.ammora.org/examples/source/file.nvmrc.txt) ## AI implementation checklist Use the actual SDK exports and parameter types in the linked files. Start with reads and unsigned plans where supported. Use a connected wallet for browser signing. Preserve raw integer units, exact approvals, caller authority, deadlines and receipt reconciliation. Report local checks separately from live-chain verification.