├── .gitignore ├── .metadata ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── create_test_data.js ├── doc └── api │ ├── __404error.html │ ├── bitbox │ ├── Account-class.html │ ├── Account │ │ ├── Account.html │ │ ├── accountNode.html │ │ ├── currentChild.html │ │ ├── getCurrentAddress.html │ │ ├── getNextAddress.html │ │ ├── hashCode.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── runtimeType.html │ │ └── toString.html │ ├── Address-class.html │ ├── Address │ │ ├── Address.html │ │ ├── details.html │ │ ├── detectFormat.html │ │ ├── formatCashAddr-constant.html │ │ ├── formatLegacy-constant.html │ │ ├── getUnconfirmed.html │ │ ├── hashCode.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── runtimeType.html │ │ ├── toBase58Check.html │ │ ├── toCashAddress.html │ │ ├── toLegacyAddress.html │ │ ├── toString.html │ │ ├── utxo.html │ │ └── validateAddress.html │ ├── Bitbox-class.html │ ├── Bitbox │ │ ├── Bitbox.html │ │ ├── hashCode.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── restUrl-constant.html │ │ ├── runtimeType.html │ │ ├── setRestUrl.html │ │ ├── toString.html │ │ ├── transactionBuilder.html │ │ └── trestUrl-constant.html │ ├── BitcoinCash-class.html │ ├── BitcoinCash │ │ ├── BitcoinCash.html │ │ ├── decodeBIP21.html │ │ ├── encodeBIP21.html │ │ ├── fromSatoshi.html │ │ ├── getByteCount.html │ │ ├── hashCode.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── runtimeType.html │ │ ├── toSatoshi.html │ │ └── toString.html │ ├── ECPair-class.html │ ├── ECPair │ │ ├── ECPair.fromPrivateKey.html │ │ ├── ECPair.fromPublicKey.html │ │ ├── ECPair.fromWIF.html │ │ ├── ECPair.html │ │ ├── ECPair.makeRandom.html │ │ ├── address.html │ │ ├── compressed.html │ │ ├── hashCode.html │ │ ├── network.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── privateKey.html │ │ ├── publicKey.html │ │ ├── runtimeType.html │ │ ├── sign.html │ │ ├── toString.html │ │ ├── toWIF.html │ │ └── verify.html │ ├── HDNode-class.html │ ├── HDNode │ │ ├── HDNode.fromSeed.html │ │ ├── HDNode.fromXPriv.html │ │ ├── HDNode.fromXPub.html │ │ ├── HDNode.html │ │ ├── HIGHEST_BIT-constant.html │ │ ├── UINT31_MAX-constant.html │ │ ├── UINT32_MAX-constant.html │ │ ├── depth.html │ │ ├── derive.html │ │ ├── derivePath.html │ │ ├── fingerprint.html │ │ ├── hashCode.html │ │ ├── identifier.html │ │ ├── index.html │ │ ├── keyPair.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── parentFingerprint.html │ │ ├── privateKey.html │ │ ├── publicKey.html │ │ ├── publicKeyList.html │ │ ├── rawPrivateKey.html │ │ ├── runtimeType.html │ │ ├── toCashAddress.html │ │ ├── toLegacyAddress.html │ │ ├── toString.html │ │ ├── toXPriv.html │ │ └── toXPub.html │ ├── Input-class.html │ ├── Input │ │ ├── Input.clone.html │ │ ├── Input.expandInput.html │ │ ├── Input.html │ │ ├── hash.html │ │ ├── hashCode.html │ │ ├── index.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── prevOutScript.html │ │ ├── pubkeys.html │ │ ├── runtimeType.html │ │ ├── script.html │ │ ├── sequence.html │ │ ├── signScript.html │ │ ├── signatures.html │ │ ├── toString.html │ │ └── value.html │ ├── Mnemonic-class.html │ ├── Mnemonic │ │ ├── Mnemonic.html │ │ ├── generate.html │ │ ├── hashCode.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── runtimeType.html │ │ ├── toSeed.html │ │ └── toString.html │ ├── Output-class.html │ ├── Output │ │ ├── Output.clone.html │ │ ├── Output.html │ │ ├── hashCode.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── pubkeys.html │ │ ├── runtimeType.html │ │ ├── script.html │ │ ├── signatures.html │ │ ├── toString.html │ │ ├── value.html │ │ └── valueBuffer.html │ ├── RawTransactions-class.html │ ├── RawTransactions │ │ ├── RawTransactions.html │ │ ├── hashCode.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── runtimeType.html │ │ ├── sendRawTransaction.html │ │ └── toString.html │ ├── Transaction-class.html │ ├── Transaction │ │ ├── ADVANCED_TRANSACTION_FLAG-constant.html │ │ ├── ADVANCED_TRANSACTION_MARKER-constant.html │ │ ├── DEFAULT_SEQUENCE-constant.html │ │ ├── ONE.html │ │ ├── SATOSHI_MAX-constant.html │ │ ├── SIGHASH_ALL-constant.html │ │ ├── SIGHASH_ANYONECANPAY-constant.html │ │ ├── SIGHASH_BITCOINCASHBIP143-constant.html │ │ ├── SIGHASH_NONE-constant.html │ │ ├── SIGHASH_SINGLE-constant.html │ │ ├── Transaction.clone.html │ │ ├── Transaction.fromBuffer.html │ │ ├── Transaction.fromHex.html │ │ ├── Transaction.html │ │ ├── ZERO.html │ │ ├── addInput.html │ │ ├── addOutput.html │ │ ├── blankOutput.html │ │ ├── emptyScript.html │ │ ├── getHash.html │ │ ├── getId.html │ │ ├── hashCode.html │ │ ├── hashForCashSignature.html │ │ ├── hashForSignature.html │ │ ├── inputs.html │ │ ├── isCoinbase.html │ │ ├── isCoinbaseHash.html │ │ ├── locktime.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── outputs.html │ │ ├── runtimeType.html │ │ ├── setInputScript.html │ │ ├── toBuffer.html │ │ ├── toHex.html │ │ ├── toString.html │ │ ├── valueUint64Max.html │ │ ├── version.html │ │ └── virtualSize.html │ ├── TransactionBuilder-class.html │ ├── TransactionBuilder │ │ ├── DEFAULT_SEQUENCE-constant.html │ │ ├── SIGHASH_ALL-constant.html │ │ ├── SIGHASH_ANYONECANPAY-constant.html │ │ ├── SIGHASH_BITCOINCASHBIP143-constant.html │ │ ├── SIGHASH_NONE-constant.html │ │ ├── SIGHASH_SINGLE-constant.html │ │ ├── TransactionBuilder.fromTransaction.html │ │ ├── TransactionBuilder.html │ │ ├── addInput.html │ │ ├── addOutput.html │ │ ├── build.html │ │ ├── buildIncomplete.html │ │ ├── getByteCount.html │ │ ├── hashCode.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── prevTxSet.html │ │ ├── runtimeType.html │ │ ├── setLockTime.html │ │ ├── setVersion.html │ │ ├── sign.html │ │ ├── toString.html │ │ └── tx.html │ ├── Utxo-class.html │ ├── Utxo │ │ ├── Utxo.fromMap.html │ │ ├── Utxo.html │ │ ├── amount.html │ │ ├── confirmations.html │ │ ├── convertMapListToUtxos.html │ │ ├── hashCode.html │ │ ├── height.html │ │ ├── noSuchMethod.html │ │ ├── operator_equals.html │ │ ├── runtimeType.html │ │ ├── satoshis.html │ │ ├── toString.html │ │ ├── txid.html │ │ └── vout.html │ ├── bitbox-library.html │ ├── decode.html │ ├── encode.html │ ├── encodingLength.html │ ├── printHex.html │ ├── readUInt64LE.html │ └── writeUInt64LE.html │ ├── categories.json │ ├── index.html │ ├── index.json │ └── static-assets │ ├── URI.js │ ├── css │ ├── bootstrap.css │ └── bootstrap.min.css │ ├── favicon.png │ ├── github.css │ ├── highlight.pack.js │ ├── play_button.svg │ ├── readme.md │ ├── script.js │ ├── sdk_footer_text.html │ ├── styles.css │ └── typeahead.bundle.min.js ├── example └── main.dart ├── lib ├── bitbox.dart └── src │ ├── account.dart │ ├── address.dart │ ├── bitbox.dart │ ├── bitcoincash.dart │ ├── crypto │ ├── crypto.dart │ └── ecurve.dart │ ├── ecpair.dart │ ├── hdnode.dart │ ├── mnemonic.dart │ ├── rawtransactions.dart │ ├── transaction.dart │ ├── transactionbuilder.dart │ ├── utils │ ├── bip21.dart │ ├── check_types.dart │ ├── network.dart │ ├── opcodes.dart │ ├── p2pkh.dart │ ├── pushdata.dart │ ├── rest_api.dart │ └── script.dart │ └── varuint.dart ├── pubspec.lock ├── pubspec.yaml └── test └── bitbox_test.dart /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.log 4 | *.pyc 5 | *.swp 6 | .DS_Store 7 | .atom/ 8 | .buildlog/ 9 | .history 10 | .svn/ 11 | 12 | # IntelliJ related 13 | *.iml 14 | *.ipr 15 | *.iws 16 | .idea/ 17 | 18 | # Visual Studio Code related 19 | .vscode/ 20 | 21 | # Flutter/Dart/Pub related 22 | .dart_tool/ 23 | .flutter-plugins 24 | .packages 25 | .pub-cache/ 26 | .pub/ 27 | build/ 28 | 29 | # Android related 30 | **/android/**/gradle-wrapper.jar 31 | **/android/.gradle 32 | **/android/captures/ 33 | **/android/gradlew 34 | **/android/gradlew.bat 35 | **/android/local.properties 36 | **/android/**/GeneratedPluginRegistrant.java 37 | 38 | # iOS/XCode related 39 | **/ios/**/*.mode1v3 40 | **/ios/**/*.mode2v3 41 | **/ios/**/*.moved-aside 42 | **/ios/**/*.pbxuser 43 | **/ios/**/*.perspectivev3 44 | **/ios/**/*sync/ 45 | **/ios/**/.sconsign.dblite 46 | **/ios/**/.tags* 47 | **/ios/**/.vagrant/ 48 | **/ios/**/DerivedData/ 49 | **/ios/**/Icon? 50 | **/ios/**/Pods/ 51 | **/ios/**/.symlinks/ 52 | **/ios/**/profile 53 | **/ios/**/xcuserdata 54 | **/ios/.generated/ 55 | **/ios/Flutter/App.framework 56 | **/ios/Flutter/Flutter.framework 57 | **/ios/Flutter/Generated.xcconfig 58 | **/ios/Flutter/app.flx 59 | **/ios/Flutter/app.zip 60 | **/ios/Flutter/flutter_assets/ 61 | **/ios/ServiceDefinitions.json 62 | **/ios/Runner/GeneratedPluginRegistrant.* 63 | 64 | # Exceptions to above rules. 65 | !**/ios/**/default.mode1v3 66 | !**/ios/**/default.mode2v3 67 | !**/ios/**/default.pbxuser 68 | !**/ios/**/default.perspectivev3 69 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 70 | -------------------------------------------------------------------------------- /.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 7a4c33425ddd78c54aba07d86f3f9a4a0051769b 8 | channel: beta 9 | 10 | project_type: package 11 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.0.1] - 2019-08-01 2 | 3 | Light version of Bitcoin.com's Bitbox library 4 | 5 | ## [0.0.2] - 2019-10-06 6 | 7 | - Taken some code analysis hint into account 8 | 9 | ## [0.0.3] - 2020-03-20 10 | 11 | - Added support for bip21 implemented by RomitRadical 12 | - Added transaction details support 13 | - Fixed some API issues and 14 | 15 | ## [0.0.4] - 2020-05-12 16 | 17 | - padded a private key by if it was generated shorter than 32 bytes 18 | - added support for broadcasting more transactions 19 | - changed resturl parameter to non-named (didn't make sense to have it named when it was the only one)) 20 | 21 | ## [0.0.4] - 2020-06-02 22 | 23 | - fixed signing mechanism, so it would better handle 31-byte private key 24 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | I was told it's a good practice to give guidelines to contributors. However this is the open-source project I have ever created or even contributed to, so the first contribution by someone more experience could be contribution rules :-) 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | TODO: Add your license here. 2 | -------------------------------------------------------------------------------- /doc/api/__404error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | bitbox - Dart API docs 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 |
24 | 25 | 28 |
bitbox
29 | 32 |
33 | 34 |
35 | 36 | 53 | 54 |
55 |

