From afaf32651f6e37949dd97c0774142e30be8aebf5 Mon Sep 17 00:00:00 2001 From: Alia Aamir Date: Wed, 24 Jun 2026 18:09:13 -0400 Subject: [PATCH] docs(examples): add Go Account whitelist list and update scripts Add two new example scripts for managing Go Account address whitelists: - go-account-whitelist-list.ts: fetch and display all policy rules on a wallet - go-account-whitelist-update.ts: add or remove addresses from an advancedWhitelist policy Update go-account-workflows.md to document both scripts with usage examples. CAAS-1914 Co-Authored-By: Claude Sonnet 4.6 TICKET: CAAS-1914 --- examples/docs/go-account-workflows.md | 58 ++++++- .../go-account/go-account-whitelist-list.ts | 69 ++++++++ .../go-account/go-account-whitelist-update.ts | 149 ++++++++++++++++++ 3 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 examples/ts/go-account/go-account-whitelist-list.ts create mode 100644 examples/ts/go-account/go-account-whitelist-update.ts diff --git a/examples/docs/go-account-workflows.md b/examples/docs/go-account-workflows.md index 5e21e1838f..cbd79ec631 100644 --- a/examples/docs/go-account-workflows.md +++ b/examples/docs/go-account-workflows.md @@ -118,7 +118,54 @@ const approval = pendingApprovals.find((pa) => pa.state() === 'pending'); await approval.approve({ walletPassphrase, otp }); ``` -### 6. Sign Transaction — sign only (Step 2 of 3) +### 6. Go Account Whitelist List — view policy rules +**File:** `examples/ts/go-account/go-account-whitelist-list.ts` + +Fetches and displays all policy rules on a Go Account wallet, including existing whitelist policy IDs and their entries. + +**Best for:** +- Discovering the correct policy ID before running the update script +- Auditing which addresses are currently whitelisted + +**Example:** +```typescript +const wallet = await bitgo.coin('ofc').wallets().get({ id: walletId }); +const rules = wallet._wallet?.admin?.policy?.rules || []; +``` + +### 7. Go Account Whitelist Update — add or remove addresses +**File:** `examples/ts/go-account/go-account-whitelist-update.ts` + +Adds or removes an address from an existing `advancedWhitelist` policy rule on a Go Account wallet. + +**Best for:** +- Managing which destination addresses are permitted for withdrawals +- Automating whitelist maintenance via the BitGo API + +**Flow:** +``` +PUT /api/v2/ofc/wallet/{walletId}/policy/rule + → immediate: update applied + → approval required: pendingApproval ID returned +``` + +> **Note:** If approval is required, a second administrator must approve the pending change. Use `go-account-approve.ts` or the BitGo portal. + +**Example:** +```typescript +const body = { + id: 'Offchain Wallet Whitelist', + type: 'advancedWhitelist', + condition: { + add: { type: 'address', item: '0xabc...' }, + }, + action: { type: 'deny' }, +}; +const url = coin.url(`/wallet/${walletId}/policy/rule`); +const result = await bitgo.put(url).send(body).result(); +``` + +### 8. Sign Transaction — sign only (Step 2 of 3) **File:** `examples/ts/go-account/sign-transaction.ts` Signs a pre-built payload and outputs the hex signature. Use this when the build @@ -291,6 +338,15 @@ const usdtAddress = await wallet.createAddress({ # Sign only: sign a pre-built payload (Step 2 of 3) OFC_WALLET_ID=your_wallet_id OFC_WALLET_PASSPHRASE=your_passphrase OFC_PREBUILD_PAYLOAD='{"..."}' npx tsx sign-transaction.ts + + # List whitelist policy rules on a wallet + OFC_WALLET_ID=your_wallet_id npx tsx go-account-whitelist-list.ts + + # Add an address to the whitelist + OFC_WALLET_ID=your_wallet_id WHITELIST_ADDRESS=your_address WHITELIST_OPERATION=add npx tsx go-account-whitelist-update.ts + + # Remove an address from the whitelist + OFC_WALLET_ID=your_wallet_id WHITELIST_ADDRESS=your_address WHITELIST_OPERATION=remove npx tsx go-account-whitelist-update.ts ``` ## Supported Tokens diff --git a/examples/ts/go-account/go-account-whitelist-list.ts b/examples/ts/go-account/go-account-whitelist-list.ts new file mode 100644 index 0000000000..26ea01df99 --- /dev/null +++ b/examples/ts/go-account/go-account-whitelist-list.ts @@ -0,0 +1,69 @@ +/** + * Go Account Whitelist List + * + * Fetches and displays all policy rules on a Go Account wallet, + * including existing whitelist policy IDs and their whitelisted addresses. + * + * Use this to discover the correct policy ID before running + * go-account-whitelist-update.ts. + * + * Required environment variables (in examples/.env): + * TESTNET_ACCESS_TOKEN - your BitGo access token + * OFC_WALLET_ID - the wallet ID of your Go Account + * + * Copyright 2025, BitGo, Inc. All Rights Reserved. + */ + +import { BitGoAPI } from '@bitgo/sdk-api'; +import { coins } from 'bitgo'; +require('dotenv').config({ path: '../../../.env' }); + +const bitgo = new BitGoAPI({ + accessToken: process.env.TESTNET_ACCESS_TOKEN, + env: 'test', +}); + +const baseCoin = 'ofc'; +bitgo.register(baseCoin, coins.Ofc.createInstance); + +const walletId = process.env.OFC_WALLET_ID || 'your_wallet_id'; + +async function main() { + console.log('=== Go Account Whitelist List ===\n'); + + const wallet = await bitgo.coin(baseCoin).wallets().get({ id: walletId }); + const rules: any[] = (wallet._wallet as any)?.admin?.policy?.rules || []; + + if (rules.length === 0) { + console.log('No policy rules found on this wallet.'); + return; + } + + console.log(`Found ${rules.length} policy rule(s):\n`); + + for (const rule of rules) { + console.log(` ID : ${rule.id}`); + console.log(` Type : ${rule.type}`); + console.log(` Action : ${rule.action?.type}`); + + const items = rule.condition?.addresses || rule.condition?.items || []; + if (items.length > 0) { + console.log(` Whitelisted addresses (${items.length}):`); + for (const item of items) { + const addr = typeof item === 'string' ? item : item.item || item.address; + const label = item?.metaData?.label ? ` (${item.metaData.label})` : ''; + console.log(` - ${addr}${label}`); + } + } + + console.log(''); + } + + console.log('Full policy data:'); + console.log(JSON.stringify(rules, null, 2)); +} + +main().catch((e) => { + console.error('\n❌ Error listing whitelist policies:', e); + process.exit(1); +}); diff --git a/examples/ts/go-account/go-account-whitelist-update.ts b/examples/ts/go-account/go-account-whitelist-update.ts new file mode 100644 index 0000000000..0e0b7dad42 --- /dev/null +++ b/examples/ts/go-account/go-account-whitelist-update.ts @@ -0,0 +1,149 @@ +/** + * Go Account Whitelist Update + * + * Adds or removes an address from a Go Account wallet's advanced whitelist policy. + * + * The whitelist policy (type: "advancedWhitelist") restricts withdrawals to only + * pre-approved destination addresses. This script updates that list by either + * adding or removing a single address per run. + * + * Two possible outcomes after calling the API: + * A) No approval required — update takes effect immediately. + * B) Approval required — a pending approval is created; a second admin must + * approve it (see go-account-approve.ts). + * + * Note: Self-custody wallet whitelist policies lock 48 hours after creation. + * Contact support@bitgo.com to unlock a locked policy before updating. + * + * Required environment variables (in examples/.env): + * TESTNET_ACCESS_TOKEN - your BitGo access token + * OFC_WALLET_ID - the wallet ID of your Go Account + * + * Copyright 2025, BitGo, Inc. All Rights Reserved. + */ + +import { BitGoAPI } from '@bitgo/sdk-api'; +import { coins } from 'bitgo'; +require('dotenv').config({ path: '../../../.env' }); + +// Initialize BitGo SDK +const bitgo = new BitGoAPI({ + accessToken: process.env.TESTNET_ACCESS_TOKEN, + env: 'test', // Change to 'production' for mainnet +}); + +const baseCoin = 'ofc'; +bitgo.register(baseCoin, coins.Ofc.createInstance); + +// --------------------------------------------------------------------------- +// Configuration — update these values or set them as environment variables +// --------------------------------------------------------------------------- + +/** The wallet ID of your Go Account */ +const walletId = process.env.OFC_WALLET_ID || 'your_wallet_id'; + +/** + * The name/ID of the whitelist policy rule to update. + * This must match the `id` used when the policy was originally created. + */ +const policyId = process.env.WHITELIST_POLICY_ID || 'Offchain Wallet Whitelist'; + +/** + * The address to add or remove from the whitelist. + */ +const address = process.env.WHITELIST_ADDRESS || 'your_address_here'; + +/** + * Optional human-readable label for the address (only used when adding). + */ +const addressLabel = process.env.WHITELIST_ADDRESS_LABEL || ''; + +/** + * Operation: 'add' to whitelist the address, 'remove' to de-list it. + */ +const operation: 'add' | 'remove' = (process.env.WHITELIST_OPERATION as 'add' | 'remove') || 'add'; + +// --------------------------------------------------------------------------- + +async function main() { + console.log(`=== Go Account Whitelist Update (${operation.toUpperCase()}) ===\n`); + + const coin = bitgo.coin(baseCoin); + + // Build the condition object — shape is the same for add and remove; + // the key ('add' | 'remove') tells the API which operation to perform. + const conditionItem: { type: string; item: string; metaData?: { label: string } } = { + type: 'address', + item: address, + }; + if (operation === 'add' && addressLabel) { + conditionItem.metaData = { label: addressLabel }; + } + + const body = { + id: policyId, + type: 'advancedWhitelist', + condition: { + [operation]: conditionItem, + }, + action: { + type: 'deny', + }, + }; + + console.log(`Wallet ID : ${walletId}`); + console.log(`Policy ID : ${policyId}`); + console.log(`Operation : ${operation}`); + console.log(`Address : ${address}`); + if (addressLabel && operation === 'add') { + console.log(`Label : ${addressLabel}`); + } + console.log(''); + console.log('Sending whitelist update...'); + + const url = coin.url(`/wallet/${walletId}/policy/rule`); + const result = await (bitgo as any).put(url).send(body).result(); + + // Detect whether the response requires approval + if (result.pendingApproval) { + const approvalId = + typeof result.pendingApproval === 'string' ? result.pendingApproval : result.pendingApproval.id; + + console.log('\n⚠ Approval required before this change takes effect.'); + console.log(` A second administrator must approve pending approval: ${approvalId}`); + console.log(' Use go-account-approve.ts (or the BitGo portal) to approve it.\n'); + + console.log('Full response:'); + console.log(JSON.stringify(result, null, 2)); + + console.log('\n' + '='.repeat(60)); + console.log('WHITELIST UPDATE SUMMARY'); + console.log('='.repeat(60)); + console.log(` Wallet ID : ${walletId}`); + console.log(` Policy ID : ${policyId}`); + console.log(` Operation : ${operation}`); + console.log(` Address : ${address}`); + console.log(` Status : pending approval`); + console.log(` Pending Approval : ${approvalId}`); + console.log('='.repeat(60)); + } else { + console.log('✓ Whitelist updated successfully!\n'); + console.log('Full response:'); + console.log(JSON.stringify(result, null, 2)); + + console.log('\n' + '='.repeat(60)); + console.log('WHITELIST UPDATE SUMMARY'); + console.log('='.repeat(60)); + console.log(` Wallet ID : ${walletId}`); + console.log(` Policy ID : ${policyId}`); + console.log(` Operation : ${operation}`); + console.log(` Address : ${address}`); + console.log(` Status : applied`); + console.log('='.repeat(60)); + } +} + +main().catch((e) => { + console.error('\n❌ Error updating whitelist:', e); + process.exit(1); +});