{"id":45597632,"url":"https://github.com/pi314x/bitshares-wallet-browser-extension","last_synced_at":"2026-03-08T09:06:11.749Z","repository":{"id":339748972,"uuid":"1162423222","full_name":"pi314x/bitshares-wallet-browser-extension","owner":"pi314x","description":"A browser extension for BitShares","archived":false,"fork":false,"pushed_at":"2026-02-25T17:34:12.000Z","size":373,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-02-25T17:47:01.564Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://pi314x.github.io/bitshares-wallet-browser-extension/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pi314x.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-20T08:44:07.000Z","updated_at":"2026-02-25T17:33:38.000Z","dependencies_parsed_at":"2026-02-23T14:02:37.091Z","dependency_job_id":null,"html_url":"https://github.com/pi314x/bitshares-wallet-browser-extension","commit_stats":null,"previous_names":["pi314x/bitshares-wallet-extension","pi314x/bitshares-wallet-browser-extension"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/pi314x/bitshares-wallet-browser-extension","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pi314x%2Fbitshares-wallet-browser-extension","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pi314x%2Fbitshares-wallet-browser-extension/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pi314x%2Fbitshares-wallet-browser-extension/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pi314x%2Fbitshares-wallet-browser-extension/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pi314x","download_url":"https://codeload.github.com/pi314x/bitshares-wallet-browser-extension/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pi314x%2Fbitshares-wallet-browser-extension/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29865409,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T16:38:37.846Z","status":"ssl_error","status_checked_at":"2026-02-26T16:37:58.932Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-02-23T14:00:59.764Z","updated_at":"2026-03-08T09:06:11.714Z","avatar_url":"https://github.com/pi314x.png","language":"JavaScript","funding_links":[],"categories":["Utilities"],"sub_categories":["Opensource Wallets"],"readme":"# BitShares Wallet Browser Extension\n\nA secure browser extension for the BitShares blockchain - similar to MetaMask but for BitShares DEX. Supports Chrome, Brave, and Firefox.\n\n![BitShares Wallet](./src/assets/icons/icon.svg)\n\n## Features\n\n### Wallet Management\n- Create new wallet with password-protected brainkey\n- Import existing wallets via:\n  - Account name + password (keys verified against chain before import)\n  - Brainkey phrase\n  - WIF private keys\n  - Premium / non-standard account names supported on import\n- Secure AES-256-GCM encryption\n- Auto-lock functionality (configurable timer or disabled)\n- Backup brainkey for recovery\n- Multi-account support with watch-only accounts\n\n### Asset Management\n- View BTS and all BitShares assets\n- Real-time balance updates\n- USD value display with market prices\n- Full transaction history with filtering\n- QR code generation for receiving\n\n### Transactions\n- Send BTS and other assets\n- Recipient account validation\n- Optional encrypted memos\n- Transaction fee calculation\n- Confirmation modal for all transactions\n\n### Full Operation Signing (All 75 BitShares Operations)\n\nThe wallet supports signing all 75 BitShares blockchain operation types, not just transfers. Every operation shows a human-readable confirmation dialog before signing.\n\n#### Supported Operation Categories\n\n| Category | Operations |\n|----------|-----------|\n| Account | account_create, account_update, account_upgrade, account_whitelist, account_transfer |\n| Assets | asset_create, asset_update, asset_update_bitasset, asset_update_feed_producers, asset_issue, asset_reserve, asset_fund_fee_pool, asset_settle, asset_global_settle, asset_publish_feed, asset_claim_fees, asset_update_issuer, asset_claim_pool |\n| Trading (DEX) | limit_order_create, limit_order_cancel, call_order_update, fill_order, bid_collateral, execute_bid |\n| Transfers | transfer, transfer_to_blind, transfer_from_blind, blind_transfer, override_transfer, balance_claim, asset_settle_cancel |\n| Proposals | proposal_create, proposal_update, proposal_delete |\n| Witnesses | witness_create, witness_update |\n| Committee | committee_member_create, committee_member_update, committee_member_update_global_parameters |\n| Workers | worker_create |\n| Vesting | vesting_balance_create, vesting_balance_withdraw |\n| Withdraw Permissions | withdraw_permission_create, withdraw_permission_update, withdraw_permission_claim, withdraw_permission_delete |\n| Custom / Misc | custom, assert, fba_distribute |\n| Liquidity Pools | liquidity_pool_create, liquidity_pool_delete, liquidity_pool_deposit, liquidity_pool_withdraw, liquidity_pool_exchange |\n| Tickets | ticket_create, ticket_update |\n| HTLC | htlc_create, htlc_redeem, htlc_redeemed, htlc_extend, htlc_refund |\n| Custom Authority | custom_authority_create, custom_authority_update, custom_authority_delete |\n| Credit | credit_offer_create, credit_offer_delete, credit_offer_update, credit_offer_accept, credit_deal_repay, credit_deal_expired |\n| Samet Fund | samet_fund_create, samet_fund_delete, samet_fund_update, samet_fund_borrow, samet_fund_repay |\n\n#### Human-Readable Operation Display\n\nThe signing confirmation dialog renders each operation in a readable format with clearly labeled fields. For example:\n\n- **Transfer**: Shows From / To / Amount / Memo\n- **Limit Order Create**: Shows Account / Sell Amount / Buy Amount / Expiration\n- **Account Create**: Shows Name / Registrar / Referrer / Keys\n- **Asset Create**: Shows Symbol / Precision / Max Supply / Issuer\n\nUnknown or future operations gracefully fall back to a formatted JSON display.\n\n### dApp Integration\n- Connect to BitShares dApps\n- Sign transactions for connected sites\n- Manage site permissions\n- BeetEOS/Scatter API compatibility\n- Event-based communication\n\n### Network Support\n- **BitShares Mainnet** and **BitShares Testnet** selectable at any point\n  - Network selector on the welcome screen (before wallet creation or import)\n  - Network selector on the dashboard\n  - Network persisted across popup sessions\n- Network-aware nodes, faucet URLs, and key prefixes (`BTS` / `TEST`)\n- Service worker stays in sync with the popup network — `ensureConnected()` reconnects to the stored network before every dApp request\n\n### Settings\n- Auto-lock timer configuration\n- Network selection (Mainnet/Testnet)\n- Custom node configuration per network\n- Connected sites management\n- Change wallet password\n- Retrieve private keys (watch-only accounts clearly identified)\n\n## Testing\n\nThe extension includes a Jest test suite (73 tests) covering the core cryptographic and wallet management logic.\n\n### Running Tests\n\n```bash\nnpm test\n```\n\n### Test Coverage\n\n#### `tests/crypto-utils.test.js`\nTests for `src/lib/crypto-utils.js`:\n\n| Function | Tests |\n|----------|-------|\n| `generateBrainkey()` | Returns string, 16 words, uppercase, non-deterministic |\n| `normalizeBrainkey()` | Trims whitespace, normalizes case, handles edge cases |\n| `generateKeysFromBrainkey()` | Returns active/owner/memo keys |\n| `generateKeysFromPassword()` | Returns keys from account + password |\n| `deriveKey()` | PBKDF2 derivation produces correct-length key |\n| `encrypt()` + `decrypt()` | Round-trip encryption/decryption |\n| `generateSalt()` | Produces non-empty, unique salts |\n| Edge cases | Null/empty inputs, malformed data |\n\n#### `tests/wallet-manager.test.js`\nTests for `src/lib/wallet-manager.js`:\n\n| Function | Tests |\n|----------|-------|\n| `hasWallet()` | False when empty, true after save, false after clear |\n| `createWallet()` | Resolves true, stores wallet, correct structure, unlocked on creation, brainkey encrypted |\n| `unlock()` | True with correct password, false with wrong, state changes, decryptedKeys populated |\n| `lock()` | Clears state, clears keys, idempotent, re-unlock works, sends WALLET_LOCKED message |\n| `isUnlocked()` | Reflects locked/unlocked state accurately |\n\n#### Test Infrastructure\n\n- **Mocks**: `tests/__mocks__/chrome.js` — in-memory `chrome.storage.local` mock with `__resetStorage()` helper\n- **Mocks**: `tests/__mocks__/bitshares-api.js` — stub for BitShares API calls\n- **Timer cleanup**: `afterAll()` calls `jest.clearAllTimers()` to prevent open handle warnings from auto-lock timers\n- **State isolation**: Each test resets storage via `resetStorage()` and tears down manager state via `silentLock()`\n\n## Browser Support\n\n| Browser | Status | Manifest |\n|---------|--------|----------|\n| Chrome  | Supported | MV3 |\n| Brave   | Supported | MV3 (same as Chrome) |\n| Firefox | Supported | MV2 |\n\n## Installation\n\n### From Release\n\n1. Download the latest release zip for your browser from [Releases](https://github.com/pi314x/bitshares-wallet-browser-extension/releases)\n2. Follow the browser-specific instructions below\n\n### Chrome / Brave\n\n1. Open `chrome://extensions/` (or `brave://extensions/`)\n2. Enable \"Developer mode\" (toggle in top right)\n3. Click \"Load unpacked\"\n4. Select the extracted `dist` folder\n\n### Firefox\n\n1. Open `about:debugging#/runtime/this-firefox`\n2. Click \"Load Temporary Add-on\"\n3. Select any file inside the extracted `dist-firefox` folder\n\n### Build from Source\n\n```bash\ngit clone https://github.com/pi314x/bitshares-wallet-browser-extension.git\ncd bitshares-wallet-browser-extension\n```\n\n```bash\n# Chrome / Brave\nnpm run build\n\n# Firefox\nnpm run build:firefox\n\n# Both\nnpm run build:all\n```\n\nOutput goes to `dist/` (Chrome/Brave) and `dist-firefox/` (Firefox).\n\n## Project Structure\n\n```\nbitshares-wallet-browser-extension/\n├── manifest.json              # Chrome/Brave manifest (MV3)\n├── manifest.firefox.json      # Firefox manifest (MV2)\n├── package.json\n├── scripts/\n│   └── build.js               # Build script (chrome/firefox/all)\n├── docs/\n│   └── index.html             # GitHub Pages website\n├── .github/\n│   └── workflows/\n│       └── release.yml        # Auto-build \u0026 release on tag push\n├── src/\n│   ├── assets/\n│   │   └── icons/             # Extension icons (16, 32, 48, 128px)\n│   ├── background/\n│   │   ├── service-worker.js  # Background service worker\n│   │   └── background-firefox.html  # Firefox background page\n│   ├── content/\n│   │   ├── inject.js          # Content script injector\n│   │   └── inpage.js          # Page-context provider API\n│   ├── lib/\n│   │   ├── bitshares-api.js   # BitShares blockchain API\n│   │   ├── crypto-utils.js    # Cryptographic utilities\n│   │   ├── identicon.js       # Account identicon generator\n│   │   ├── qr-generator.js    # QR code generator\n│   │   └── wallet-manager.js  # Wallet state management\n│   └── popup/\n│       ├── popup.html         # Main popup UI\n│       ├── popup.css          # Styling\n│       └── popup.js           # Popup logic (operation signing + display)\n├── tests/\n│   ├── __mocks__/\n│   │   ├── chrome.js          # chrome.storage.local / runtime mock\n│   │   └── bitshares-api.js   # BitShares API stub\n│   ├── crypto-utils.test.js   # Tests for CryptoUtils\n│   └── wallet-manager.test.js # Tests for WalletManager\n├── dist/                      # Chrome/Brave build output\n└── dist-firefox/              # Firefox build output\n```\n\n## API for dApp Developers\n\n### Detecting the Wallet\n\n```javascript\n// Wait for wallet to be ready\nwindow.addEventListener('bitsharesWalletReady', (event) =\u003e {\n  const provider = event.detail.provider;\n  console.log('BitShares Wallet detected!');\n});\n\n// Or check directly\nif (window.bitsharesWallet) {\n  console.log('BitShares Wallet is available');\n}\n```\n\n### Connecting to the Wallet\n\n```javascript\n// Connect — prompts the user to approve your site.\n// Returns the active account and its balances.\nconst { account, balances } = await window.bitsharesWallet.connect();\nconsole.log('Connected:', account.name, account.id);\nconsole.log('Balances:', balances);\n// balances: [{ asset_id: '1.3.0', amount: 123456, symbol: 'BTS', precision: 5 }, ...]\n```\n\n#### Checking / Restoring an Existing Connection\n\nIf the user already approved your site in a previous session, you can\nsilently restore the connection without showing a popup:\n\n```javascript\nconst { connected, account } = await window.bitsharesWallet.checkConnection();\nif (connected) {\n  console.log('Already connected as', account.name);\n} else {\n  // Not yet approved — call connect() to prompt the user\n  const { account, balances } = await window.bitsharesWallet.connect();\n}\n```\n\n#### Verifying the Chain ID\n\nAlways verify the chain ID before submitting transactions to make sure\nthe wallet is connected to the expected network:\n\n```javascript\nconst chainId = await window.bitsharesWallet.getChainId();\n\n// BitShares Mainnet\nconst BTS_MAINNET = '4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8';\n// BitShares Testnet\nconst BTS_TESTNET = '39f5e2ede1f8bc1a3a54a7914414e3779e33193f1f5693510e73cb7a87617447';\n\nif (chainId !== BTS_MAINNET) {\n  throw new Error('Please switch to BitShares Mainnet');\n}\n```\n\n**Tip:** Pass `chain_id` directly in the `connect()` call so the extension\nrejects the connection immediately if the user is on the wrong network:\n\n```javascript\nconst { account, balances } = await window.bitsharesWallet.connect({\n  chain_id: BTS_TESTNET   // connection is rejected if wallet is not on testnet\n});\n```\n\n#### Disconnecting\n\n```javascript\nawait window.bitsharesWallet.disconnect();\n// window.bitsharesWallet.isConnected is now false\n```\n\n### Getting Account Information\n\n```javascript\nconst account = await window.bitsharesWallet.getAccount();\nconsole.log('Account name:', account.name);\nconsole.log('Account ID:', account.id);\n```\n\n### Signing \u0026 Broadcasting Transactions\n\n`signTransaction` signs **and** broadcasts the transaction in one call.\nThe wallet fills required fees, resolves account names / asset symbols\nto object IDs, refreshes block headers, signs with the user's active\nkey, and broadcasts to the network.\n\nEach operation triggers a human-readable confirmation dialog in the\nextension popup. The user has **2 minutes** to approve or reject before\nthe request times out.\n\n```javascript\n// Transfer (operation type 0)\nconst result = await window.bitsharesWallet.signTransaction({\n  operations: [\n    [0, {\n      fee: { amount: 0, asset_id: '1.3.0' },\n      from: account.id,         // or account name, e.g. 'my-account'\n      to: '1.2.yyyyy',          // or account name\n      amount: { amount: 100000, asset_id: '1.3.0' },\n      memo: { message: 'hello' } // optional — plain text, hex, or full memo_data\n    }]\n  ]\n});\n// result: { success: true, result: \u003cbroadcast callback result\u003e }\n// or:     { success: false, error: 'User rejected transaction' }\n```\n\n```javascript\n// Limit Order (operation type 1)\nconst orderResult = await window.bitsharesWallet.signTransaction({\n  operations: [\n    [1, {\n      fee: { amount: 0, asset_id: '1.3.0' },\n      seller: account.id,\n      amount_to_sell: { amount: 500000, asset_id: '1.3.0' },\n      min_to_receive: { amount: 1000, asset_id: '1.3.861' },\n      expiration: '2026-12-31T00:00:00'\n    }]\n  ]\n});\n```\n\n\u003e **Notes**\n\u003e - `fee` can be `{ amount: 0, asset_id: '1.3.0' }` — the wallet fills the real fee.\n\u003e - Account fields (`from`, `to`, `seller`, …) accept either object IDs (`1.2.xxxxx`) or account names (`my-account`).\n\u003e - Asset fields accept either object IDs (`1.3.0`) or symbols (`BTS`).\n\u003e - Multi-operation transactions are supported — each operation is shown as a separate labeled section in the confirmation dialog.\n\n### Transfers (Convenience Method)\n\n```javascript\nconst result = await window.bitsharesWallet.transfer({\n  to: 'recipient-name',\n  amount: { amount: 100000, asset_id: '1.3.0' },\n  memo: 'Thanks!'\n});\n```\n\n### Event Listeners\n\n```javascript\n// Listen for account changes (user switches active account)\nwindow.bitsharesWallet.on('accountChanged', (account) =\u003e {\n  console.log('Account changed to:', account.name);\n});\n\n// Listen for lock events\nwindow.bitsharesWallet.on('locked', () =\u003e {\n  console.log('Wallet was locked');\n});\n\n// Listen for unlock events\nwindow.bitsharesWallet.on('unlocked', () =\u003e {\n  console.log('Wallet was unlocked');\n});\n\n// Remove a specific listener\nwindow.bitsharesWallet.off('accountChanged', myHandler);\n\n// Remove all listeners for an event\nwindow.bitsharesWallet.removeAllListeners('accountChanged');\n```\n\n### BeetEOS Compatibility\n\nThe wallet also exposes `window.beet` and `window.scatter` for\ncompatibility with existing BeetEOS / Scatter dApps:\n\n```javascript\n// Using Beet-style API\nconst identity = await window.beet.requestIdentity();\nconsole.log('Account:', identity.accounts[0].name);\n\n// Sign transaction\nconst result = await window.beet.requestSignature({\n  transaction: myTransaction\n});\n\n// Disconnect\nawait window.beet.forgetIdentity();\n```\n\n## Security\n\n- **Private keys** are encrypted using AES-256-GCM with PBKDF2-derived keys\n- **Brainkey** is never stored unencrypted\n- **Session storage** is used for temporary unlock state (cleared when browser closes)\n- **Auto-lock** prevents unauthorized access after inactivity\n- **dApp connections** require explicit user approval\n- **All transactions** must be confirmed in the popup with human-readable operation details\n\n### Best Practices\n\n1. Always backup your brainkey in a secure location\n2. Use a strong wallet password\n3. Enable auto-lock with a short timer\n4. Review transaction details before confirming\n5. Only connect to trusted dApps\n6. Disconnect from sites when not in use\n\n## BitShares Network\n\n### Mainnet Nodes\n- `wss://node.xbts.io/ws`\n- `wss://cloud.xbts.io/ws`\n- `wss://public.xbts.io/ws`\n- `wss://btsws.roelandp.nl/ws`\n- `wss://dex.iobanker.com/ws`\n- `wss://api.bitshares.dev/ws`\n\n### Testnet Nodes\n- `wss://testnet.xbts.io/ws`\n- `wss://testnet.dex.trading/`\n\n### Chain IDs\n| Network | Chain ID |\n|---------|----------|\n| Mainnet | `4018d7844c78f6a6c41c6a552b898022310fc5dec06da467ee7905a8dad512c8` |\n| Testnet | `39f5e2ede1f8bc1a3a54a7914414e3779e33193f1f5693510e73cb7a87617447` |\n\n## Building for Distribution\n\n```bash\nnpm run build:all\n```\n\nOn tag push (`git tag v1.0.0 \u0026\u0026 git push origin v1.0.0`), GitHub Actions automatically builds and creates a release with both browser zips attached.\n\n## Contributing\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n## License\n\nMIT License - see [LICENSE](LICENSE) file for details.\n\n## Acknowledgments\n\n- Inspired by [BeetEOS](https://github.com/beetapp/beeteos)\n- Based on [MetaMask](https://metamask.io/) UX patterns\n- BitShares community and developers\n\n## Website\n\nThe project website is hosted on GitHub Pages from the `docs/` folder:\n\n**[https://pi314x.github.io/bitshares-wallet-browser-extension](https://pi314x.github.io/bitshares-wallet-browser-extension)**\n\nTo deploy changes, push to the `main` branch. GitHub Pages serves from `Settings \u003e Pages \u003e Source: main branch, /docs folder`.\n\n## Support\n\n- **Website**: [pi314x.github.io/bitshares-wallet-browser-extension](https://pi314x.github.io/bitshares-wallet-browser-extension)\n- **Telegram**: [BitShares DEV](https://t.me/BitSharesDEV)\n- **GitHub Issues**: [Report bugs](https://github.com/pi314x/bitshares-wallet-browser-extension/issues)\n- **BitShares Forum**: [bitsharestalk.org](https://bitsharestalk.org)\n\n---\n\n**Security Notice**: Never share your brainkey or private keys. This wallet stores keys locally on your device only. Always verify you're using the official extension.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpi314x%2Fbitshares-wallet-browser-extension","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpi314x%2Fbitshares-wallet-browser-extension","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpi314x%2Fbitshares-wallet-browser-extension/lists"}