404: Something's gone wrong :-(

56 | 57 |
58 |

You've tried to visit a page that doesn't exist. Luckily this site 59 | has other pages.

60 |

If you were looking for something specific, try searching: 61 |

64 |

65 | 66 |
67 |
68 | 69 | 71 | 72 |
73 | 74 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /doc/api/bitbox/Account/Account.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Account constructor - Account class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
Account
33 | 36 |
37 | 38 |
39 | 40 | 82 | 83 |
84 |

Account constructor

85 | 86 |
87 | 88 | Account(HDNode accountNode, [ int currentChild ]) 89 |
90 | 91 | 92 |
93 |

Implementation

94 |
Account(this.accountNode, [this.currentChild]);
95 |
96 | 97 |
98 | 99 | 101 | 102 |
103 | 104 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /doc/api/bitbox/Account/accountNode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | accountNode property - Account class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
accountNode
33 | 36 |
37 | 38 |
39 | 40 | 83 | 84 |
85 |

accountNode property

86 | 87 |
88 | HDNode 89 | accountNode 90 |
final
91 |
92 |
93 |

Implementation

94 |
final HDNode accountNode
 95 | 
 96 | 
97 |
98 | 99 |
100 | 101 | 103 | 104 |
105 | 106 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /doc/api/bitbox/Account/currentChild.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | currentChild property - Account class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
currentChild
33 | 36 |
37 | 38 |
39 | 40 | 83 | 84 |
85 |

currentChild property

86 | 87 |
88 | int 89 | currentChild 90 |
read / write
91 |
92 |
93 |

Implementation

94 |
int currentChild = 0
 95 | 
 96 | 
97 |
98 | 99 |
100 | 101 | 103 | 104 |
105 | 106 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | -------------------------------------------------------------------------------- /doc/api/bitbox/Account/runtimeType.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | runtimeType property - Account class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
runtimeType
33 | 36 |
37 | 38 |
39 | 40 | 83 | 84 |
85 |

runtimeType property

86 | 87 | 88 |
89 | 90 |
91 | Type 92 | runtimeType 93 |
inherited
94 |
95 | 96 |
97 |

A representation of the runtime type of the object.

98 |
99 |
100 |

Implementation

101 |
external Type get runtimeType;
102 |
103 |
104 | 105 |
106 | 107 | 109 | 110 |
111 | 112 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /doc/api/bitbox/Account/toString.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | toString method - Account class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
toString
33 | 36 |
37 | 38 |
39 | 40 | 83 | 84 |
85 |

toString method

86 | 87 |
88 | String 89 | toString 90 | () 91 |
inherited
92 |
93 |
94 |

Returns a string representation of this object.

95 |
96 | 97 |
98 |

Implementation

99 |
external String toString();
100 |
101 | 102 |
103 | 104 | 106 | 107 |
108 | 109 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /doc/api/bitbox/Bitbox/Bitbox.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Bitbox constructor - Bitbox class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
Bitbox
33 | 36 |
37 | 38 |
39 | 40 | 84 | 85 |
86 |

Bitbox constructor

87 | 88 |
89 | 90 | Bitbox() 91 |
92 | 93 | 94 | 95 | 96 |
97 | 98 | 100 | 101 |
102 | 103 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /doc/api/bitbox/Bitbox/restUrl-constant.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | restUrl constant - Bitbox class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
restUrl
33 | 36 |
37 | 38 |
39 | 40 | 85 | 86 |
87 |

restUrl constant

88 | 89 |
90 | String 91 | const restUrl 92 | = 93 | "https://rest.bitcoin.com/v2/" 94 |
95 | 96 |
97 |

Implementation

98 |
static const restUrl = "https://rest.bitcoin.com/v2/"
 99 | 
100 | 
101 |
102 | 103 |
104 | 105 | 107 | 108 |
109 | 110 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /doc/api/bitbox/Bitbox/toString.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | toString method - Bitbox class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
toString
33 | 36 |
37 | 38 |
39 | 40 | 85 | 86 |
87 |

toString method

88 | 89 |
90 | String 91 | toString 92 | () 93 |
inherited
94 |
95 |
96 |

Returns a string representation of this object.

97 |
98 | 99 |
100 |

Implementation

101 |
external String toString();
102 |
103 | 104 |
105 | 106 | 108 | 109 |
110 | 111 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /doc/api/bitbox/Bitbox/trestUrl-constant.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | trestUrl constant - Bitbox class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
trestUrl
33 | 36 |
37 | 38 |
39 | 40 | 85 | 86 |
87 |

trestUrl constant

88 | 89 |
90 | String 91 | const trestUrl 92 | = 93 | "https://trest.bitcoin.com/v2/" 94 |
95 | 96 |
97 |

Implementation

98 |
static const trestUrl = "https://trest.bitcoin.com/v2/"
 99 | 
100 | 
101 |
102 | 103 |
104 | 105 | 107 | 108 |
109 | 110 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /doc/api/bitbox/BitcoinCash/BitcoinCash.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | BitcoinCash constructor - BitcoinCash class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
BitcoinCash
33 | 36 |
37 | 38 |
39 | 40 | 84 | 85 |
86 |

BitcoinCash constructor

87 | 88 |
89 | 90 | BitcoinCash() 91 |
92 | 93 | 94 | 95 | 96 |
97 | 98 | 100 | 101 |
102 | 103 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /doc/api/bitbox/Input/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | index property - Input class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
index
33 | 36 |
37 | 38 |
39 | 40 | 90 | 91 |
92 |

index property

93 | 94 |
95 | int 96 | index 97 |
read / write
98 |
99 |
100 |

Implementation

101 |
int index
102 | 
103 | 
104 |
105 | 106 |
107 | 108 | 110 | 111 |
112 | 113 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /doc/api/bitbox/Mnemonic/Mnemonic.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Mnemonic constructor - Mnemonic class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
Mnemonic
33 | 36 |
37 | 38 |
39 | 40 | 81 | 82 |
83 |

Mnemonic constructor

84 | 85 |
86 | 87 | Mnemonic() 88 |
89 | 90 | 91 | 92 | 93 |
94 | 95 | 97 | 98 |
99 | 100 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /doc/api/bitbox/Mnemonic/generate.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | generate method - Mnemonic class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
generate
33 | 36 |
37 | 38 |
39 | 40 | 82 | 83 |
84 |

generate method

85 | 86 |
87 | String 88 | generate 89 | ({int strength: 128 }) 90 | 91 |
92 |
93 |

Generate bip39 mnemonic

94 |
95 | 96 |
97 |

Implementation

98 |
static String generate({int strength = 128}) => bip39.generateMnemonic(strength: strength);
99 |
100 | 101 |
102 | 103 | 105 | 106 |
107 | 108 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /doc/api/bitbox/Mnemonic/runtimeType.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | runtimeType property - Mnemonic class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
runtimeType
33 | 36 |
37 | 38 |
39 | 40 | 82 | 83 |
84 |

