{"version":3,"file":"custody-signer.mjs","names":[],"sources":["../../../src/services/auth/custody-signer.ts"],"sourcesContent":["import { OutlayerClient, OutlayerError, PolicyDeniedError, WalletFrozenError } from \"@outlayer/sdk\";\nimport type { NetworkId } from \"../registry/fastkv\";\nimport type { RelayResult } from \"./delegate-signer\";\nimport type { CustodyWalletRecord } from \"./session\";\n\nconst PUBLISH_GAS = \"30000000000000\";\nconst MIN_GAS_BALANCE = \"50000000000000000000000\";\n\nconst OUTLAYER_HOSTS: Record<NetworkId, string> = {\n  mainnet: \"https://api.outlayer.ai\",\n  testnet: \"https://testnet-api.outlayer.ai\",\n};\n\nexport interface CustodySubmitOptions {\n  contract: string;\n  args: Record<string, string>;\n  custodyWallet: CustodyWalletRecord;\n  idempotencyKey?: string;\n}\n\nfunction custodyClient(custodyWallet: CustodyWalletRecord): OutlayerClient {\n  const network = custodyWallet.network;\n  return new OutlayerClient({\n    apiKey: custodyWallet.apiKey,\n    network,\n    baseUrl: OUTLAYER_HOSTS[network],\n  });\n}\n\nexport function custodyFundUrl(custodyWallet: CustodyWalletRecord): string {\n  return `https://app.outlayer.ai/wallet/fund?to=${custodyWallet.nearAccountId}&amount=0.05&token=near`;\n}\n\nexport async function ensureCustodyBalance(custodyWallet: CustodyWalletRecord): Promise<void> {\n  const client = custodyClient(custodyWallet);\n  try {\n    const { balance } = await client.getBalance({ chain: \"near\" });\n    if (BigInt(balance) < BigInt(MIN_GAS_BALANCE)) {\n      throw new Error(\n        `The custody wallet ${custodyWallet.nearAccountId} holds ${balance} yoctoNEAR on ` +\n          `${custodyWallet.network}, below the gas minimum. Fund it at ${custodyFundUrl(custodyWallet)}`,\n      );\n    }\n  } catch (error) {\n    throw custodyPublishError(error, custodyWallet);\n  }\n}\n\nexport async function submitRegistryWriteCustody(opts: CustodySubmitOptions): Promise<RelayResult> {\n  const client = custodyClient(opts.custodyWallet);\n  try {\n    const result = await client.call({\n      receiver_id: opts.contract,\n      method_name: \"__fastdata_kv\",\n      args: opts.args,\n      gas: PUBLISH_GAS,\n      deposit: \"0\",\n      ...(opts.idempotencyKey ? { idempotencyKey: opts.idempotencyKey } : {}),\n    });\n    if (result.status === \"failed\" || result.status === \"rejected\") {\n      throw new Error(\n        `The custody publish did not settle (status ${result.status}). Inspect request ${result.request_id} at the OutLayer dashboard.`,\n      );\n    }\n    if (result.status === \"pending_approval\") {\n      throw new Error(\n        `The custody publish needs multisig approval (${result.approved ?? 0}/${result.required ?? \"?\"} so far). ` +\n          \"Approve it at the OutLayer dashboard, then re-run the deploy.\",\n      );\n    }\n    return { success: true, txHash: result.tx_hash ?? undefined };\n  } catch (error) {\n    const code: string = error instanceof OutlayerError ? error.code : \"\";\n    if (code === \"onchain_tx_failed\") {\n      return { success: true };\n    }\n    throw custodyPublishError(error, opts.custodyWallet);\n  }\n}\n\nfunction custodyPublishError(error: unknown, custodyWallet: CustodyWalletRecord): unknown {\n  if (!(error instanceof OutlayerError)) return error;\n  const code: string = error.code;\n  const context = custodyWallet.handoffUrl\n    ? ` Manage the wallet at ${custodyWallet.handoffUrl}.`\n    : \"\";\n  if (error instanceof PolicyDeniedError) {\n    return new Error(`The custody wallet policy refused the publish.${context}`);\n  }\n  if (error instanceof WalletFrozenError) {\n    return new Error(`The custody wallet is frozen.${context}`);\n  }\n  if (code === \"insufficient_balance\" || code === \"wallet_underfunded\") {\n    const detail = error.message ? ` (${error.message})` : \"\";\n    return new Error(\n      `The custody wallet ran out of gas for the publish${detail}. Fund it at ${custodyFundUrl(custodyWallet)}`,\n    );\n  }\n  if (code === \"invalid_api_key\" || code === \"missing_auth\") {\n    return new Error(\n      `The stored custody wallet key was rejected. Re-run \\`bos login --custody\\` to re-register.`,\n    );\n  }\n  return new Error(`Custody publish failed (${code}): ${error.message}`);\n}\n"],"mappings":";;;AAKA,MAAM,cAAc;AACpB,MAAM,kBAAkB;AAExB,MAAM,iBAA4C;CAChD,SAAS;CACT,SAAS;AACX;AASA,SAAS,cAAc,eAAoD;CACzE,MAAM,UAAU,cAAc;CAC9B,OAAO,IAAI,eAAe;EACxB,QAAQ,cAAc;EACtB;EACA,SAAS,eAAe;CAC1B,CAAC;AACH;AAEA,SAAgB,eAAe,eAA4C;CACzE,OAAO,0CAA0C,cAAc,cAAc;AAC/E;AAEA,eAAsB,qBAAqB,eAAmD;CAC5F,MAAM,SAAS,cAAc,aAAa;CAC1C,IAAI;EACF,MAAM,EAAE,YAAY,MAAM,OAAO,WAAW,EAAE,OAAO,OAAO,CAAC;EAC7D,IAAI,OAAO,OAAO,IAAI,OAAO,eAAe,GAC1C,MAAM,IAAI,MACR,sBAAsB,cAAc,cAAc,SAAS,QAAQ,gBAC9D,cAAc,QAAQ,sCAAsC,eAAe,aAAa,GAC/F;CAEJ,SAAS,OAAO;EACd,MAAM,oBAAoB,OAAO,aAAa;CAChD;AACF;AAEA,eAAsB,2BAA2B,MAAkD;CACjG,MAAM,SAAS,cAAc,KAAK,aAAa;CAC/C,IAAI;EACF,MAAM,SAAS,MAAM,OAAO,KAAK;GAC/B,aAAa,KAAK;GAClB,aAAa;GACb,MAAM,KAAK;GACX,KAAK;GACL,SAAS;GACT,GAAI,KAAK,iBAAiB,EAAE,gBAAgB,KAAK,eAAe,IAAI,CAAC;EACvE,CAAC;EACD,IAAI,OAAO,WAAW,YAAY,OAAO,WAAW,YAClD,MAAM,IAAI,MACR,8CAA8C,OAAO,OAAO,qBAAqB,OAAO,WAAW,4BACrG;EAEF,IAAI,OAAO,WAAW,oBACpB,MAAM,IAAI,MACR,gDAAgD,OAAO,YAAY,EAAE,GAAG,OAAO,YAAY,IAAI,wEAEjG;EAEF,OAAO;GAAE,SAAS;GAAM,QAAQ,OAAO,WAAW;EAAU;CAC9D,SAAS,OAAO;EAEd,KADqB,iBAAiB,gBAAgB,MAAM,OAAO,QACtD,qBACX,OAAO,EAAE,SAAS,KAAK;EAEzB,MAAM,oBAAoB,OAAO,KAAK,aAAa;CACrD;AACF;AAEA,SAAS,oBAAoB,OAAgB,eAA6C;CACxF,IAAI,EAAE,iBAAiB,gBAAgB,OAAO;CAC9C,MAAM,OAAe,MAAM;CAC3B,MAAM,UAAU,cAAc,aAC1B,yBAAyB,cAAc,WAAW,KAClD;CACJ,IAAI,iBAAiB,mBACnB,uBAAO,IAAI,MAAM,iDAAiD,SAAS;CAE7E,IAAI,iBAAiB,mBACnB,uBAAO,IAAI,MAAM,gCAAgC,SAAS;CAE5D,IAAI,SAAS,0BAA0B,SAAS,sBAAsB;EACpE,MAAM,SAAS,MAAM,UAAU,KAAK,MAAM,QAAQ,KAAK;EACvD,uBAAO,IAAI,MACT,oDAAoD,OAAO,eAAe,eAAe,aAAa,GACxG;CACF;CACA,IAAI,SAAS,qBAAqB,SAAS,gBACzC,uBAAO,IAAI,MACT,4FACF;CAEF,uBAAO,IAAI,MAAM,2BAA2B,KAAK,KAAK,MAAM,SAAS;AACvE"}