import {
execUnshield,
getPrivateBalance,
requestGasFunding,
waitForFunding,
sweepCompanion,
GAS_FUND_STRK,
type CompanionCtx,
} from "@chipi-stack/core";
import { Account } from "starknet";
declare const ctx: CompanionCtx; // the same ctx used to shield
declare const gasTankAddress: string; // leftover fronted STRK returns here
// Exact private amounts per token (viewing-key note scan, read-only).
const account = new Account({
provider: ctx.provider,
address: ctx.companionAddress,
signer: ctx.companionKey,
cairoVersion: "1",
});
const { byToken } = await getPrivateBalance({
provider: ctx.provider,
account,
viewingKey: ctx.poolKey,
provingProvider: ctx.provingProvider,
});
// The prover proves against head − 12: wait until it can SEE the state the
// previous operation wrote before compiling the next one.
async function waitProverView(fromBlock: number) {
for (;;) {
const b = await ctx.provider.getBlockNumber();
if (b >= fromBlock + 13) return;
await new Promise((r) => setTimeout(r, 30_000));
}
}
const gasOpts = {
baseUrl: "https://api.chipipay.com/v1",
apiKey: apiPublicKey,
getBearerToken: () => getToken(),
};
// `lastOpBlock` starts at the SHIELD's block — the freshly created notes are
// just as invisible to the prover as a fresh withdrawal.
let lastOpBlock = await ctx.provider.getBlockNumber();
for (const [token, amountRaw] of Object.entries(byToken)) {
if (amountRaw === 0n) continue;
await waitProverView(lastOpBlock);
await requestGasFunding(ctx.companionAddress, gasOpts); // refuel EVERY op
await waitForFunding(ctx.provider, ctx.companionAddress, { strk: GAS_FUND_STRK });
const result = await execUnshield(ctx, token, amountRaw);
lastOpBlock = await ctx.provider.getBlockNumber();
// The sweep IS the delivery of the user's money here — strict, not
// best-effort, so a failed delivery throws instead of claiming success.
await sweepCompanion({
provider: ctx.provider,
companionAddress: ctx.companionAddress,
companionKey: ctx.companionKey,
gasTank: gasTankAddress,
deliverToken: { address: token, to: wallet.address },
strict: true,
});
console.log(`unshielded ${token}: ${result.transactionHash}`);
}