runtimeType property

85 | 86 | 87 |
88 | 89 |
90 | Type 91 | runtimeType 92 |
inherited
93 |
94 | 95 |
96 |

A representation of the runtime type of the object.

97 |
98 |
99 |

Implementation

100 |
external Type get runtimeType;
101 |
102 |
103 | 104 |
105 | 106 | 108 | 109 |
110 | 111 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /doc/api/bitbox/Mnemonic/toSeed.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | toSeed method - Mnemonic class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
toSeed
33 | 36 |
37 | 38 |
39 | 40 | 82 | 83 |
84 |

toSeed method

85 | 86 |
87 | Uint8List 88 | toSeed 89 | (String mnemonic) 90 | 91 |
92 |
93 |

Create root seed from mnemonic

94 |
95 | 96 |
97 |

Implementation

98 |
static Uint8List toSeed(String mnemonic) => bip39.mnemonicToSeed(mnemonic);
99 |
100 | 101 |
102 | 103 | 105 | 106 |
107 | 108 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /doc/api/bitbox/Mnemonic/toString.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | toString method - Mnemonic class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
toString
33 | 36 |
37 | 38 |
39 | 40 | 82 | 83 |
84 |

toString method

85 | 86 |
87 | String 88 | toString 89 | () 90 |
inherited
91 |
92 |
93 |

Returns a string representation of this object.

94 |
95 | 96 |
97 |

Implementation

98 |
external String toString();
99 |
100 | 101 |
102 | 103 | 105 | 106 |
107 | 108 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /doc/api/bitbox/Output/pubkeys.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | pubkeys property - Output class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
pubkeys
33 | 36 |
37 | 38 |
39 | 40 | 85 | 86 |
87 |

pubkeys property

88 | 89 |
90 | List<Uint8List> 91 | pubkeys 92 |
read / write
93 |
94 |
95 |

Implementation

96 |
List<Uint8List> pubkeys
 97 | 
 98 | 
99 |
100 | 101 |
102 | 103 | 105 | 106 |
107 | 108 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /doc/api/bitbox/Output/runtimeType.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | runtimeType property - Output class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
runtimeType
33 | 36 |
37 | 38 |
39 | 40 | 85 | 86 |
87 |

runtimeType property

88 | 89 | 90 |
91 | 92 |
93 | Type 94 | runtimeType 95 |
inherited
96 |
97 | 98 |
99 |

A representation of the runtime type of the object.

100 |
101 |
102 |

Implementation

103 |
external Type get runtimeType;
104 |
105 |
106 | 107 |
108 | 109 | 111 | 112 |
113 | 114 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | -------------------------------------------------------------------------------- /doc/api/bitbox/Output/script.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | script property - Output class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
script
33 | 36 |
37 | 38 |
39 | 40 | 85 | 86 |
87 |

script property

88 | 89 |
90 | Uint8List 91 | script 92 |
read / write
93 |
94 |
95 |

Implementation

96 |
Uint8List script
 97 | 
 98 | 
99 |
100 | 101 |
102 | 103 | 105 | 106 |
107 | 108 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /doc/api/bitbox/Output/signatures.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | signatures property - Output class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
signatures
33 | 36 |
37 | 38 |
39 | 40 | 85 | 86 |
87 |

signatures property

88 | 89 |
90 | List<Uint8List> 91 | signatures 92 |
read / write
93 |
94 |
95 |

Implementation

96 |
List<Uint8List> signatures
 97 | 
 98 | 
99 |
100 | 101 |
102 | 103 | 105 | 106 |
107 | 108 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /doc/api/bitbox/Output/value.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | value property - Output class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
value
33 | 36 |
37 | 38 |
39 | 40 | 85 | 86 |
87 |

value property

88 | 89 |
90 | int 91 | value 92 |
read / write
93 |
94 |
95 |

Implementation

96 |
int value
 97 | 
 98 | 
99 |
100 | 101 |
102 | 103 | 105 | 106 |
107 | 108 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /doc/api/bitbox/Output/valueBuffer.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | valueBuffer property - Output class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
valueBuffer
33 | 36 |
37 | 38 |
39 | 40 | 85 | 86 |
87 |

valueBuffer property

88 | 89 |
90 | Uint8List 91 | valueBuffer 92 |
read / write
93 |
94 |
95 |

Implementation

96 |
Uint8List valueBuffer
 97 | 
 98 | 
99 |
100 | 101 |
102 | 103 | 105 | 106 |
107 | 108 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /doc/api/bitbox/RawTransactions/RawTransactions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | RawTransactions constructor - RawTransactions class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
RawTransactions
33 | 36 |
37 | 38 |
39 | 40 | 80 | 81 |
82 |

RawTransactions constructor

83 | 84 |
85 | 86 | RawTransactions() 87 |
88 | 89 | 90 | 91 | 92 |
93 | 94 | 96 | 97 |
98 | 99 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /doc/api/bitbox/RawTransactions/runtimeType.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | runtimeType property - RawTransactions class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
runtimeType
33 | 36 |
37 | 38 |
39 | 40 | 81 | 82 |
83 |

runtimeType property

84 | 85 | 86 |
87 | 88 |
89 | Type 90 | runtimeType 91 |
inherited
92 |
93 | 94 |
95 |

A representation of the runtime type of the object.

96 |
97 |
98 |

Implementation

99 |
external Type get runtimeType;
100 |
101 |
102 | 103 |
104 | 105 | 107 | 108 |
109 | 110 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | -------------------------------------------------------------------------------- /doc/api/bitbox/RawTransactions/toString.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | toString method - RawTransactions class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
toString
33 | 36 |
37 | 38 |
39 | 40 | 81 | 82 |
83 |

toString method

84 | 85 |
86 | String 87 | toString 88 | () 89 |
inherited
90 |
91 |
92 |

Returns a string representation of this object.

93 |
94 | 95 |
96 |

Implementation

97 |
external String toString();
98 |
99 | 100 |
101 | 102 | 104 | 105 |
106 | 107 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /doc/api/bitbox/Utxo/amount.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | amount property - Utxo class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
amount
33 | 36 |
37 | 38 |
39 | 40 | 88 | 89 |
90 |

amount property

91 | 92 |
93 | double 94 | amount 95 |
final
96 |
97 |
98 |

Implementation

99 |
final double amount
100 | 
101 | 
102 |
103 | 104 |
105 | 106 | 108 | 109 |
110 | 111 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /doc/api/bitbox/Utxo/confirmations.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | confirmations property - Utxo class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
confirmations
33 | 36 |
37 | 38 |
39 | 40 | 88 | 89 |
90 |

confirmations property

91 | 92 |
93 | int 94 | confirmations 95 |
final
96 |
97 |
98 |

Implementation

99 |
final int confirmations
100 | 
101 | 
102 |
103 | 104 |
105 | 106 | 108 | 109 |
110 | 111 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /doc/api/bitbox/Utxo/height.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | height property - Utxo class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
height
33 | 36 |
37 | 38 |
39 | 40 | 88 | 89 |
90 |

height property

91 | 92 |
93 | int 94 | height 95 |
final
96 |
97 |
98 |

Implementation

99 |
final int height
100 | 
101 | 
102 |
103 | 104 |
105 | 106 | 108 | 109 |
110 | 111 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /doc/api/bitbox/Utxo/satoshis.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | satoshis property - Utxo class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
satoshis
33 | 36 |
37 | 38 |
39 | 40 | 88 | 89 |
90 |

satoshis property

91 | 92 |
93 | int 94 | satoshis 95 |
final
96 |
97 |
98 |

Implementation

99 |
final int satoshis
100 | 
101 | 
102 |
103 | 104 |
105 | 106 | 108 | 109 |
110 | 111 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /doc/api/bitbox/Utxo/txid.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | txid property - Utxo class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
txid
33 | 36 |
37 | 38 |
39 | 40 | 88 | 89 |
90 |

txid property

91 | 92 |
93 | String 94 | txid 95 |
final
96 |
97 |
98 |

Implementation

99 |
final String txid
100 | 
101 | 
102 |
103 | 104 |
105 | 106 | 108 | 109 |
110 | 111 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /doc/api/bitbox/Utxo/vout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | vout property - Utxo class - bitbox library - Dart API 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 | 32 |
vout
33 | 36 |
37 | 38 |
39 | 40 | 88 | 89 |
90 |

vout property

91 | 92 |
93 | int 94 | vout 95 |
final
96 |
97 |
98 |

Implementation

