Skip to content
Open
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
4 changes: 4 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,7 @@ WALLETCONNECT_SOLANA_DEVNET_RPC_URL=https://api.devnet.solana.com

# Set to "true" to actually send transactions (requires funded wallet)
# ACTUALLY_SEND=true

# Bermuda module
PLASMA_TESTNET_RPC_URL=https://testnet-rpc.plasma.to
WXPL_ADDRESS=0x6100e367285b01f48d07953803a2d8dca5d19873
2 changes: 1 addition & 1 deletion .github/workflows/typecheck.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
example: [wdk, wallet-evm, wallet-evm-erc-4337, wallet-solana, wallet-ton, wallet-tron, mcp-toolkit, walletconnect-walletkit]
example: [wdk, wallet-evm, wallet-evm-erc-4337, wallet-solana, wallet-ton, wallet-tron, wallet-bermuda, mcp-toolkit, walletconnect-walletkit]
steps:
- uses: actions/checkout@v4

Expand Down
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
foreground-scripts=true
ignore-scripts=false
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Each folder contains small runnable examples for one WDK package or integration.
| [wallet-solana](./wallet-solana/) | `@tetherto/wdk-wallet-solana` | Solana wallets, balances, transactions, SPL tokens, signing, and fees |
| [wallet-ton](./wallet-ton/) | `@tetherto/wdk-wallet-ton` | TON wallets, balances, transactions, Jettons, signing, and fees |
| [wallet-tron](./wallet-tron/) | `@tetherto/wdk-wallet-tron` | TRON wallets, balances, transactions, TRC20 tokens, signing, and fees |
| [wallet-bermuda](./wallet-bermuda/) | `@bermuda/wdk-wallet-bermuda` | Private accounts and transactions |
| [mcp-toolkit](./mcp-toolkit/) | `@tetherto/wdk-mcp-toolkit` | MCP server and LangChain agent examples for WDK tools |
| [walletconnect-walletkit](./walletconnect-walletkit/) | `@reown/walletkit` + WDK | Self-contained dApp ↔ wallet signing flow |

Expand Down
97 changes: 97 additions & 0 deletions scripts/postinstall.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
'use strict'

const fs = require('fs')
const { createRequire } = require('module')
const path = require('path')

// Resolve @bermuda/sdk build directory - handles npm hoisting.
let sdkBuildSrc
try {
const projectRequire = createRequire(path.join(process.cwd(), 'package.json'))
const entry = projectRequire.resolve('@bermuda/sdk')
const sdkRoot = path.resolve(entry, '..', '..', '..')
sdkBuildSrc = path.join(sdkRoot, 'build', 'src')
if (!fs.existsSync(sdkBuildSrc)) {
console.log('postinstall: @bermuda/sdk build/src not found, skipping')
process.exit(0)
}
} catch {
console.log('postinstall: @bermuda/sdk not resolved, skipping')
process.exit(0)
}

// --- utils.js patches ---
const utilsPath = path.join(sdkBuildSrc, 'utils.js')
let utils = fs.readFileSync(utilsPath, 'utf8')
let utilsChanged = false

// 1. fetchComplianceBlackList: graceful fallback on failure
if (!utils.includes('using empty blacklist')) {
const orig =
'async function ze(e){const t=`${e.replace(/\\/$/,"")}/blacklist`,' +
'n=await fetch(t);if(!n.ok)throw new Error(`Fetching compliance ' +
'blacklist failed with ${n.status}`);return await n.json()}'
const fix =
'async function ze(e){const t=`${e.replace(/\\/$/,"")}/blacklist`;' +
'try{const n=await fetch(t);if(!n.ok)throw new Error(`Fetching ' +
'compliance blacklist failed with ${n.status}`);return await n.json()' +
'}catch(n){return console.warn(`fetchComplianceBlackList: ${n.message}' +
' \\u2013 using empty blacklist`),{blacklist:[]}}}'
if (utils.includes(orig)) {
utils = utils.replace(orig, fix)
utilsChanged = true
console.log('postinstall: patched fetchComplianceBlackList fallback')
}
}

// 2. queryFilterBatched: 200ms throttle between batches
if (!utils.includes('setTimeout(w,200)')) {
const orig =
'if(s=[...s,...u],i+=o,i>=t)break}return s}'
const fix =
'if(s=[...s,...u],i+=o,i>=t)break;' +
'await new Promise(w=>setTimeout(w,200))}return s}'
if (utils.includes(orig)) {
utils = utils.replace(orig, fix)
utilsChanged = true
console.log('postinstall: patched queryFilterBatched throttle')
}
}

if (utilsChanged) fs.writeFileSync(utilsPath, utils)

// --- find-utxos.js patch ---
const fuPath = path.join(sdkBuildSrc, 'find-utxos.js')
let fu = fs.readFileSync(fuPath, 'utf8')

