diff --git a/scripts/e2e-control-plane-flow.cjs b/scripts/e2e-control-plane-flow.cjs index 13953aa..61be4ac 100644 --- a/scripts/e2e-control-plane-flow.cjs +++ b/scripts/e2e-control-plane-flow.cjs @@ -88,6 +88,23 @@ function summarizeSkip(reasonCode, httpStatus, detail) { }; } +function isInsufficientFundsError(err) { + const text = String(err?.message || err || "").toLowerCase(); + return text.includes("insufficient funds"); +} + +function isTxPendingResponse(result) { + if (!result || result.ok) { + return false; + } + const code = String(result.data?.code || "").toLowerCase(); + const detail = String(result.data?.error || "").toLowerCase(); + if (result.status === 409 && code.includes("verification") && detail.includes("pending")) { + return true; + } + return false; +} + async function main() { required("DEPLOYER_PRIVATE_KEY", PRIVATE_KEY); required("BASE_SEPOLIA_RPC_URL", RPC_URL); @@ -161,7 +178,25 @@ async function main() { chain_id: CHAIN_ID, }); - const membershipTxHash = await submitTransaction(signer, quote.tx || {}); + let membershipTxHash; + try { + membershipTxHash = await submitTransaction(signer, quote.tx || {}); + } catch (err) { + if (isInsufficientFundsError(err)) { + result.stages.membership_activation = summarizeSkip( + "insufficient_funds", + 0, + String(err?.message || err) + ); + } else { + throw err; + } + } + if (!membershipTxHash) { + console.log(JSON.stringify(result, null, 2)); + return; + } + const confirmPayload = { designation_code: intent.designation_code, quote_id: quote.quote_id, @@ -179,12 +214,26 @@ async function main() { confirmPayload.identity_attestation_id = IDENTITY_ATTESTATION_ID; } - const confirm = await expectOK("POST", "/secret/membership/confirm", confirmPayload); - result.stages.membership_activation = { - status: confirm.status, - tx_hash: membershipTxHash, - identity_assurance_level: confirm.identity_assurance_level || null, - }; + const confirmRes = await requestJSON("POST", "/secret/membership/confirm", confirmPayload); + if (!confirmRes.ok) { + if (isTxPendingResponse(confirmRes)) { + result.stages.membership_activation = summarizeSkip( + "tx_pending", + confirmRes.status, + confirmRes.data?.error || JSON.stringify(confirmRes.data || {}) + ); + } else { + throw new Error( + `POST /secret/membership/confirm failed (${confirmRes.status}): ${JSON.stringify(confirmRes.data)}` + ); + } + } else { + result.stages.membership_activation = { + status: confirmRes.data.status, + tx_hash: membershipTxHash, + identity_assurance_level: confirmRes.data.identity_assurance_level || null, + }; + } } else { result.stages.membership_activation = { status: "skipped_already_active", @@ -236,8 +285,26 @@ async function main() { "checkout quote returned empty calldata" ); } else { - const checkoutTxHash = await submitTransaction(signer, checkoutQuote.tx || {}); - const checkoutConfirm = await expectOK( + let checkoutTxHash; + try { + checkoutTxHash = await submitTransaction(signer, checkoutQuote.tx || {}); + } catch (err) { + if (isInsufficientFundsError(err)) { + result.stages.marketplace_checkout = summarizeSkip( + "insufficient_funds", + 0, + String(err?.message || err) + ); + } else { + throw err; + } + } + if (!checkoutTxHash) { + console.log(JSON.stringify(result, null, 2)); + return; + } + + const checkoutConfirmRes = await requestJSON( "POST", "/marketplace/checkout/confirm", { @@ -253,20 +320,34 @@ async function main() { }, sessionToken ); - const entitlements = await expectOK( - "GET", - `/marketplace/entitlements?wallet=${encodeURIComponent(wallet)}`, - undefined, - sessionToken - ); - result.stages.marketplace_checkout = { - status: checkoutConfirm.status, - entitlement_id: checkoutConfirm.entitlement_id, - tx_hash: checkoutTxHash, - entitlement_count: Array.isArray(entitlements.entitlements) - ? entitlements.entitlements.length - : 0, - }; + if (!checkoutConfirmRes.ok) { + if (isTxPendingResponse(checkoutConfirmRes)) { + result.stages.marketplace_checkout = summarizeSkip( + "tx_pending", + checkoutConfirmRes.status, + checkoutConfirmRes.data?.error || JSON.stringify(checkoutConfirmRes.data || {}) + ); + } else { + throw new Error( + `POST /marketplace/checkout/confirm failed (${checkoutConfirmRes.status}): ${JSON.stringify(checkoutConfirmRes.data)}` + ); + } + } else { + const entitlements = await expectOK( + "GET", + `/marketplace/entitlements?wallet=${encodeURIComponent(wallet)}`, + undefined, + sessionToken + ); + result.stages.marketplace_checkout = { + status: checkoutConfirmRes.data.status, + entitlement_id: checkoutConfirmRes.data.entitlement_id, + tx_hash: checkoutTxHash, + entitlement_count: Array.isArray(entitlements.entitlements) + ? entitlements.entitlements.length + : 0, + }; + } } }