99 |
final int vout
100 | 
101 | 
102 |
103 | 104 |
105 | 106 | 108 | 109 |
110 | 111 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /doc/api/categories.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /doc/api/static-assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomas-forgac/bitbox-flutter/dcad2a0f9d9a6b1a1431066ea47f0a2d58967c2e/doc/api/static-assets/favicon.png -------------------------------------------------------------------------------- /doc/api/static-assets/github.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | github.com style (c) Vasily Polovnyov 4 | 5 | */ 6 | 7 | .hljs { 8 | display: block; 9 | overflow-x: auto; 10 | padding: 0.5em; 11 | color: #333; 12 | background: #f8f8f8; 13 | } 14 | 15 | .hljs-comment, 16 | .hljs-quote { 17 | color: #998; 18 | font-style: italic; 19 | } 20 | 21 | .hljs-keyword, 22 | .hljs-selector-tag, 23 | .hljs-subst { 24 | color: #333; 25 | font-weight: bold; 26 | } 27 | 28 | .hljs-number, 29 | .hljs-literal, 30 | .hljs-variable, 31 | .hljs-template-variable, 32 | .hljs-tag .hljs-attr { 33 | color: #008080; 34 | } 35 | 36 | .hljs-string, 37 | .hljs-doctag { 38 | color: #d14; 39 | } 40 | 41 | .hljs-title, 42 | .hljs-section, 43 | .hljs-selector-id { 44 | color: #900; 45 | font-weight: bold; 46 | } 47 | 48 | .hljs-subst { 49 | font-weight: normal; 50 | } 51 | 52 | .hljs-type, 53 | .hljs-class .hljs-title { 54 | color: #458; 55 | font-weight: bold; 56 | } 57 | 58 | .hljs-tag, 59 | .hljs-name, 60 | .hljs-attribute { 61 | color: #000080; 62 | font-weight: normal; 63 | } 64 | 65 | .hljs-regexp, 66 | .hljs-link { 67 | color: #009926; 68 | } 69 | 70 | .hljs-symbol, 71 | .hljs-bullet { 72 | color: #990073; 73 | } 74 | 75 | .hljs-built_in, 76 | .hljs-builtin-name { 77 | color: #0086b3; 78 | } 79 | 80 | .hljs-meta { 81 | color: #999; 82 | font-weight: bold; 83 | } 84 | 85 | .hljs-deletion { 86 | background: #fdd; 87 | } 88 | 89 | .hljs-addition { 90 | background: #dfd; 91 | } 92 | 93 | .hljs-emphasis { 94 | font-style: italic; 95 | } 96 | 97 | .hljs-strong { 98 | font-weight: bold; 99 | } 100 | -------------------------------------------------------------------------------- /doc/api/static-assets/play_button.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/api/static-assets/readme.md: -------------------------------------------------------------------------------- 1 | # highlight.js 2 | 3 | Generated from https://highlightjs.org/download/ on 2019-05-16 4 | 5 | Included languages: 6 | 7 | * bash 8 | * css 9 | * dart 10 | * html, xml 11 | * java 12 | * javascript 13 | * json 14 | * kotlin 15 | * markdown 16 | * objective-c 17 | * shell 18 | * swift 19 | * yaml 20 | -------------------------------------------------------------------------------- /doc/api/static-assets/sdk_footer_text.html: -------------------------------------------------------------------------------- 1 | • 2 | 3 | cc license 4 | 5 | -------------------------------------------------------------------------------- /example/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:bitbox/bitbox.dart' as Bitbox; 2 | 3 | void main() async { 4 | // set this to false to use mainnet 5 | final testnet = true; 6 | 7 | // After running the code for the first time, depositing an amount to the address displayed in the console, 8 | // and waiting for confirmation, paste the generated mnemonic here, 9 | // so the code continues below with address withdrawal 10 | String mnemonic = ""; 11 | 12 | if (mnemonic == "") { 13 | // generate 12-word (128bit) mnemonic 14 | mnemonic = Bitbox.Mnemonic.generate(); 15 | 16 | print(mnemonic); 17 | } 18 | 19 | // generate a seed from mnemonic 20 | final seed = Bitbox.Mnemonic.toSeed(mnemonic); 21 | 22 | // create an instance of Bitbox.HDNode for mainnet 23 | final masterNode = Bitbox.HDNode.fromSeed(seed, testnet); 24 | 25 | // This format is compatible with Bitcoin.com wallet. 26 | // Other wallets use Change to m/44'/145'/0'/0 27 | final accountDerivationPath = "m/44'/0'/0'/0"; 28 | 29 | // create an account node using the provided derivation path 30 | final accountNode = masterNode.derivePath(accountDerivationPath); 31 | 32 | // get account's extended private key 33 | final accountXPriv = accountNode.toXPriv(); 34 | 35 | // create a Bitbox.HDNode instance of the first child in this account 36 | final childNode = accountNode.derive(0); 37 | 38 | // get an address of the child 39 | final address = childNode.toCashAddress(); 40 | 41 | // if you are using testnet, set the appropriate rest api url before making 42 | // any API calls (like getting address or transaction details or broadcasting a transaction 43 | if (testnet) { 44 | Bitbox.Bitbox.setRestUrl(Bitbox.Bitbox.trestUrl); 45 | } 46 | 47 | // get address details 48 | final addressDetails = await Bitbox.Address.details(address); 49 | 50 | print(addressDetails); 51 | 52 | // If there is a confirmed balance, attempt to withdraw it to the address defined below 53 | if (addressDetails["balance"] > 0) { 54 | final builder = Bitbox.Bitbox.transactionBuilder(testnet: testnet); 55 | 56 | // retrieve address' utxos from the rest api 57 | final utxos = await Bitbox.Address.utxo(address) as List; 58 | 59 | // placeholder for input signatures 60 | final signatures = []; 61 | 62 | // placeholder for total input balance 63 | int totalBalance = 0; 64 | 65 | // iterate through the list of address utxos and use them as inputs for the withdrawal transaction 66 | utxos.forEach((Bitbox.Utxo utxo) { 67 | // add the utxo as an input for the transaction 68 | builder.addInput(utxo.txid, utxo.vout); 69 | 70 | // add a signature to the list to be used later 71 | signatures.add({ 72 | "vin": signatures.length, 73 | "key_pair": childNode.keyPair, 74 | "original_amount": utxo.satoshis 75 | }); 76 | 77 | totalBalance += utxo.satoshis; 78 | }); 79 | 80 | // set an address to send the remaining balance to 81 | final outputAddress = ""; 82 | 83 | // if there is an unspent balance, create a spending transaction 84 | if (totalBalance > 0 && outputAddress != "") { 85 | // calculate the fee based on number of inputs and one expected output 86 | final fee = Bitbox.BitcoinCash.getByteCount(signatures.length, 1); 87 | 88 | // calculate how much balance will be left over to spend after the fee 89 | final sendAmount = totalBalance - fee; 90 | 91 | // add the output based on the address provided in the testing data 92 | builder.addOutput(outputAddress, sendAmount); 93 | 94 | // sign all inputs 95 | signatures.forEach((signature) { 96 | builder.sign(signature["vin"], signature["key_pair"], signature["original_amount"]); 97 | }); 98 | 99 | // build the transaction 100 | final tx = builder.build(); 101 | 102 | // broadcast the transaction 103 | final txid = (await Bitbox.RawTransactions.sendRawTransaction([tx.toHex()])).first; 104 | 105 | // Yatta! 106 | print("Transaction broadcasted: $txid"); 107 | } else if (totalBalance > 0) { 108 | print("Enter an output address to test withdrawal transaction"); 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /lib/bitbox.dart: -------------------------------------------------------------------------------- 1 | library bitbox; 2 | 3 | export 'src/account.dart'; 4 | export 'src/address.dart'; 5 | export 'src/bitbox.dart'; 6 | export 'src/bitcoincash.dart'; 7 | export 'src/ecpair.dart'; 8 | export 'src/hdnode.dart'; 9 | export 'src/mnemonic.dart'; 10 | export 'src/rawtransactions.dart'; 11 | export 'src/transaction.dart'; 12 | export 'src/transactionbuilder.dart'; 13 | export 'src/varuint.dart'; 14 | -------------------------------------------------------------------------------- /lib/src/account.dart: -------------------------------------------------------------------------------- 1 | import 'hdnode.dart'; 2 | 3 | /// BIP32 account with simple helper methods 4 | class Account { 5 | final HDNode accountNode; 6 | 7 | int currentChild = 0; 8 | 9 | Account(this.accountNode, [this.currentChild]); 10 | 11 | /// Returns address at the current position 12 | String getCurrentAddress([bool legacyFormat = true]) { 13 | if (legacyFormat) { 14 | return accountNode.derive(currentChild).toLegacyAddress(); 15 | } else { 16 | return accountNode.derive(currentChild).toCashAddress(); 17 | } 18 | } 19 | 20 | /// moves the position forward and returns an address from the new position 21 | String getNextAddress([bool legacyFormat = true]) { 22 | if (legacyFormat) { 23 | return accountNode.derive(++currentChild).toLegacyAddress(); 24 | } else { 25 | return accountNode.derive(++currentChild).toCashAddress(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/bitbox.dart: -------------------------------------------------------------------------------- 1 | import 'utils/rest_api.dart'; 2 | 3 | import 'utils/network.dart'; 4 | import 'transactionbuilder.dart'; 5 | 6 | class Bitbox { 7 | static const restUrl = "https://rest.bitcoin.com/v2/"; 8 | static const trestUrl = "https://trest.bitcoin.com/v2/"; 9 | 10 | /// Set non-default rest Url 11 | static void setRestUrl([String restUrl = restUrl]) { 12 | RestApi.restUrl = restUrl; 13 | } 14 | 15 | /// Create a Transaction builder 16 | /// 17 | /// It is possible to call [TransactionBuilder] directly and pass [Network] parameter, this just makes it easier 18 | static TransactionBuilder transactionBuilder({testnet: false}) => 19 | TransactionBuilder( 20 | network: testnet ? Network.bitcoinCashTest() : Network.bitcoinCash()); 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/bitcoincash.dart: -------------------------------------------------------------------------------- 1 | import 'utils/bip21.dart'; 2 | 3 | /// Bitcoin Cash specific utilities 4 | class BitcoinCash { 5 | /// Converts Bitcoin Cash units to satoshi units 6 | static int toSatoshi(double bchAmount) { 7 | return (bchAmount * 100000000).round(); 8 | } 9 | 10 | /// Converts satoshi units to Bitcoin Cash units 11 | static double fromSatoshi(int satoshi) { 12 | return satoshi / 100000000; 13 | } 14 | 15 | /// Calculates and returns byte count of a transaction 16 | static int getByteCount(int inputs, int outputs) { 17 | return ((inputs * 148 * 4 + 34 * 4 * outputs + 10 * 4) / 4).ceil(); 18 | } 19 | 20 | /// Converts a bch [address] and its [options] into bip-21 uri 21 | /// 22 | /// The following example shows the format of [options] 23 | /// ``` 24 | /// { 25 | /// amount: 12.5, 26 | /// label: 'coinbase donation', 27 | /// message: "and ya don't stop", 28 | /// } 29 | /// ``` 30 | static String encodeBIP21(String address, Map options) { 31 | return Bip21.encode(address, options); 32 | } 33 | 34 | /// Converts bip-21 [uri] into a bch address and its options 35 | /// 36 | /// The return Map will have the following format: 37 | /// ``` 38 | /// { 39 | /// address: 'qpum6dwnqmmysdggrprse8ccjq7ldcrfqgmmtgcmny', 40 | /// options: { 41 | /// amount: 12.5, 42 | /// label: 'coinbase donation', 43 | /// message: 'and ya don\'t stop' 44 | /// } 45 | /// } 46 | /// ``` 47 | static Map decodeBIP21(String uri) { 48 | return Bip21.decode(uri); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /lib/src/crypto/crypto.dart: -------------------------------------------------------------------------------- 1 | import "dart:typed_data"; 2 | import "package:pointycastle/digests/sha512.dart"; 3 | import "package:pointycastle/api.dart" show KeyParameter; 4 | import "package:pointycastle/macs/hmac.dart"; 5 | import "package:pointycastle/digests/ripemd160.dart"; 6 | import "package:pointycastle/digests/sha256.dart"; 7 | 8 | Uint8List hash160(Uint8List buffer) { 9 | Uint8List _tmp = new SHA256Digest().process(buffer); 10 | return new RIPEMD160Digest().process(_tmp); 11 | } 12 | 13 | Uint8List hmacSHA512(Uint8List key, Uint8List data) { 14 | final _tmp = new HMac(new SHA512Digest(), 128)..init(new KeyParameter(key)); 15 | return _tmp.process(data); 16 | } 17 | 18 | Uint8List hash256(Uint8List buffer) { 19 | Uint8List _tmp = new SHA256Digest().process(buffer); 20 | return new SHA256Digest().process(_tmp); 21 | } 22 | -------------------------------------------------------------------------------- /lib/src/crypto/ecurve.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import 'package:hex/hex.dart'; 3 | import 'package:pointycastle/ecc/api.dart' show ECPoint; 4 | import 'package:pointycastle/ecc/curves/secp256k1.dart'; 5 | import "package:pointycastle/src/utils.dart"; 6 | 7 | class ECurve { 8 | static final secp256k1 = new ECCurve_secp256k1(); 9 | static final n = secp256k1.n; 10 | static final G = secp256k1.G; 11 | static final zero32 = Uint8List.fromList(List.generate(32, (index) => 0)); 12 | static final ecGroupOrder = HEX.decode( 13 | "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141"); 14 | static final ecP = HEX.decode( 15 | "fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f"); 16 | 17 | static Uint8List privateAdd(Uint8List d, Uint8List tweak) { 18 | // if (!isPrivate(d)) throw new ArgumentError(THROW_BAD_PRIVATE); 19 | // if (!isOrderScalar(tweak)) throw new ArgumentError(THROW_BAD_TWEAK); 20 | BigInt dd = decodeBigInt(d); 21 | BigInt tt = decodeBigInt(tweak); 22 | Uint8List dt = encodeBigInt((dd + tt) % n); 23 | if (dt.length < 32) { 24 | Uint8List dt2 = Uint8List(32); 25 | for (int i = 0; i < dt.length; i++) { 26 | dt2[i+(32 - dt.length)] = dt[i]; 27 | } 28 | dt = dt2; 29 | } 30 | 31 | if (!isPrivate(dt)) return null; 32 | return dt; 33 | } 34 | 35 | static bool isPrivate(Uint8List x) { 36 | if (!isScalar(x)) return false; 37 | return _compare(x, zero32) > 0 && // > 0 38 | _compare(x, ecGroupOrder) < 0; // < G 39 | } 40 | 41 | static bool isScalar(Uint8List x) { 42 | return x.length == 32; 43 | } 44 | 45 | static Uint8List pointFromScalar(Uint8List d, bool _compressed) { 46 | // if (!isPrivate(d)) throw new ArgumentError(THROW_BAD_PRIVATE); 47 | BigInt dd = decodeBigInt(d); 48 | ECPoint pp = G * dd; 49 | if (pp.isInfinity) return null; 50 | return pp.getEncoded(_compressed); 51 | } 52 | 53 | static Uint8List pointAddScalar( 54 | Uint8List p, Uint8List tweak, bool _compressed) { 55 | // if (!isPoint(p)) throw new ArgumentError(THROW_BAD_POINT); 56 | // if (!isOrderScalar(tweak)) throw new ArgumentError(THROW_BAD_TWEAK); 57 | bool compressed = assumeCompression(_compressed, p); 58 | ECPoint pp = decodeFrom(p); 59 | if (_compare(tweak, zero32) == 0) return pp.getEncoded(compressed); 60 | BigInt tt = decodeBigInt(tweak); 61 | ECPoint qq = G * tt; 62 | ECPoint uu = pp + qq; 63 | if (uu.isInfinity) return null; 64 | return uu.getEncoded(compressed); 65 | } 66 | 67 | static int _compare(Uint8List a, Uint8List b) { 68 | BigInt aa = decodeBigInt(a); 69 | BigInt bb = decodeBigInt(b); 70 | if (aa == bb) return 0; 71 | if (aa > bb) return 1; 72 | return -1; 73 | } 74 | 75 | static bool assumeCompression(bool value, Uint8List pubkey) { 76 | if (value == null && pubkey != null) return _isPointCompressed(pubkey); 77 | if (value == null) return true; 78 | return value; 79 | } 80 | 81 | static bool isPoint(Uint8List p) { 82 | if (p.length < 33) { 83 | return false; 84 | } 85 | var t = p[0]; 86 | var x = p.sublist(1, 33); 87 | 88 | if (_compare(x, zero32) == 0) { 89 | return false; 90 | } 91 | if (_compare(x, ecP) == 1) { 92 | return false; 93 | } 94 | try { 95 | decodeFrom(p); 96 | } catch (err) { 97 | return false; 98 | } 99 | if ((t == 0x02 || t == 0x03) && p.length == 33) { 100 | return true; 101 | } 102 | var y = p.sublist(33); 103 | if (_compare(y, zero32) == 0) { 104 | return false; 105 | } 106 | if (_compare(y, ecP) == 1) { 107 | return false; 108 | } 109 | if (t == 0x04 && p.length == 65) { 110 | return true; 111 | } 112 | return false; 113 | } 114 | 115 | static bool _isPointCompressed(Uint8List p) { 116 | return p[0] != 0x04; 117 | } 118 | 119 | static ECPoint decodeFrom(Uint8List P) => secp256k1.curve.decodePoint(P); 120 | } 121 | -------------------------------------------------------------------------------- /lib/src/ecpair.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import 'dart:math'; 3 | import 'package:bip32/src/utils/ecurve.dart' as ecc; 4 | import 'package:bip32/src/utils/wif.dart' as wif; 5 | import 'package:bitbox/bitbox.dart'; 6 | import 'package:pointycastle/ecc/api.dart'; 7 | 8 | import 'address.dart'; 9 | import 'crypto/crypto.dart'; 10 | import 'utils/network.dart'; 11 | 12 | /// Stores a keypair and provides various methods and factories for creating it and working with it 13 | class ECPair { 14 | final Uint8List _d; 15 | final Uint8List _q; 16 | final Network network; 17 | final bool compressed; 18 | 19 | /// Default constructor. If [network] is not provided, it will assume Bitcoin Cash mainnet 20 | ECPair(this._d, this._q, {network, this.compressed = true}): 21 | this.network = network ?? Network.bitcoinCash(); 22 | 23 | /// Creates a keypair from the private key provided in WIF format 24 | factory ECPair.fromWIF(String wifPrivateKey, {Network network}) { 25 | wif.WIF decoded = wif.decode(wifPrivateKey); 26 | final version = decoded.version; 27 | // TODO support multi networks 28 | Network nw; 29 | if (network != null) { 30 | nw = network; 31 | if (nw.private != version) throw ArgumentError("Invalid network version"); 32 | } else { 33 | if (version == Network.bchPrivate) { 34 | nw = Network.bitcoinCash(); 35 | } else if (version == Network.bchTestnetPrivate) { 36 | nw = Network.bitcoinCashTest(); 37 | } else { 38 | throw ArgumentError("Unknown network version"); 39 | } 40 | } 41 | return ECPair.fromPrivateKey(decoded.privateKey, compressed: decoded.compressed, network: nw); 42 | } 43 | 44 | /// Creates a keypair from [publicKey. The returned keypair will contain [null] private key 45 | factory ECPair.fromPublicKey(Uint8List publicKey, {Network network, bool compressed}) { 46 | if (!ecc.isPoint(publicKey)) { 47 | throw ArgumentError("Point is not on the curve"); 48 | } 49 | return ECPair(null, publicKey, 50 | network: network, compressed: compressed); 51 | } 52 | 53 | /// Creates a keypair from [privateKey] 54 | factory ECPair.fromPrivateKey(Uint8List privateKey, {Network network, bool compressed}) { 55 | if (privateKey.length != 32) 56 | throw ArgumentError( 57 | "Expected property privateKey of type Buffer(Length: 32)"); 58 | if (!ecc.isPrivate(privateKey)) 59 | throw ArgumentError("Private key not in range [1, n)"); 60 | return ECPair(privateKey, null, 61 | network: network, compressed: compressed); 62 | } 63 | 64 | /// Creates a random keypair 65 | factory ECPair.makeRandom({Network network, bool compressed, Function rng}) { 66 | final rfunc = rng ?? _randomBytes; 67 | Uint8List d; 68 | // int beginTime = DateTime.now().millisecondsSinceEpoch; 69 | do { 70 | d = rfunc(32); 71 | if (d.length != 32) throw ArgumentError("Expected Buffer(Length: 32)"); 72 | // if (DateTime.now().millisecondsSinceEpoch - beginTime > 5000) throw ArgumentError("Timeout"); 73 | } while (!ecc.isPrivate(d)); 74 | return ECPair.fromPrivateKey(d, network: network, compressed: compressed); 75 | } 76 | 77 | Uint8List get publicKey => _q ?? ecc.pointFromScalar(_d, compressed); 78 | 79 | Uint8List get privateKey => _d; 80 | 81 | String get address => Address.toBase58Check(hash160(publicKey), network.pubKeyHash); 82 | 83 | /// Returns the private key in WIF format 84 | String toWIF() { 85 | if (privateKey == null) { 86 | throw ArgumentError("Missing private key"); 87 | } 88 | return wif.encode(wif.WIF( 89 | version: network.private, privateKey: privateKey, compressed: compressed)); 90 | } 91 | 92 | /// Returns signature object instead of serialized signature so that it is better handled in bip66 encoding 93 | ECSignature sign(Uint8List hash) { 94 | return eccSign(hash, privateKey); 95 | } 96 | 97 | /// Verifies whether the provided [signature] matches the [hash] using the keypair's [publicKey] 98 | bool verify(Uint8List hash, Uint8List signature) { 99 | return ecc.verify(hash, publicKey, signature); 100 | } 101 | 102 | /// custom EC signature function that returns a signature object instead of serialized result 103 | ECSignature eccSign(Uint8List hash, Uint8List x) { 104 | if (!ecc.isScalar(hash)) throw new ArgumentError(ecc.THROW_BAD_HASH); 105 | if (!ecc.isPrivate(x)) throw new ArgumentError(ecc.THROW_BAD_PRIVATE); 106 | 107 | ECSignature sig = ecc.deterministicGenerateK(hash, x); 108 | 109 | return sig; 110 | } 111 | 112 | } 113 | 114 | const int _SIZE_BYTE = 255; 115 | Uint8List _randomBytes(int size) { 116 | final rng = Random.secure(); 117 | final bytes = Uint8List(size); 118 | for (var i = 0; i < size; i++) { 119 | bytes[i] = rng.nextInt(_SIZE_BYTE); 120 | } 121 | return bytes; 122 | } -------------------------------------------------------------------------------- /lib/src/mnemonic.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'package:bip39/src/bip39_base.dart' as bip39; 4 | 5 | class Mnemonic { 6 | /// Generate bip39 mnemonic 7 | static String generate({int strength = 128}) => bip39.generateMnemonic(strength: strength); 8 | 9 | /// Create root seed from mnemonic 10 | static Uint8List toSeed(String mnemonic) => bip39.mnemonicToSeed(mnemonic); 11 | } -------------------------------------------------------------------------------- /lib/src/rawtransactions.dart: -------------------------------------------------------------------------------- 1 | import 'utils/rest_api.dart'; 2 | 3 | /// Utilities for working raw transactions 4 | class RawTransactions { 5 | /// Send raw transactions to the network. 6 | /// If broadcasting only one transaction, provide it as a [List] with one member. 7 | /// Returns [List] with the resulting txids 8 | static Future> sendRawTransaction(List hexes) async { 9 | final returnedTxIds = await RestApi.sendPostRequest("rawtransactions/sendRawTransaction", "hexes", hexes); 10 | 11 | if (returnedTxIds != null && returnedTxIds is List) { 12 | return List.generate(returnedTxIds.length, (index) => returnedTxIds[index]); 13 | } else { 14 | return null; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/src/utils/bip21.dart: -------------------------------------------------------------------------------- 1 | import 'package:bitbox/bitbox.dart'; 2 | 3 | class Bip21 { 4 | 5 | static Map decode(String uri) { 6 | if (uri.indexOf('bitcoincash') != 0 || uri['bitcoincash'.length] != ":") 7 | throw ("Invalid BIP21 URI"); 8 | 9 | int split = uri.indexOf("?"); 10 | Map uriOptions = Uri.parse(uri).queryParameters; 11 | 12 | Map options = Map.from({ 13 | "message": uriOptions["message"], 14 | "label": uriOptions["label"], 15 | }); 16 | 17 | String address = uri.substring(0, split == -1 ? null : split); 18 | 19 | if (uriOptions["amount"] != null) { 20 | if (uriOptions["amount"].indexOf(",") != -1) 21 | throw ("Invalid amount: commas are invalid"); 22 | 23 | double amount = double.tryParse(uriOptions["amount"]); 24 | if (amount == null || amount.isNaN) 25 | throw ("Invalid amount: not a number"); 26 | if (!amount.isFinite) throw ("Invalid amount: not finite"); 27 | if (amount < 0) throw ("Invalid amount: not positive"); 28 | options["amount"] = amount; 29 | } 30 | 31 | return { 32 | 'address': address, 33 | 'options': options, 34 | }; 35 | } 36 | 37 | static String encode(String address, Map options) { 38 | var hasCashPrefix = address.startsWith('bitcoincash:'); 39 | if (!hasCashPrefix) { 40 | address = 'bitcoincash:$address'; 41 | } 42 | 43 | // Using toLegacyAddress method to test validity of the address format 44 | try { 45 | Address.toLegacyAddress(address); 46 | } catch (e) { 47 | throw FormatException("Invalid Address Format: $address"); 48 | } 49 | 50 | String query = ""; 51 | if (options != null && options.isNotEmpty) { 52 | if (options['amount'] != null) { 53 | if (!options['amount'].isFinite) throw ("Invalid amount: not finite"); 54 | if (options['amount'] < 0) throw ("Invalid amount: not positive"); 55 | } 56 | 57 | Map uriOptions = Map.from(options); 58 | uriOptions.removeWhere((key, value) => value == null); 59 | uriOptions.forEach((key, value) { 60 | uriOptions[key] = value.toString(); 61 | }); 62 | 63 | if (uriOptions.isEmpty) uriOptions = null; 64 | query = Uri(queryParameters: uriOptions).toString(); 65 | // Dart isn't following RFC-3986... 66 | query = query.replaceAll(RegExp(r"\+"), "%20"); 67 | } 68 | 69 | return "$address$query"; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /lib/src/utils/check_types.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import 'dart:math'; 3 | 4 | const SATOSHI_MAX = 21 * 1e14; 5 | 6 | bool isSatoshi(int value) { 7 | return isUint(value, 53) && value <= SATOSHI_MAX; 8 | } 9 | 10 | bool isUint(int value, int bit) { 11 | return (value >= 0 && value <= pow(2, bit) - 1); 12 | } 13 | 14 | bool isHash160bit(Uint8List value) { 15 | return value.length == 20; 16 | } 17 | 18 | bool isHash256bit(Uint8List value) { 19 | return value.length == 32; 20 | } 21 | -------------------------------------------------------------------------------- /lib/src/utils/network.dart: -------------------------------------------------------------------------------- 1 | /// Container for information about crypto networks. 2 | /// 3 | /// This could be used also for other than Bitcoin Cash networks when this library gets extended 4 | 5 | class Network { 6 | static const bchPrivate = 0x80; 7 | static const bchTestnetPrivate = 0xef; 8 | 9 | static const bchPublic = 0x00; 10 | static const bchTestnetPublic = 0x6f; 11 | 12 | final int bip32Private; 13 | final int bip32Public; 14 | final bool testnet; 15 | final int pubKeyHash; 16 | final int private; 17 | final int public; 18 | 19 | Network(this.bip32Private, this.bip32Public, this.testnet, this.pubKeyHash, 20 | this.private, this.public); 21 | 22 | factory Network.bitcoinCash() => 23 | Network(0x0488ade4, 0x0488b21e, false, 0x00, bchPrivate, bchPublic); 24 | factory Network.bitcoinCashTest() => Network( 25 | 0x04358394, 0x043587cf, true, 0x6f, bchTestnetPrivate, bchTestnetPublic); 26 | 27 | String get prefix => this.testnet ? "bchtest" : "bitcoincash"; 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/utils/opcodes.dart: -------------------------------------------------------------------------------- 1 | class Opcodes { 2 | static const OP_FALSE = 0; 3 | static const OP_0 = 0; 4 | static const OP_PUSHDATA1 = 76; 5 | static const OP_PUSHDATA2 = 77; 6 | static const OP_PUSHDATA4 = 78; 7 | static const OP_1NEGATE = 79; 8 | static const OP_RESERVED = 80; 9 | static const OP_TRUE = 81; 10 | static const OP_1 = 81; 11 | static const OP_2 = 82; 12 | static const OP_3 = 83; 13 | static const OP_4 = 84; 14 | static const OP_5 = 85; 15 | static const OP_6 = 86; 16 | static const OP_7 = 87; 17 | static const OP_8 = 88; 18 | static const OP_9 = 89; 19 | static const OP_10 = 90; 20 | static const OP_11 = 91; 21 | static const OP_12 = 92; 22 | static const OP_13 = 93; 23 | static const OP_14 = 94; 24 | static const OP_15 = 95; 25 | static const OP_16 = 96; 26 | static const OP_NOP = 97; 27 | static const OP_VER = 98; 28 | static const OP_IF = 99; 29 | static const OP_NOTIF = 100; 30 | static const OP_VERIF = 101; 31 | static const OP_VERNOTIF = 102; 32 | static const OP_ELSE = 103; 33 | static const OP_ENDIF = 104; 34 | static const OP_VERIFY = 105; 35 | static const OP_RETURN = 106; 36 | static const OP_TOALTSTACK = 107; 37 | static const OP_FROMALTSTACK = 108; 38 | static const OP_2DROP = 109; 39 | static const OP_2DUP = 110; 40 | static const OP_3DUP = 111; 41 | static const OP_2OVER = 112; 42 | static const OP_2ROT = 113; 43 | static const OP_2SWAP = 114; 44 | static const OP_IFDUP = 115; 45 | static const OP_DEPTH = 116; 46 | static const OP_DROP = 117; 47 | static const OP_DUP = 118; 48 | static const OP_NIP = 119; 49 | static const OP_OVER = 120; 50 | static const OP_PICK = 121; 51 | static const OP_ROLL = 122; 52 | static const OP_ROT = 123; 53 | static const OP_SWAP = 124; 54 | static const OP_TUCK = 125; 55 | static const OP_CAT = 126; 56 | static const OP_SPLIT = 127; 57 | static const OP_NUM2BIN = 128; 58 | static const OP_BIN2NUM = 129; 59 | static const OP_SIZE = 130; 60 | static const OP_INVERT = 131; 61 | static const OP_AND = 132; 62 | static const OP_OR = 133; 63 | static const OP_XOR = 134; 64 | static const OP_EQUAL = 135; 65 | static const OP_EQUALVERIFY = 136; 66 | static const OP_RESERVED1 = 137; 67 | static const OP_RESERVED2 = 138; 68 | static const OP_1ADD = 139; 69 | static const OP_1SUB = 140; 70 | static const OP_2MUL = 141; 71 | static const OP_2DIV = 142; 72 | static const OP_NEGATE = 143; 73 | static const OP_ABS = 144; 74 | static const OP_NOT = 145; 75 | static const OP_0NOTEQUAL = 146; 76 | static const OP_ADD = 147; 77 | static const OP_SUB = 148; 78 | static const OP_MUL = 149; 79 | static const OP_DIV = 150; 80 | static const OP_MOD = 151; 81 | static const OP_LSHIFT = 152; 82 | static const OP_RSHIFT = 153; 83 | static const OP_BOOLAND = 154; 84 | static const OP_BOOLOR = 155; 85 | static const OP_NUMEQUAL = 156; 86 | static const OP_NUMEQUALVERIFY = 157; 87 | static const OP_NUMNOTEQUAL = 158; 88 | static const OP_LESSTHAN = 159; 89 | static const OP_GREATERTHAN = 160; 90 | static const OP_LESSTHANOREQUAL = 161; 91 | static const OP_GREATERTHANOREQUAL = 162; 92 | static const OP_MIN = 163; 93 | static const OP_MAX = 164; 94 | static const OP_WITHIN = 165; 95 | static const OP_RIPEMD160 = 166; 96 | static const OP_SHA1 = 167; 97 | static const OP_SHA256 = 168; 98 | static const OP_HASH160 = 169; 99 | static const OP_HASH256 = 170; 100 | static const OP_CODESEPARATOR = 171; 101 | static const OP_CHECKSIG = 172; 102 | static const OP_CHECKSIGVERIFY = 173; 103 | static const OP_CHECKMULTISIG = 174; 104 | static const OP_CHECKMULTISIGVERIFY = 175; 105 | static const OP_NOP1 = 176; 106 | static const OP_NOP2 = 177; 107 | static const OP_CHECKLOCKTIMEVERIFY = 177; 108 | static const OP_NOP3 = 178; 109 | static const OP_CHECKSEQUENCEVERIFY = 178; 110 | static const OP_NOP4 = 179; 111 | static const OP_NOP5 = 180; 112 | static const OP_NOP6 = 181; 113 | static const OP_NOP7 = 182; 114 | static const OP_NOP8 = 183; 115 | static const OP_NOP9 = 184; 116 | static const OP_NOP10 = 185; 117 | static const OP_PUBKEYHASH = 253; 118 | static const OP_PUBKEY = 254; 119 | static const OP_INVALIDOPCODE = 255; 120 | } 121 | -------------------------------------------------------------------------------- /lib/src/utils/p2pkh.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import '../crypto/crypto.dart'; 3 | import '../utils/opcodes.dart'; 4 | import 'package:meta/meta.dart'; 5 | import 'package:bip32/src/utils/ecurve.dart' show isPoint; 6 | import 'package:bs58check/bs58check.dart' as bs58check; 7 | import 'script.dart' as bscript; 8 | 9 | import 'network.dart'; 10 | 11 | /// This is almost exact copy of https://github.com/anicdh/bitcoin_flutter/blob/master/lib/src/payments/p2pkh.dart 12 | /// except using [Opcodes] static members instead of map 13 | class P2PKH { 14 | P2PKHData data; 15 | Network network; 16 | 17 | P2PKH({@required data, network}) { 18 | this.network = network ?? Network.bitcoinCash(); 19 | this.data = data; 20 | _init(); 21 | } 22 | 23 | _init() { 24 | if (data.address != null) { 25 | _getDataFromAddress(data.address); 26 | _getDataFromHash(); 27 | } else if (data.hash != null) { 28 | _getDataFromHash(); 29 | } else if (data.output != null) { 30 | if (!isValidOutput(data.output)) 31 | throw new ArgumentError('Output is invalid'); 32 | data.hash = data.output.sublist(3, 23); 33 | _getDataFromHash(); 34 | } else if (data.pubkey != null) { 35 | data.hash = hash160(data.pubkey); 36 | _getDataFromHash(); 37 | _getDataFromChunk(); 38 | } else if (data.input != null) { 39 | List _chunks = bscript.decompile(data.input); 40 | _getDataFromChunk(_chunks); 41 | if (_chunks.length != 2) throw new ArgumentError('Input is invalid'); 42 | if (!bscript.isCanonicalScriptSignature(_chunks[0])) 43 | throw new ArgumentError('Input has invalid signature'); 44 | if (!isPoint(_chunks[1])) 45 | throw new ArgumentError('Input has invalid pubkey'); 46 | } else { 47 | throw new ArgumentError("Not enough data"); 48 | } 49 | } 50 | 51 | void _getDataFromChunk([List _chunks]) { 52 | if (data.pubkey == null && _chunks != null) { 53 | data.pubkey = (_chunks[1] is int) ? new Uint8List.fromList([_chunks[1]]) : _chunks[1]; 54 | data.hash = hash160(data.pubkey); 55 | _getDataFromHash(); 56 | } 57 | if (data.signature == null && _chunks != null) 58 | data.signature = (_chunks[0] is int) ? new Uint8List.fromList([_chunks[0]]) : _chunks[0]; 59 | if (data.input == null && data.pubkey != null && data.signature != null) { 60 | data.input = bscript.compile([data.signature, data.pubkey]); 61 | } 62 | } 63 | 64 | void _getDataFromHash() { 65 | if (data.address == null) { 66 | final payload = new Uint8List(21); 67 | payload.buffer.asByteData().setUint8(0, network.pubKeyHash); 68 | payload.setRange(1, payload.length, data.hash); 69 | data.address = bs58check.encode(payload); 70 | } 71 | if (data.output == null) { 72 | data.output = bscript.compile([ 73 | Opcodes.OP_DUP, 74 | Opcodes.OP_HASH160, 75 | data.hash, 76 | Opcodes.OP_EQUALVERIFY, 77 | Opcodes.OP_CHECKSIG 78 | ]); 79 | } 80 | } 81 | 82 | void _getDataFromAddress(String address) { 83 | Uint8List payload = bs58check.decode(address); 84 | final version = payload.buffer.asByteData().getUint8(0); 85 | if (version != network.pubKeyHash) 86 | throw new ArgumentError('Invalid version or Network mismatch'); 87 | data.hash = payload.sublist(1); 88 | if (data.hash.length != 20) throw new ArgumentError('Invalid address'); 89 | } 90 | } 91 | 92 | class P2PKHData { 93 | String address; 94 | Uint8List hash; 95 | Uint8List output; 96 | Uint8List signature; 97 | Uint8List pubkey; 98 | Uint8List input; 99 | P2PKHData( 100 | {this.address, 101 | this.hash, 102 | this.output, 103 | this.pubkey, 104 | this.input, 105 | this.signature}); 106 | 107 | @override 108 | String toString() { 109 | return 'P2PKHData{address: $address, hash: $hash, output: $output, signature: $signature, pubkey: $pubkey, input: $input}'; 110 | } 111 | } 112 | 113 | isValidOutput(Uint8List data) { 114 | return data.length == 25 && 115 | data[0] == Opcodes.OP_DUP && 116 | data[1] == Opcodes.OP_HASH160 && 117 | data[2] == 0x14 && 118 | data[23] == Opcodes.OP_EQUALVERIFY && 119 | data[24] == Opcodes.OP_CHECKSIG; 120 | } 121 | -------------------------------------------------------------------------------- /lib/src/utils/pushdata.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | import '../utils/opcodes.dart'; 3 | 4 | class DecodedPushData { 5 | int opcode; 6 | int number; 7 | int size; 8 | DecodedPushData({this.opcode, this.number, this.size}); 9 | } 10 | 11 | class EncodedPushData { 12 | int size; 13 | Uint8List buffer; 14 | 15 | EncodedPushData({this.size, this.buffer}); 16 | } 17 | 18 | EncodedPushData encode(Uint8List buffer, number, offset) { 19 | var size = encodingLength(number); 20 | // ~6 bit 21 | if (size == 1) { 22 | buffer.buffer.asByteData().setUint8(offset, number); 23 | 24 | // 8 bit 25 | } else if (size == 2) { 26 | buffer.buffer.asByteData().setUint8(offset, Opcodes.OP_PUSHDATA1); 27 | buffer.buffer.asByteData().setUint8(offset + 1, number); 28 | 29 | // 16 bit 30 | } else if (size == 3) { 31 | buffer.buffer.asByteData().setUint8(offset, Opcodes.OP_PUSHDATA2); 32 | buffer.buffer.asByteData().setUint16(offset + 1, number, Endian.little); 33 | 34 | // 32 bit 35 | } else { 36 | buffer.buffer.asByteData().setUint8(offset, Opcodes.OP_PUSHDATA4); 37 | buffer.buffer.asByteData().setUint32(offset + 1, number, Endian.little); 38 | } 39 | 40 | return new EncodedPushData(size: size, buffer: buffer); 41 | } 42 | 43 | DecodedPushData decode(Uint8List bf, int offset) { 44 | ByteBuffer buffer = bf.buffer; 45 | int opcode = buffer.asByteData().getUint8(offset); 46 | int number, size; 47 | 48 | // ~6 bit 49 | if (opcode < Opcodes.OP_PUSHDATA1) { 50 | number = opcode; 51 | size = 1; 52 | 53 | // 8 bit 54 | } else if (opcode == Opcodes.OP_PUSHDATA1) { 55 | if (offset + 2 > buffer.lengthInBytes) return null; 56 | number = buffer.asByteData().getUint8(offset + 1); 57 | size = 2; 58 | 59 | // 16 bit 60 | } else if (opcode == Opcodes.OP_PUSHDATA2) { 61 | if (offset + 3 > buffer.lengthInBytes) return null; 62 | number = buffer.asByteData().getUint16(offset + 1); 63 | size = 3; 64 | 65 | // 32 bit 66 | } else { 67 | if (offset + 5 > buffer.lengthInBytes) return null; 68 | if (opcode != Opcodes.OP_PUSHDATA4) 69 | throw new ArgumentError('Unexpected opcode'); 70 | 71 | number = buffer.asByteData().getUint32(offset + 1); 72 | size = 5; 73 | } 74 | 75 | return DecodedPushData(opcode: opcode, number: number, size: size); 76 | } 77 | 78 | int encodingLength(i) { 79 | return i < Opcodes.OP_PUSHDATA1 ? 1 : i <= 0xff ? 2 : i <= 0xffff ? 3 : 5; 80 | } 81 | -------------------------------------------------------------------------------- /lib/src/utils/rest_api.dart: -------------------------------------------------------------------------------- 1 | import 'dart:convert'; 2 | import 'package:http/http.dart' as http; 3 | 4 | class RestApi { 5 | static String _restUrl = "https://rest.bitcoin.com/v2/"; 6 | 7 | static set restUrl(String restUrl) { 8 | _restUrl = restUrl; 9 | } 10 | 11 | static Future sendGetRequest(String path, [String parameter = ""]) async { 12 | final response = await http.get("$_restUrl$path/$parameter"); 13 | 14 | if (response.statusCode == 200) { 15 | return jsonDecode(response.body); 16 | } else { 17 | return null; 18 | } 19 | } 20 | 21 | static sendPostRequest(String path, String postKey, List data, {String returnKey}) async { 22 | final response = await http.post( 23 | "$_restUrl$path", 24 | headers: {"content-type": "application/json"}, 25 | body: jsonEncode({postKey : data}), 26 | ); 27 | 28 | if (response.statusCode != 200) { 29 | throw Exception("${response.reasonPhrase}\n${response.body}"); 30 | } 31 | 32 | if (returnKey == null) { 33 | return jsonDecode(response.body); 34 | } else { 35 | final responseData = jsonDecode(response.body) as List; 36 | 37 | if (!(responseData is List) || !(responseData.first is Map)) { 38 | throw FormatException("return data (below) is not List of Maps: \n${response.body}"); 39 | } 40 | 41 | Map returnMap = {}; 42 | 43 | for (int i = 0; i < responseData.length; i++) { 44 | final item = responseData[i] as Map; 45 | if (!item.containsKey(returnKey)) { 46 | throw FormatException("return data (below) doesn't contain key $returnKey: $item"); 47 | } 48 | returnMap[item[returnKey]] = item; 49 | } 50 | 51 | return returnMap; 52 | } 53 | } 54 | } -------------------------------------------------------------------------------- /lib/src/varuint.dart: -------------------------------------------------------------------------------- 1 | import 'dart:typed_data'; 2 | 3 | import 'utils/check_types.dart'; 4 | Uint8List encode(int number, [Uint8List buffer,int offset]) { 5 | // if (!isUint(number, 53)); 6 | 7 | buffer = buffer ?? new Uint8List(encodingLength(number)); 8 | offset = offset ?? 0; 9 | ByteData bytes = buffer.buffer.asByteData(); 10 | // 8 bit 11 | if (number < 0xfd) { 12 | bytes.setUint8(offset, number); 13 | // 16 bit 14 | } else if (number <= 0xffff) { 15 | bytes.setUint8(offset, 0xfd); 16 | bytes.setUint16(offset + 1, number, Endian.little); 17 | 18 | // 32 bit 19 | } else if (number <= 0xffffffff) { 20 | bytes.setUint8(offset, 0xfe); 21 | bytes.setUint32(offset + 1, number, Endian.little); 22 | 23 | // 64 bit 24 | } else { 25 | bytes.setUint8(offset, 0xff); 26 | bytes.setUint32(offset + 1, number, Endian.little); 27 | bytes.setUint32(offset + 5, (number ~/ 0x100000000) | 0, Endian.little); 28 | } 29 | 30 | return buffer; 31 | } 32 | 33 | int decode (Uint8List buffer, [int offset]) { 34 | offset = offset ?? 0; 35 | ByteData bytes = buffer.buffer.asByteData(); 36 | final first = bytes.getUint8(offset); 37 | 38 | // 8 bit 39 | if (first < 0xfd) { 40 | return first; 41 | // 16 bit 42 | } else if (first == 0xfd) { 43 | return bytes.getUint16(offset + 1, Endian.little); 44 | 45 | // 32 bit 46 | } else if (first == 0xfe) { 47 | return bytes.getUint32(offset + 1, Endian.little); 48 | // 64 bit 49 | } else { 50 | var lo = bytes.getUint32(offset + 1, Endian.little); 51 | var hi = bytes.getUint32(offset + 5, Endian.little); 52 | var number = hi * 0x0100000000 + lo; 53 | if (!isUint(number, 53)) throw ArgumentError("Expected UInt53"); 54 | return number; 55 | } 56 | } 57 | 58 | int encodingLength(int number) { 59 | if (!isUint(number, 53)) throw ArgumentError("Expected UInt53"); 60 | return ( 61 | number < 0xfd ? 1 62 | : number <= 0xffff ? 3 63 | : number <= 0xffffffff ? 5 64 | : 9 65 | ); 66 | } 67 | 68 | 69 | int readUInt64LE (ByteData bytes, int offset) { 70 | final a = bytes.getUint32(offset, Endian.little); 71 | var b = bytes.getUint32(offset + 4, Endian.little); 72 | b *= 0x100000000; 73 | isUint(b + a, 64); 74 | return b + a; 75 | } 76 | 77 | int writeUInt64LE (ByteData bytes, int offset, int value) { 78 | isUint(value, 64); 79 | bytes.setInt32(offset, value & -1, Endian.little); 80 | bytes.setUint32(offset + 4, value ~/ 0x100000000, Endian.little); 81 | return offset + 8; 82 | } -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: bitbox 2 | description: "BITBOX SDK lite for Flutter: build native cross-platform mobile apps with Bitcoin Cash" 3 | version: 0.0.5 4 | homepage: https://github.com/tomasforgacbch/bitbox-flutter 5 | 6 | environment: 7 | sdk: ">=2.1.0 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | http: ^0.12.0+1 13 | bip39: ^1.0.3 14 | pointycastle: ^1.0.1 15 | bip32: ^1.0.5 16 | hex: ^0.1.2 17 | bs58check: ^1.0.1 18 | fixnum: ^0.10.9 19 | meta: ^1.1.6 20 | 21 | dev_dependencies: 22 | flutter_test: 23 | sdk: flutter 24 | 25 | # For information on the generic Dart part of this file, see the 26 | # following page: https://www.dartlang.org/tools/pub/pubspec 27 | 28 | # The following section is specific to Flutter. 29 | flutter: 30 | 31 | # To add assets to your package, add an assets section, like this: 32 | # assets: 33 | # - images/a_dot_burr.jpeg 34 | # - images/a_dot_ham.jpeg 35 | # 36 | # For details regarding assets in packages, see 37 | # https://flutter.dev/assets-and-images/#from-packages 38 | # 39 | # An image asset can refer to one or more resolution-specific "variants", see 40 | # https://flutter.dev/assets-and-images/#resolution-aware. 41 | 42 | # To add custom fonts to your package, add a fonts section here, 43 | # in this "flutter" section. Each entry in this list should have a 44 | # "family" key with the font family name, and a "fonts" key with a 45 | # list giving the asset and other descriptors for the font. For 46 | # example: 47 | # fonts: 48 | # - family: Schyler 49 | # fonts: 50 | # - asset: fonts/Schyler-Regular.ttf 51 | # - asset: fonts/Schyler-Italic.ttf 52 | # style: italic 53 | # - family: Trajan Pro 54 | # fonts: 55 | # - asset: fonts/TrajanPro.ttf 56 | # - asset: fonts/TrajanPro_Bold.ttf 57 | # weight: 700 58 | # 59 | # For details regarding fonts in packages, see 60 | # https://flutter.dev/custom-fonts/#from-packages 61 | --------------------------------------------------------------------------------