// 3. findUtxos: sequential isSpent instead of Promise.all burst
if (!fu.includes('for(const n of w.events)')) {
const orig =
'const b=await Promise.all(w.events.map(async n=>{let e;' +
'try{e=(await F.decrypt(S,n.encryptedOutput,BigInt(n.index),x)).utxo}' +
'catch{}if(e){if(e.amount.toString()==="0")return null;' +
'const s=v(e.token).toLowerCase();' +
'if(D&&!e.keypair.privkey)return null;' +
'if(B){const t=await e.getNullifier().then(i=>v(i,32));' +
'if(await f.isSpent(t))return null}' +
'return[s,e]}else return null}))' +
'.then(n=>n.filter(Boolean))' +
'.then(n=>n.reduce((e,[s,t])=>' +
'(Array.isArray(e[s])?e[s].push(t):e[s]=[t],e),{}))'
const fix =
'const b=await(async()=>{const _r=[];for(const n of w.events){let e;' +
'try{e=(await F.decrypt(S,n.encryptedOutput,BigInt(n.index),x)).utxo}' +
'catch{}if(e){if(e.amount.toString()==="0")continue;' +
'const s=v(e.token).toLowerCase();' +
'if(D&&!e.keypair.privkey)continue;' +
'if(B){const t=await e.getNullifier().then(i=>v(i,32));' +
'if(await f.isSpent(t))continue}' +
'_r.push([s,e])}}' +
'return _r.reduce((e,[s,t])=>' +
'(Array.isArray(e[s])?e[s].push(t):e[s]=[t],e),{})})()'
if (fu.includes(orig)) {
fu = fu.replace(orig, fix)
fs.writeFileSync(fuPath, fu)
console.log('postinstall: patched findUtxos sequential isSpent')
}
}
9 changes: 9 additions & 0 deletions shared/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,12 @@ export function loadWdkConfig() {
tron,
}
}

export function loadBermudaConfig() {
return {
seedPhrase: requireEnv('SEED_PHRASE'),
rpcUrl: requireEnv('PLASMA_TESTNET_RPC_URL'),
tokenContract: requireEnv('WXPL_ADDRESS'),
recipientAddress: requireEnv('EVM_RECIPIENT_ADDRESS'),
}
}
40 changes: 40 additions & 0 deletions wallet-bermuda/check-balances.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Bermuda Example: Check Balances
*
* Demonstrates: Querying shielded ERC-20 token balances for an owned account.
*
* Run: npx tsx wallet-bermuda/check-balances.ts
*/

import WalletManagerBermuda from '@bermuda/wdk-wallet-bermuda'
import { loadBermudaConfig } from '../shared/config.js'
import { logSection, logResult } from '../shared/helpers.js'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
import fs from 'node:fs'

async function main() {
const config = loadBermudaConfig()

logSection('Check Balances')

const wallet = new WalletManagerBermuda(config.seedPhrase, {
provider: config.rpcUrl,
utxoCache: join(tmpdir(), 'wdk-wallet-bermuda-examples-utxo-cache.json'),
fs
})

const account = await wallet.getBermudaAccount()
logResult('Bermuda account', { address: account.address })

const tokenBalance = await account.getTokenBalance(config.tokenContract)
logResult('Shielded ERC-20 token balance', {
token: config.tokenContract,
balance: `${tokenBalance} (base units)`,
})

wallet.dispose()
console.log('\nDone.')
}

main().then(() => process.exit(0))
30 changes: 30 additions & 0 deletions wallet-bermuda/create-wallet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**
* Bermuda Example: Create Wallet
*
* Demonstrates: Initializing a WalletManagerBermuda, and deriving the default
* Bermuda account.
*
* Run: npx tsx wallet-bermuda/create-wallet.ts
*/

import WalletManagerBermuda from '@bermuda/wdk-wallet-bermuda'
import { loadBermudaConfig } from '../shared/config.js'
import { logSection, logResult } from '../shared/helpers.js'

async function main() {
const config = loadBermudaConfig()

logSection('Create Wallet')

const wallet = new WalletManagerBermuda(config.seedPhrase, {
provider: config.rpcUrl,
})

const account00 = await wallet.getBermudaAccount()
logResult('Default Bermuda account', { address: account00.address })

wallet.dispose()
console.log('\nDone.')
}

main().then(() => process.exit(0))
40 changes: 40 additions & 0 deletions wallet-bermuda/deposit.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Bermuda Example: Fund a Bermuda account.
*
* Run: npx tsx wallet-bermuda/deposit.ts
*/

import WalletManagerBermuda from '@bermuda/wdk-wallet-bermuda'
import { loadBermudaConfig } from '../shared/config.js'
import { logSection, logResult } from '../shared/helpers.js'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
import fs from 'node:fs'

async function main() {
const config = loadBermudaConfig()

logSection('Deposit')

const wallet = new WalletManagerBermuda(config.seedPhrase, {
provider: config.rpcUrl,
utxoCache: join(tmpdir(), 'wdk-wallet-bermuda-examples-utxo-cache.json'),
fs
})

const account = await wallet.getBermudaAccount()

// Funds the Bermuda account itself by default. You can set params.to to
// designate a different deposit recipient or params.recipients for multiple
// recipients.
const txHash = await account.deposit({
token: config.tokenContract,
amount: 100n
})
logResult('Transaction Sent', { hash: txHash })

wallet.dispose()
console.log('\nDone.')
}

main().then(() => process.exit(0))
35 changes: 35 additions & 0 deletions wallet-bermuda/manage-accounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* Bermuda Example: Manage Accounts
*
* Demonstrates: Deriving multiple Bermuda accounts by custom BIP-44/Bermuda
* account indices.
*
* Run: npx tsx wallet-bermuda/manage-accounts.ts
*/

import WalletManagerBermuda from '@bermuda/wdk-wallet-bermuda'
import { loadBermudaConfig } from '../shared/config.js'
import { logSection, logResult } from '../shared/helpers.js'

async function main() {
const config = loadBermudaConfig()

logSection('Manage Multiple Accounts')

const wallet = new WalletManagerBermuda(config.seedPhrase, {
provider: config.rpcUrl,
})

const defaultAccount = await wallet.getBermudaAccount()
const account00 = await wallet.getBermudaAccount(0, 0)
const account01 = await wallet.getBermudaAccount(0, 1)

logResult('Default Bermuda account', { address: defaultAccount.address })
logResult('Bermuda account 00', { address: account00.address })
logResult('Bermuda account 01', { address: account01.address })

wallet.dispose()
console.log('\nDone.')
}

main().then(() => process.exit(0))
Loading