sendBitcoin 함수 구현하기
1. 지갑 생성
2. 생성한 주소에 비트코인 전송
3. sendBTC.js > sendBitcoin 함수 구현
3-1) API 사용해 Get Unspent Transactions
참고 : https://sochain.com/api/#get-network-confidence
https://chain.so/api/v2/get_tx_unspent/${sochain_network}/${sourceAddress}
ex) https://chain.so/api/v2/get_tx_unspent/BTCTEST/mngfToQdYLdetGDoZDHmYCzECitg9yxbPt
sochain_network : BTCTEST (bitcoin testnet)
sourceAddress : wallet address.
결과 :
하나의 트랜잭션 반환.
txid : 트랜잭션 id
여러 개의 트랜잭션이 생성될 경우 txs 배열에 트랜잭션이 추가됨.
3-2) Get Unspent Transactions 코드
sourceAddress : 우리가 비트코인을 보내기 위해 비트코인 자금을 가지고 있는 주소.
response : sourceAddress 통해 전달된 트랜잭션들을 확인
sochain_network : BTC testnet
const sochain_network = "BTCTEST";
const privateKey =
"5d264784f587621ffae7013405b2ffb862b9115c0839dc1844263243c800538d";
const sourceAddress = "mngfToQdYLdetGDoZDHmYCzECitg9yxbPt";
const response = await axios.get(
`https://chain.so/api/v2/get_tx_unspent/${sochain_network}/${sourceAddress}`
);
3-3) transaction fee
참고 :
각기 다른 Fee와 Time을 갖고 있음
API 통해 사람들이 사용하는 수수료에 대한 요약/평균 정보 얻을 수 있음
https://bitcoinfees.earn.com/api/v1/fees/recommended
const recommendedFee = await axios.get(
"https://bitcoinfees.earn.com/api/v1/fees/recommended"
);
3-4) 여러 개의 트랜잭션에 대해 input 추가하기
let inputCount = 0
- 초기값. 이후 주소에 해당하는 모든 input 트랜잭션 수를 계산해 업데이트.
let outputCount = 2
- output은 항상 최소 기본 2개가 됨. 수신자의 주소로 보내는 출력 하나, 나에게 변경사항을 반영한 잔액이 돌아오는 출력 하나.
let inputCount = 0;
let outputCount = 2;
bitcore.Transaction 사용하기
const transaction = new bitcore.Transaction();
input 초기화
모든 unspent 트랜잭션 가져와 input으로 추가, 사용가능코인량 totalAmountAvailable 업데이트
response :
let inputs = [];
let utxos = response.data.data.txs;
for (const element of utxos) {
let utxo = {};
utxo.satoshis = Math.floor(Number(element.value) * 100000000);
utxo.script = element.script_hex;
utxo.address = response.data.data.address;
utxo.txId = element.txid;
utxo.outputIndex = element.output_no;
totalAmountAvailable += utxo.satoshis;
inputCount += 1;
inputs.push(utxo);
}
3-5) 트랜잭션에 보내기
fee 의 경우 테스트 시 수수료를 적게 내고 싶으면 나눠서 크기를 줄임. 다른 이유는 없음.
Balance check.
const transactionSize =
inputCount * 180 + outputCount * 34 + 10 - inputCount;
fee = (transactionSize * recommededFee.data.hourFee) / 3;
// Balance check
if (totalAmountAvailable - satoshiToSend - fee < 0) {
throw new Error("Balance is too low for this transaction");
}
받는 주소, 보낼 금액 전달,
보낼 금액 전송 후 남은 금액 보낼 주소 (내주소 / 혹은 다른 주소로 보내도 됨),
개인키 전달해 서명... send Transaction 생성
// Set transaction input
transaction.from(inputs);
// Set recieverAddress and amountToSend
transaction.to(recieverAddress, satoshiToSend);
// Update sender Address (receive the left over funds after transfer)
transaction.change(sourceAddress);
console.log(satoshiToSend, fee);
// manually set transaction fees - 20 satoshis per byte
transaction.fee(Math.round(fee));
// Sign transaction with sender privateKey
transaction.sign(privateKey);
트랜잭션 serialize,
send Transaction
POST /api/v2/send_tx/{NETWORK}
// serialize transactions
console.log(transaction.serialize());
const serializedTransaction = transaction.serialize();
// Send transaction
const result = await axios({
method: "POST",
url: `https://chain.so/api/v2/send_tx/${sochain_network}`,
data: {
tx_hex: serializedTransaction,
},
});
성공 시 트랜잭션 반환, 실패 시 예외처리
try {
...
return result.data.data;
} catch (error) {
return error;
}
전체코드
src > api > sendBTC.js
const axios = require("axios");
const bitcore = require("bitcore-lib");
const sendBitcoin = async (recieverAddress, amountToSend) => {
try {
const sochain_network = "BTCTEST";
const privateKey =
"5d264784f587621ffae7013405b2ffb862b9115c0839dc1844263243c800538d";
const sourceAddress = "mngfToQdYLdetGDoZDHmYCzECitg9yxbPt";
const satoshiToSend = amountToSend * 100000000;
let fee = 0;
let inputCount = 0;
let outputCount = 2;
const response = await axios.get(
`https://chain.so/api/v2/get_tx_unspent/${sochain_network}/${sourceAddress}`
);
const recommededFee = await axios.get(
"https://bitcoinfees.earn.com/api/v1/fees/recommended"
);
const transaction = new bitcore.Transaction();
let totalAmountAvailable = 0;
let inputs = [];
let utxos = response.data.data.txs;
for (const element of utxos) {
let utxo = {};
utxo.satoshis = Math.floor(Number(element.value) * 100000000);
utxo.script = element.script_hex;
utxo.address = response.data.data.address;
utxo.txId = element.txid;
utxo.outputIndex = element.output_no;
totalAmountAvailable += utxo.satoshis;
inputCount += 1;
inputs.push(utxo);
}
const transactionSize =
inputCount * 180 + outputCount * 34 + 10 - inputCount;
fee = (transactionSize * recommededFee.data.hourFee) / 3;
// Balance check
if (totalAmountAvailable - satoshiToSend - fee < 0) {
throw new Error("Balance is too low for this transaction");
}
// Set transaction input
transaction.from(inputs);
// Set recieverAddress and amountToSend
transaction.to(recieverAddress, satoshiToSend);
// Update sender Address (receive the left over funds after transfer)
transaction.change(sourceAddress);
console.log(satoshiToSend, fee);
// manually set transaction fees - 20 satoshis per byte
transaction.fee(Math.round(fee));
// Sign transaction with sender privateKey
transaction.sign(privateKey);
// serialize transactions
console.log(transaction.serialize());
const serializedTransaction = transaction.serialize();
// Send transaction
const result = await axios({
method: "POST",
url: `https://chain.so/api/v2/send_tx/${sochain_network}`,
data: {
tx_hex: serializedTransaction,
},
});
return result.data.data;
} catch (error) {
return error;
}
};
module.exports = {
sendBitcoin: sendBitcoin,
};
메인넷 사용 ==> sochain_network = "BTC"
4. sendTransaction 실행해보기
src > app.js
const { sendBitcoin } = require("./api/sendBTC");
sendBitcoin("mhe5hkmx26CZkbMPprQQifLLwqfb5pZUKZ", 0.0001)
.then((result) => {
console.log(result);
})
.catch((error) => {
console.log(error);
});
테스트넷에서 확인하기
https://www.blockchain.com/btc-testnet/address/mhe5hkmx26CZkbMPprQQifLLwqfb5pZUKZ
mhe5hkmx26CZkbMPprQQifLLwqfb5pZUKZ 주소로 0.0001BTC 전송
수수료 제외한 나머지 금액은 내 주소로 전송
transaction hash 확인
unspent transaction 에서 변화된 value확인
https://chain.so/api/v2/get_tx_unspent/BTCTEST/mngfToQdYLdetGDoZDHmYCzECitg9yxbPt
value 변화. 0.0005 -> 0.00032461
spent transaction 확인
https://chain.so/api/v2/get_tx_spent/BTCTEST/mngfToQdYLdetGDoZDHmYCzECitg9yxbPt
***
serialized transaction 을 push해서 트랜잭션 생성할 수 있음
https://live.blockcypher.com/btc/pushtx/
serialized transaction :
0200000001d4e154490d0c4be455f2aa94d4ff71bc12e634f601a15effcb7ba6fc41001d8c010000006a473044022061be827f864e6d10278fbf922c75cd5d2f6c7df026856e0dab420425f6d799b902201b9b5a7784b19ab8312bcd10bccf3803b6ad1818bb70260e39ae132141f3cb9c012102352cdb60484be3cf898dbebebd1a8641a3818d50822e6a66fa82ba5808032a72ffffffff0210270000000000001976a91417495904a810c3b4e42381dedb777ad14074b25b88ac4a3a0000000000001976a9144e9efd4fe5e4e7380982af853b886a69a57a01b088ac00000000
참고 :
https://sochain.com/api/#get-network-confidence
https://bitcoinfaucet.uo1.net/
https://www.blockchain.com/explorer/assets/btc-testnet
'blockchain' 카테고리의 다른 글
[HD wallet] BIP32, BIP39, BIP44 (0) | 2024.05.08 |
---|---|
[Metamask] 메타마스크에 네트워크 추가하기 (Avalanche) (0) | 2024.05.02 |
[BitcoinWallet] HD wallet 생성 (0) | 2022.10.27 |
[BitcoinWallet] 생성한 testnet주소로 bitcoin 보내기 (1) | 2022.10.27 |
[BitcoinWallet] wallet에 필요한 private key, address 생성 (0) | 2022.10.27 |
댓글