ic_cdk_bitcoin_canister/
lib.rs1#![doc = include_str!("../README.md")]
2
3pub use ic_btc_interface::*;
4
5use candid::Principal;
6use ic_cdk::call::{Call, CallResult};
7
8const MAINNET_ID: Principal = Principal::from_slice(&[0, 0, 0, 0, 1, 160, 0, 4, 1, 1]); const TESTNET_ID: Principal = Principal::from_slice(&[0, 0, 0, 0, 1, 160, 0, 1, 1, 1]); const REGTEST_ID: Principal = Principal::from_slice(&[0, 0, 0, 0, 1, 160, 0, 1, 1, 1]); const GET_UTXO_MAINNET: u128 = 10_000_000_000;
15const GET_UTXO_TESTNET: u128 = 4_000_000_000;
16
17const GET_BALANCE_MAINNET: u128 = 100_000_000;
18const GET_BALANCE_TESTNET: u128 = 40_000_000;
19
20const GET_CURRENT_FEE_PERCENTILES_MAINNET: u128 = 100_000_000;
21const GET_CURRENT_FEE_PERCENTILES_TESTNET: u128 = 40_000_000;
22
23const GET_BLOCK_HEADERS_MAINNET: u128 = 10_000_000_000;
24const GET_BLOCK_HEADERS_TESTNET: u128 = 4_000_000_000;
25
26const SEND_TRANSACTION_SUBMISSION_MAINNET: u128 = 5_000_000_000;
27const SEND_TRANSACTION_SUBMISSION_TESTNET: u128 = 2_000_000_000;
28
29const SEND_TRANSACTION_PAYLOAD_MAINNET: u128 = 20_000_000;
30const SEND_TRANSACTION_PAYLOAD_TESTNET: u128 = 8_000_000;
31
32pub fn get_bitcoin_canister_id(network: Network) -> Principal {
34 match network {
35 Network::Mainnet => MAINNET_ID,
36 Network::Testnet => TESTNET_ID,
37 Network::Regtest => REGTEST_ID,
38 }
39}
40
41pub async fn bitcoin_get_utxos(arg: &GetUtxosRequest) -> CallResult<GetUtxosResponse> {
47 let canister_id = get_bitcoin_canister_id(arg.network.into());
48 let cycles = cost_get_utxos(arg);
49 Ok(Call::bounded_wait(canister_id, "bitcoin_get_utxos")
50 .with_arg(arg)
51 .with_cycles(cycles)
52 .await?
53 .candid()?)
54}
55
56pub fn cost_get_utxos(arg: &GetUtxosRequest) -> u128 {
63 match Network::from(arg.network) {
64 Network::Mainnet => GET_UTXO_MAINNET,
65 Network::Testnet => GET_UTXO_TESTNET,
66 Network::Regtest => GET_UTXO_MAINNET,
67 }
68}
69
70pub async fn bitcoin_get_balance(arg: &GetBalanceRequest) -> CallResult<Satoshi> {
76 let canister_id = get_bitcoin_canister_id(arg.network.into());
77 let cycles = cost_get_balance(arg);
78 Ok(Call::bounded_wait(canister_id, "bitcoin_get_balance")
79 .with_arg(arg)
80 .with_cycles(cycles)
81 .await?
82 .candid()?)
83}
84
85pub fn cost_get_balance(arg: &GetBalanceRequest) -> u128 {
92 match Network::from(arg.network) {
93 Network::Mainnet => GET_BALANCE_MAINNET,
94 Network::Testnet => GET_BALANCE_TESTNET,
95 Network::Regtest => GET_BALANCE_MAINNET,
96 }
97}
98
99pub async fn bitcoin_get_current_fee_percentiles(
107 arg: &GetCurrentFeePercentilesRequest,
108) -> CallResult<Vec<MillisatoshiPerByte>> {
109 let canister_id = get_bitcoin_canister_id(arg.network.into());
110 let cycles = cost_get_current_fee_percentiles(arg);
111 Ok(
112 Call::bounded_wait(canister_id, "bitcoin_get_current_fee_percentiles")
113 .with_arg(arg)
114 .with_cycles(cycles)
115 .await?
116 .candid()?,
117 )
118}
119
120pub fn cost_get_current_fee_percentiles(arg: &GetCurrentFeePercentilesRequest) -> u128 {
127 match Network::from(arg.network) {
128 Network::Mainnet => GET_CURRENT_FEE_PERCENTILES_MAINNET,
129 Network::Testnet => GET_CURRENT_FEE_PERCENTILES_TESTNET,
130 Network::Regtest => GET_CURRENT_FEE_PERCENTILES_MAINNET,
131 }
132}
133
134pub async fn bitcoin_get_block_headers(
140 arg: &GetBlockHeadersRequest,
141) -> CallResult<GetBlockHeadersResponse> {
142 let canister_id = get_bitcoin_canister_id(arg.network.into());
143 let cycles = cost_get_block_headers(arg);
144 Ok(Call::bounded_wait(canister_id, "bitcoin_get_block_headers")
145 .with_arg(arg)
146 .with_cycles(cycles)
147 .await?
148 .candid()?)
149}
150
151pub fn cost_get_block_headers(arg: &GetBlockHeadersRequest) -> u128 {
158 match Network::from(arg.network) {
159 Network::Mainnet => GET_BLOCK_HEADERS_MAINNET,
160 Network::Testnet => GET_BLOCK_HEADERS_TESTNET,
161 Network::Regtest => GET_BLOCK_HEADERS_MAINNET,
162 }
163}
164
165pub async fn get_blockchain_info(network: Network) -> CallResult<BlockchainInfo> {
175 let canister_id = get_bitcoin_canister_id(network);
176 Ok(Call::bounded_wait(canister_id, "get_blockchain_info")
177 .await?
178 .candid()?)
179}
180
181pub async fn bitcoin_send_transaction(arg: &SendTransactionRequest) -> CallResult<()> {
187 let canister_id = get_bitcoin_canister_id(arg.network.into());
188 let cycles = cost_send_transaction(arg);
189 Ok(
190 Call::unbounded_wait(canister_id, "bitcoin_send_transaction")
191 .with_arg(arg)
192 .with_cycles(cycles)
193 .await?
194 .candid()?,
195 )
196}
197
198pub fn cost_send_transaction(arg: &SendTransactionRequest) -> u128 {
205 let (submission, payload) = match Network::from(arg.network) {
206 Network::Mainnet => (
207 SEND_TRANSACTION_SUBMISSION_MAINNET,
208 SEND_TRANSACTION_PAYLOAD_MAINNET,
209 ),
210 Network::Testnet => (
211 SEND_TRANSACTION_SUBMISSION_TESTNET,
212 SEND_TRANSACTION_PAYLOAD_TESTNET,
213 ),
214 Network::Regtest => (
215 SEND_TRANSACTION_SUBMISSION_MAINNET,
216 SEND_TRANSACTION_PAYLOAD_MAINNET,
217 ),
218 };
219 submission + payload * arg.transaction.len() as u128
220}