What is JellySwap?
JellySwap is a cross-chain atomic swap protocol that supports many different blockchains. The Bitcoin package is used to interact with the Bitcoin Hash Time Locked Contracts and to handle blockchain events. The main components of the module are Providers, Contract, Event, Adapter and Config.
Install package
Using yarn
Copy $ yarn add @jelly-swap/bitcoin
Using npm
Copy $ npm install @jelly-swap/bitcoin
Importing
JavaScript (ES3)
Copy const jellyBtc = require ( '@jelly-swap/bitcoin' );
JavaScript (ES6) / TypeScript
Copy import * as jellyBtc from '@jelly-swap/bitcoin' ;
Config Module
This module contains the main configuration for the whole package
Copy const config = jellyBtc .Config ();
//Expected output
{
network : 'BTC' ,
explorer : 'https://blockstream.info/testnet/tx/' ,
providerUrl : 'https://spacejelly.network/bitpay/api/BTC/testnet' ,
receiverAddress : 'tb1qc4mwllgvmy0xqsdexpm5v8g74ldmv698whnyrw' ,
expiration : 10800 ,
decimals : 8 ,
unix : true ,
apiProviderUrl : 'https://spacejelly.network/btc/api/v1/btc'
}
Provider Module
A Provider abstracts a connection to the Bitcoin blockchain, for issuing queries and sending signed state changing transactions.
BitcoinProvider - allows you to connect to Bitcoin nodes you control or have access to, including mainnet, testnets, etc.
Copy const btcProvider = new jellyBtc . Providers .BitcoinProvider (
"https://spacejelly.network/btc/api/v1/btc"
);
Contract Module
Create contract instance:
Copy const btcContract = new jellyBtc .Contract (
btcWallet ,
network ? ,
"https://spacejelly.network/btc/api/v1/btc" ?
);
subscribe
Copy await btcContract .subscribe (onEvent , filter ? );
getPastEvents
Returns past blockchain events.
Copy const pastEvents = await btcContract .getPastEvents (eventType , filter ? , currentBlock ? );
getCurrentBlock
Returns the latest block.
Copy const currentBlock = await btcContract .getCurrentBlock ();
getBalance
Returns the balance of the given address.
Copy const balance = await btcContract .getBalance (address , network);
newContract
Creates and broadcasts a new swap transaction.
Copy const transactionHashSwap = await btcContract .newContract (swap);
withdraw
Creates and broadcasts a withdraw transaction.
Copy const transactionHashWithdraw = await btcContract .withdraw (withdraw);
refund
Creates and broadcasts a refund transaction.
Copy const transactionHashRefund = await btcContract .refund (contractRefund);
Event module
Event module is used to read past blockchain events and subscribe for new ones
Initialize event module:
Copy const btcEvents = new jellyBtc .Event (btcContract);
getPast
Returns past blockchain events.
Copy const pastEvents = await btcEvents .getPast (eventType , filter ? , currentBlock ? );
subscribe
Copy await btcEvents .subscribe (onEvent , filter ? );
Adapter module
The Adapter module is used to format the client data and prepare the input for the swaps.
Initialize adapter module:
Copy const btcAdapter = new jellyBtc .Adapter ();
generateId
Generate swap id based on the input parameters. The same id will be generated by the Solidity Contract.
Copy const id = btcAdapter .generateId (input);
addressValid
Checks if the passed address is valid or not.
Copy const isAddressValid = btcAdapter .addressValid (address);
parseAddress
Returns the address in lower case.
Copy const addressParsed = btcAdapter .parseAddress (address);
parseToNative
Parse BTC amount to satoshi amount i.e. 0.1 to 10000000
Copy const result = btcAdapter .parseToNative (amount);
parseFromNative
Parse satoshi amount to BTC amount i.e. 10000000 to 0.1
Copy const result = btcAdapter .parseFromNative (amount);
formatInput
Returns object of type UserInputSwap.
Copy const swapInput = btcAdapter .formatInput (data , receiver);
Example
Copy const jellyBtc = require ( "@jelly-swap/bitcoin" );
const { Wallet , Networks } = require ( "@jelly-swap/btc-wallet" );
const btcProvider = new jellyBtc . Providers .BitcoinProvider (
"https://spacejelly.network/btc/api/v1/btc"
);
const network = Networks .bitcoin;
const btcWallet = new Wallet (
network ,
"witch collapse practice feed shame open despair creek road again ice least" ,
"bech32" ,
btcProvider
);
const btcContract = new jellyBtc .Contract (
btcWallet ,
network ,
"https://spacejelly.network/btc/api/v1/btc"
);
const adapter = new jellyBtc .Adapter ();
const subscribeFilter = type => {
const address = "bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4" ;
switch (type) {
case "new" : {
return () => {
return {
type : "getSwapsByAddressAndBlock" ,
address
};
};
}
case "withdraw" : {
return () => {
return {
type : "getWithdrawByReceiverAndBlock" ,
address
};
};
}
default : {
break ;
}
}
};
const swapsFilter = type => {
const address = "bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4" ;
switch (type) {
case "new" : {
return () => {
return {
type : "getSwapsByAddress" ,
address
};
};
}
case "withdraw" : {
return () => {
return {
type : "getWithdrawByReceiver" ,
address
};
};
}
default : {
break ;
}
}
};
async function start () {
// Subscribe for contract events and pass handle function
await btcContract .subscribe (() => {} , subscribeFilter);
// Get past blockchain events
const swaps = await btcContract .getPastEvents ( "new" , swapsFilter ( "new" ));
console .log (swaps);
//...
// { blockHeight: 616793,
// transactionHash: 'd15d985165708af57d08d17986bde6140ed655e49fa420fbc7e39a258900d6c1',
// id: '0x47b3f15cf1837a8f293df06d5846514f413025b8c978031e62a59400d0d1c22e',
// status: 3,
// inputAmount: 221300,
// sender: 'bc1qwjeylyfrkn8sckwux789dqtscafujhgy4xcddg',
// receiver: 'bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4',
// refundAddress: 'bc1qwjeylyfrkn8sckwux789dqtscafujhgy4xcddg',
// network: 'BTC',
// outputNetwork: 'ETH',
// outputAddress: '0xb2cB83E2E367682B2C0d3AAF04131Dd94C41A1A9',
// outputAmount: '100000000000000000',
// expiration: 1581341813,
// hashLock: '0x6a98ad2137e52aaf0eb29f44fc97084bf45a33115a0850c4355a1dcfba95c1d6',
// _id: '5e41475f84702846cfe3a4e3',
// createdAt: '2020-02-10T12:28:48.794Z',
// withdrawTxHash: 'a0aadca779be5e5a9775da357634a3655fc049244a255376bf1f58976d868606' },
//...
const withdraws = await btcContract .getPastEvents (
"withdraw" ,
swapsFilter ( "withdraw" )
);
console .log (withdraws);
//...
// [ { blockHeight: 616794,
// transactionHash: 'a0aadca779be5e5a9775da357634a3655fc049244a255376bf1f58976d868606',
// id: '0x47b3f15cf1837a8f293df06d5846514f413025b8c978031e62a59400d0d1c22e',
// secret: '0xce79be42bd15a541845c6f3e6d24e053460a8062e74082440f768705b6fa2b6a',
// hashLock: '0x6a98ad2137e52aaf0eb29f44fc97084bf45a33115a0850c4355a1dcfba95c1d6',
// sender: 'bc1qwjeylyfrkn8sckwux789dqtscafujhgy4xcddg',
// receiver: 'bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4',
// network: 'BTC',
// _id: '5e4148ea84702846cfe3a4e4',
// createdAt: '2020-02-10T12:13:30.057Z' } ]
//...
const refunds = await btcContract .getPastEvents (
"refund" ,
swapsFilter ( "refund" )
);
console .log (refunds);
//...
// [ { blockHeight: 616794,
// transactionHash: 'a0aadca779be5e5a9775da357634a3655fc049244a255376bf1f58976d868606',
// id: '0x47b3f15cf1837a8f293df06d5846514f413025b8c978031e62a59400d0d1c22e',
// secret: '0xce79be42bd15a541845c6f3e6d24e053460a8062e74082440f768705b6fa2b6a',
// hashLock: '0x6a98ad2137e52aaf0eb29f44fc97084bf45a33115a0850c4355a1dcfba95c1d6',
// sender: 'bc1qwjeylyfrkn8sckwux789dqtscafujhgy4xcddg',
// receiver: 'bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4',
// network: 'BTC',
// _id: '5e4148ea84702846cfe3a4e4',
// createdAt: '2020-02-10T12:13:30.057Z' } ]
//...
const currentBlock = await btcProvider .getBlockHeight ();
console .log (currentBlock);
//616241
const balance = await btcContract .getBalance (
"bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4" ,
network
);
console .log ( adapter .parseFromNative (balance));
//0.00183863
// ================ SWAP ================
const userInputSwap = {
inputAmount : "0.00001" ,
network : "BTC" ,
outputAddress : "0xD6Ff8542eC1606772fF29946218a624b08A1D51E" ,
outputAmount : "0.0004488" ,
outputNetwork : "ETH" ,
secret :
"pond cram isolate chair float moon tongue firm spirit hand peace together" ,
sender : "bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4"
};
const swap = adapter .formatInput (userInputSwap);
console .log (swap);
// { inputAmount: '1000',
// network: 'BTC',
// outputAddress: '0xD6Ff8542eC1606772fF29946218a624b08A1D51E',
// outputAmount: '0.0004488',
// outputNetwork: 'ETH',
// secret: 'pond cram isolate chair float moon tongue firm spirit hand peace together',
// sender: 'bc1qsdejyek0kw5n2m2xhesc9x5yj35wtsjj2uzpe4',
// hashLock: '0x4af116ee28ecde1d2b71e49fb964fe76a20c694c94f6895c1baa8ed1d1b06dda',
// receiver: 'tb1qc4mwllgvmy0xqsdexpm5v8g74ldmv698whnyrw',
// expiration: 1581359277 }
const swapHash = await btcContract .newContract (swap);
console .log (swapHash);
//5013c0b0005af10cd9db82e63a18e8bc248c843993f9433fcf00d3611663dc56
// ================ REFUND ================
const refund = {
id : "5e41738da5d71552f72e2faf"
};
try {
const refundHash = await btcContract .refund (refund);
console .log (refundHash);
//5013c0b0005af10cd9db82e63a18e8bc248c843993f9433fcf00d3611663dc56
} catch (e) {
console .log ( "Refund Error. Check timestamp and id params." );
}
// ================ WITHDRAW ================
const withdraw = {
id : "5e41738da5d71552f72e2faf" ,
secret : "c5f715ae9c3f79aed4af080f881385e22cec3ecb2811740e7018daea79dcc15c"
};
try {
const withdrawHash = await btcContract .withdraw (withdraw);
console .log (withdrawHash);
//5013c0b0005af10cd9db82e63a18e8bc248c843993f9433fcf00d3611663dc56
} catch (e) {
console .log ( "Withdraw Error. Check timestamp, id and secret params." );
}
}