{"id":26788262,"url":"https://github.com/qedprotocol/doge-sdk","last_synced_at":"2025-04-19T20:51:09.799Z","repository":{"id":245777641,"uuid":"819201487","full_name":"QEDProtocol/doge-sdk","owner":"QEDProtocol","description":"🐶 very lightweight dogecoin library, wow ✨ only 20kb gzipped， such node and browser support","archived":false,"fork":false,"pushed_at":"2025-03-08T01:12:01.000Z","size":320,"stargazers_count":12,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-08T01:16:04.288Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","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/QEDProtocol.png","metadata":{"files":{"readme":"README.md","changelog":null,"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}},"created_at":"2024-06-24T03:26:43.000Z","updated_at":"2025-03-08T01:11:53.000Z","dependencies_parsed_at":"2024-06-24T04:39:26.247Z","dependency_job_id":"3533c381-5f50-4342-b422-aec9e7c4907a","html_url":"https://github.com/QEDProtocol/doge-sdk","commit_stats":null,"previous_names":["qedprotocol/doge-sdk"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QEDProtocol%2Fdoge-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QEDProtocol%2Fdoge-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QEDProtocol%2Fdoge-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/QEDProtocol%2Fdoge-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/QEDProtocol","download_url":"https://codeload.github.com/QEDProtocol/doge-sdk/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246187227,"owners_count":20737463,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":"2025-03-29T13:16:39.066Z","updated_at":"2025-03-29T13:16:39.645Z","avatar_url":"https://github.com/QEDProtocol.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ca name=\"readme-top\"\u003e\u003c/a\u003e\n[![Contributors][contributors-shield]][contributors-url]\n[![Forks][forks-shield]][forks-url]\n[![Stargazers][stars-shield]][stars-url]\n[![Issues][issues-shield]][issues-url]\n\n\n\u003c!-- PROJECT LOGO --\u003e\n\u003cbr /\u003e\n\u003cdiv align=\"center\"\u003e\n  \u003ca href=\"https://github.com/QEDProtocol/doge-sdk\"\u003e\n  \u003cimg width=\"256\" height=\"256\" src=\"https://github.com/QEDProtocol/doge-sdk/raw/main/docs/static/doge-sdk-logo.png?raw=true\"\u003e\n  \u003c/a\u003e\n\n  \u003ch2 align=\"center\"\u003edoge-sdk\u003c/h2\u003e\n  \u003cp align=\"center\"\u003e\nAn ultra lightweight (24kb gzipped) doge library for Node.js and the Browser with only 1 dependency.\n  \u003c/p\u003e\n  \u003cp align=\"center\"\u003e\n    Made with ❤️ by \u003ca href=\"https://qedprotocol.com\"\u003eQED\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\n## Features\n* Works out of the box in Node and the Browser without any polyfills\n* only 24kb gzipped ✨\n* Support for both P2PKH and P2SH transactions\n* Built in Memory Wallet + Support for Hardware Wallets (ledger, trezor, etc.)\n* Does not depend on bitcoinjs-lib (no need for a megabyte of nodejs polyfills and global scope pollution)\n* Only has pinned one dependency, [@qed-noble/secp256k1](https://github.com/QEDProtocol/noble-secp256k1) which is only 4kb, and has already been [audited](https://cure53.de/pentest-report_noble-lib.pdf).\n* Compiler/Assembler for BASM and standard bitcoin assembly\n\n\n## Installation\n```bash\nnpm install doge-sdk\n```\n\n## Usage\n\n### P2PKH\n```typescript\nimport { DogeLinkRPC, DogeMemoryWalletProvider, createP2PKHTransaction } from \"doge-sdk\";\n\nasync function exampleP2PKH(){\n  // networkId can be doge, dogeTestnet, or dogeRegtest\n  const networkId = \"dogeRegtest\";\n\n  // your dogecoin rpc node url, with an added query equal to doge, dogeTestnet, or dogeRegtest\n  const RPC_API_URL = \"http://devnet:devnet@localhost:1337/bitcoin-rpc/?network=\"+networkId;\n\n  const rpc = new DogeLinkRPC(RPC_API_URL);\n\n  // wallet provider, in this case an in-memory wallet provider\n  const walletProvider = new DogeMemoryWalletProvider();\n\n  // create a random dogecoin P2PKH wallet\n  const wallet1 = walletProvider.addRandomWallet(networkId);\n  console.log(\"wallet 1 address: \", wallet1.address);\n\n  // import a wallet from WIF\n  const wallet2 = walletProvider.addWalletFromWIF(\"cN1CE8kQ3QADHeumGSVvMBNaqMZUyNnKmURqEryYzNDorB7xRRab\");\n  console.log(\"wallet 2 address: \", wallet2.address);\n\n  // in dogeRegtest, we can faucet tokens to any address we like after mining some blocks\n  await rpc.mineBlocks(200);\n  // faucet 10 DOGE to the wallet\n  const faucetTxid = await rpc.sendFromWallet(wallet1.address, 10);\n\n  // send 9.5 DOGE from wallet1 to wallet2\n  // get the funding transaction\n  const faucetFundingTx = await rpc.getTransaction(faucetTxid);\n  // get the unspent transaction output for wallet 1\n  const faucetUTXO = faucetFundingTx.getUTXOsForAddress(wallet1.address)[0];\n  // create a transaction which sends 9.5 DOGE from wallet1 to wallet2\n  const txBuilder = createP2PKHTransaction(wallet1, {\n    inputs: [faucetUTXO],\n    outputs: [{address: wallet2.address, value: 900_500_000}],\n    address: wallet1.address,\n  });\n\n  // sign the transaction\n  const finalizedTx = await txBuilder.finalizeAndSign();\n\n  // broadcast the transaction\n  const txid = await rpc.sendRawTransaction(finalizedTx.toHex());\n  console.log(\"transaction id: \", txid);\n}\n```\n\n### Simple P2SH Puzzle\n```typescript\nimport { DogeLinkRPC, DogeMemoryWalletProvider, createP2SHTransaction, getP2SHAddress } from \"doge-sdk\";\n\nasync function exampleP2SH(){\n  // networkId can be doge, dogeTestnet, or dogeRegtest\n  const networkId = \"dogeRegtest\";\n\n  // note: if you don't have an RPC node, you can start one up with docker:\n  // docker run -p 1337:1337 -it --rm qedprotocol/bitide-doge:latest\n\n  // your dogecoin rpc node url, with an added query equal to doge, dogeTestnet, or dogeRegtest\n  const RPC_API_URL = \"http://devnet:devnet@localhost:1337/bitcoin-rpc/?network=\"+networkId;\n\n  const rpc = new DogeLinkRPC(RPC_API_URL);\n\n  // a simple puzzle utxo that can be unlocked by solving the equation x + 5 = 7\n  const REDEEM_SCRIPT = `\n    \u003c5\u003e\n    OP_ADD\n    \u003c7\u003e\n    OP_EQUAL\n  `;\n\n  // the unlock script that solves the equation x + 5 = 7, where x = 2\n  const UNLOCK_SCRIPT = `\n    \u003c2\u003e\n  `;\n\n  // compute the pay-to-script-hash address for our puzzle\n  const p2shAddress = getP2SHAddress(REDEEM_SCRIPT, networkId);\n  console.log(\"pay-to-script-hash address: \", p2shAddress);\n\n  // in dogeRegtest, we can faucet tokens to any address we like after mining some blocks\n  await rpc.mineBlocks(200);\n  // faucet 10 DOGE to the P2SH address\n  const faucetTxid = await rpc.sendFromWallet(p2shAddress, 10);\n\n  // create a random dogecoin P2PKH wallet to send the puzzle's reward to\n  const walletProvider = new DogeMemoryWalletProvider();\n  const wallet1 = walletProvider.addRandomWallet(networkId);\n  console.log(\"wallet 1 address: \", wallet1.address);\n\n  // -- unlock the puzzle and spend 9.5 DOGE from the puzzle to wallet1 --\n  // get the funding transaction\n  const faucetFundingTx = await rpc.getTransaction(faucetTxid);\n  // get the unspent transaction output for the puzzle p2sh script\n  const faucetUTXO = faucetFundingTx.getUTXOsForAddress(p2shAddress)[0];\n\n  // create a transaction which sends 9.5 DOGE from the puzzle script to wallet1\n  const p2shTxBuilder = createP2SHTransaction({\n    redeemScriptBASM: REDEEM_SCRIPT,\n    unlockScriptBASM: UNLOCK_SCRIPT,\n    inputs: [faucetUTXO],\n    outputs: [{address: wallet1.address, value: 950_000_000}],\n  });\n\n  // finalize the transaction\n  const finalizedTx = await p2shTxBuilder.finalizeAndSign();\n\n  // broadcast the transaction\n  const txid = await rpc.sendRawTransaction(finalizedTx.toHex());\n  console.log(\"transaction id: \", txid);\n}\n```\n\n### Complex P2SH Puzzle with Signature + Secret Preimage Reveal\n```typescript\nimport { DogeLinkRPC, DogeMemoryWalletProvider, createP2PKHTransaction, createP2SHTransaction, getP2SHAddress, hashBuffer } from \"doge-sdk\";\n\n\nasync function exampleComplexP2SH(){\n  /*\n   * Wallet 1 -\u003e sign(P2SH Puzzle, Wallet 2) -\u003e Wallet 3\n   */\n  // networkId can be doge, dogeTestnet, or dogeRegtest\n  const networkId = \"dogeRegtest\";\n\n  // note: if you don't have an RPC node, you can start one up with docker:\n  // docker run -p 1337:1337 -it --rm qedprotocol/bitide-doge:latest\n\n  // your dogecoin rpc node url, with an added query equal to doge, dogeTestnet, or dogeRegtest\n  const RPC_API_URL = \"http://devnet:devnet@localhost:1337/bitcoin-rpc/?network=\"+networkId;\n\n  const rpc = new DogeLinkRPC(RPC_API_URL);\n\n  // create some wallets, wallet 1 will sign the tx and wallet 2 will receive the funds\n  const walletProvider = new DogeMemoryWalletProvider();\n  const wallet1 = walletProvider.addRandomWallet(networkId);\n  console.log(\"wallet 1 address: \", wallet1.address);\n  const wallet2 = walletProvider.addRandomWallet(networkId);\n  console.log(\"wallet 2 address: \", wallet2.address);\n  const wallet3 = walletProvider.addRandomWallet(networkId);\n  console.log(\"wallet 3 address: \", wallet3.address);\n\n  // create a secret string and hash it\n  const secretString = \"hello world\";\n  const secretStringHashHex = hashBuffer(\"hash160\", new TextEncoder().encode(secretString), \"hex\");\n\n  \n  // hash the public key of wallet2\n  const pubKeyHashHex = hashBuffer(\"hash160\", wallet2.compressedPublicKey, \"hex\")\n\n\n  // a more complex puzzle utxo that can be unlocked by providing the secret string \"hello world\" and a signature from wallet2\n  const REDEEM_SCRIPT = `\n    OP_HASH160\n    \u003c0x${secretStringHashHex}\u003e\n    OP_EQUALVERIFY \n\n    OP_DUP\n    OP_HASH160\n    \u003c0x${pubKeyHashHex}\u003e\n    OP_EQUALVERIFY\n    OP_CHECKSIG\n  `;\n  // our unlock script will contain the secret string and a signature from wallet2\n  // (the signature will be added automatically when we run finalizeAndSign)\n  const UNLOCK_SCRIPT = `\n    \u003c\"${secretString}\"\u003e\n  `;\n\n  // compute the pay-to-script-hash address for our puzzle\n  const p2shAddress = getP2SHAddress(REDEEM_SCRIPT, networkId);\n  console.log(\"pay-to-script-hash address: \", p2shAddress);\n\n\n  // in dogeRegtest, we can faucet tokens to any address we like after mining some blocks\n  await rpc.mineBlocks(200);\n  // faucet 10 DOGE to wallet1\n  \n  const faucetTxid = await rpc.sendFromWallet(wallet1.address, 10);\n  await rpc.mineBlocks(1);\n\n  // -- STEP 1: send 9.9 DOGE from wallet1 to the puzzle script --\n  // get the funding transaction\n  const faucetFundingTx = await rpc.getTransaction(faucetTxid);\n  // get the unspent transaction output for wallet 1\n  const faucetUTXO = faucetFundingTx.getUTXOsForAddress(wallet1.address)[0];\n  // create a transaction which sends 9.9 DOGE from wallet1 to wallet2\n  const txBuilder1 = createP2PKHTransaction(wallet1, {\n    inputs: [faucetUTXO],\n    outputs: [{address: p2shAddress, value: 990_000_000}],\n    address: wallet1.address,\n  });\n  // finalize the transaction\n  const finalizedTx1 = await txBuilder1.finalizeAndSign();\n\n  // broadcast the transaction\n  const txid1 = await rpc.sendRawTransaction(finalizedTx1.toHex());\n  console.log(\"(send from wallet 1 to p2sh script) transaction id: \", txid1);\n\n  await rpc.mineBlocks(1);\n\n  // -- unlock the puzzle and spend 9.8 DOGE from the puzzle to wallet3 --\n  // get the p2sh funding transaction\n  const p2shFundingTx = await rpc.getTransaction(txid1);\n  // get the unspent transaction output for the puzzle p2sh script\n  const p2shUTXO = p2shFundingTx.getUTXOsForAddress(p2shAddress)[0];\n  console.log(\"p2shUTXO\",faucetUTXO);\n\n  // create a transaction which sends 9.8 DOGE from the puzzle script to wallet1\n  const p2shTxBuilder = createP2SHTransaction({\n    redeemScriptBASM: REDEEM_SCRIPT,\n    unlockScriptBASM: UNLOCK_SCRIPT,\n    inputs: [p2shUTXO],\n    outputs: [{address: wallet3.address, value: 980_000_000}],\n    // wallet2 will sign the transaction\n    signers: [wallet2],\n  });\n\n  // finalize the transaction\n  const finalizedTx = await p2shTxBuilder.finalizeAndSign();\n\n  // broadcast the transaction\n  const txid = await rpc.sendRawTransaction(finalizedTx.toHex());\n  console.log(\"(send from the p2sh script to wallet 3) transaction id: \", txid);\n}\n```\n\n### NodeJS Usage\nOn Node.js, the usage exactly the same as in the browser, but you need to provide an HTTP transport:\n```typescript\nimport fetch from 'node-fetch';\nconst httpTransport = new FetchHTTPClient(fetch);\nconst rpc = new DogeLinkRPC(\"http://devnet:devnet@localhost:1337/bitcoin-rpc/?network=dogeRegtest\", httpTransport);\n```\n\nIf you don't want to use node-fetch, you can also implement `IDogeHTTPClient` with the HTTP client of your choice:\n```typescript\ninterface ISimpleHTTPRequest {\n  url: string;\n  method: string;\n  credentials?: \"include\" | \"omit\" | \"same-origin\";\n  headers?: Record\u003cstring, string\u003e;\n  body?: string | ArrayBuffer;\n  responseType: \"text\" | \"json\" | \"arraybuffer\";\n}\ninterface ISimpleHTTPResponse {\n  statusCode: number;\n  body: any;\n}\n\ninterface IDogeHTTPClient {\n  sendRequest(request: ISimpleHTTPRequest): Promise\u003cISimpleHTTPResponse\u003e;\n}\n\nclass MyHttpTransport implements IDogeHTTPClient {\n  async sendRequest(request: ISimpleHTTPRequest): Promise\u003cISimpleHTTPResponse\u003e {\n    // ...\n  }\n}\n\nconst httpTransport = new MyHttpTransport();\nconst rpc = new DogeLinkRPC(\"http://devnet:devnet@localhost:1337/bitcoin-rpc/?network=dogeRegtest\", httpTransport);\n```\n\n### Hardware/Third Party Wallet Support\nTo implement a hardware wallet you need to implement the interfaces `IDogeTransactionSigner` and `IDogeWalletProvider` (see [src/wallet/types.ts](./src/wallet/types.ts)).\n\nYou can find an end-to-end example of implementing a doge wallet provider for ledger in [docs/ThirdPartyWallets.md](./docs/ThirdPartyWallets.md). \n\n## FAQ\n### How do I get a doge RPC API URL\nTo test out the library, you will need a doge RPC API node, you can spin one up locally along with a block explorer + electrs API by running:\n```bash\ndocker run -p 1337:1337 -it --rm qedprotocol/bitide-doge:latest\n```\n\n\n## TODO\n* Add more unit tests\n* Support Bitcoin compatible PSBT (instead of using TransactionBuilder)\n* Perform Audit\n\n\n## License\nMIT License\n\nCopyright (c) 2024 Zero Knowledge Labs Limited\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n\n\n\u003c!-- MARKDOWN LINKS \u0026 IMAGES --\u003e\n\u003c!-- https://www.markdownguide.org/basic-syntax/#reference-style-links --\u003e\n[contributors-shield]: https://img.shields.io/github/contributors/QEDProtocol/doge-sdk.svg?style=for-the-badge\n[contributors-url]: https://github.com/QEDProtocol/doge-sdk/graphs/contributors\n[forks-shield]: https://img.shields.io/github/forks/QEDProtocol/doge-sdk.svg?style=for-the-badge\n[forks-url]: https://github.com/QEDProtocol/doge-sdk/network/members\n[stars-shield]: https://img.shields.io/github/stars/QEDProtocol/doge-sdk.svg?style=for-the-badge\n[stars-url]: https://github.com/QEDProtocol/doge-sdk/stargazers\n[issues-shield]: https://img.shields.io/github/issues/QEDProtocol/doge-sdk.svg?style=for-the-badge\n[issues-url]: https://github.com/QEDProtocol/doge-sdk/issues\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqedprotocol%2Fdoge-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fqedprotocol%2Fdoge-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fqedprotocol%2Fdoge-sdk/lists"}