Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 57 additions & 1 deletion examples/docs/go-account-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
69 changes: 69 additions & 0 deletions examples/ts/go-account/go-account-whitelist-list.ts
Original file line number Diff line number Diff line change
@@ -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);
});
149 changes: 149 additions & 0 deletions examples/ts/go-account/go-account-whitelist-update.ts
Original file line number Diff line number Diff line change
@@ -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);
});