What is JellySwap?
JellySwap is a cross-chain atomic swap protocol that supports many different blockchains. The aeternity package is used to interact with the Aeternity 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/aeternity@0.1.26-node
Using npm
Copy $ npm install @jelly-swap/aeternity@0.1.26-node
Importing
JavaScript (ES3)
Copy const jellyAeternity = require ( '@jelly-swap/aeternity' );
JavaScript (ES6) / TypeScript
Copy import * as jellyAeternity from '@jelly-swap/aeternity' ;
Config Module
This module contains the main configuration for the whole package.
Copy const config = jellyAeternity .Config (token ? , expiration ? );
//Expected output
{
network : 'AE' ,
explorer : 'https://testnet.explorer.aepps.com/transactions/' ,
providerUrl : 'https://sdk-testnet.aepps.com/' ,
internalUrl : 'https://sdk-testnet.aepps.com/' ,
compilerUrl : 'https://compiler.aepps.com' ,
wsUrl : 'wss://testnet.aeternal.io/websocket' ,
contractAddress : 'ct_2M9XPMwz1GggFRPatEd2aAPZbig32ZqRJBnhTT2yRVM4k6CQnb' ,
receiverAddress : 'ak_2ifr2XxhrMskWdnXZqJE2mVhhwhXYvQD6nRGYLMR5mTSHW4RZz' ,
blockTime : 15 ,
expiration : 10800 ,
decimals : 18 ,
unix : false ,
apiUrl : 'https://testnet.aeternal.io/'
}
Provider Module
A Provider abstracts a connection to the Aeternity blockchain, for issuing queries and sending signed state changing transactions.
HTTP Provider - allows you to connect to Aeternity nodes you control or have access to, including mainnet, testnets, etc.
Copy const httpProvider = new jellyAeternity . Providers .HTTP ();
Waellet Provider
Copy const waelletProvider = new jellyAeternity . Providers .Waellet ();
Contract Module
Contract module is used to interact with the Sophia Contract and get blockchain specific data (balance, blockNumber, subscribe to events, get past events).
Create contract instance:
Copy const aeternityContract = new jellyAeternity .Contract (provider);
subscribe
Copy await jellyContract .subscribe (onEvent , filter ? );
getPastEvents
Returns past blockchain events.
Copy const pastEvents = await jellyContract .getPastEvents (eventType ? , filter ? , currentBlock ? );
getCurrentBlock
Returns the latest block.
Copy const currentBlock = await aeternityContract .getCurrentBlock ();
getBalance
Returns the balance of the given address.
Copy const balance = await aeternityContract .getBalance (address);
getStatus
Returns the swaps statuses by given ids.
Copy const statuses = await aeternityContract .getStatus (ids);
newContract
Creates and broadcasts a new swap transaction.
Copy const transactionHashSwap = await aeternityContract .newContract (swap);
withdraw
Creates and broadcasts a withdraw transaction.
Copy const transactionHashWithdraw = await aeternityContract .withdraw (withdraw);
refund
Creates and broadcasts a refund transaction.
Copy const transactionHashRefund = await aeternityContract .refund (contractRefund);
Event module
Event module is used to read past blockchain events and subscribe for new ones
Initialize event module:
Copy const aeternityEvents = new jellyAeternity .Event (aeternityContract);
getPast
Returns past blockchain events.
Copy const pastEvents = await aeternityEvents .getPast (eventType , filter ? , currentBlock ? );
subscribe
Copy await aeternityEvents .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 aeternityAdapter = new jellyAeternity .Adapter ();
generateId
Generate swap id based on the input parameters. The same id will be generated by the Solidity Contract.
Copy const id = aeternityAdapter .generateId (input);
addressValid
Checks if the passed address is valid or not.
Copy const isAddressValid = aeternityAdapter .addressValid (address);
parseAddress
Returns the address in lower case.
Copy const addressParsed = aeternityAdapter .parseAddress (address);
parseToNative
Parse AE amount to aetto amount i.e. 0.1 to 100000000000000000
Copy const result = aeternityAdapter .parseToNative (amount);
parseFromNative
Parse aetto amount to AE amount i.e. 100000000000000000 to 0.1
Copy const result = aeternityAdapter .parseFromNative (amount);
formatInput
Returns object of type UserInputSwap.
Copy const swapInput = aeternityAdapter .formatInput (data , receiver);
Example
Copy const jellyAeternity = require ( "@jelly-swap/aeternity" );
const config = jellyAeternity .Config ();
const httpProvider = new jellyAeternity . Providers .HTTP (config , {
publicKey : "ak_SMwGaaRfryc8s7wPhpa1jzxAAtJfkWz2rZG5zrBny968Eqiqr" ,
secretKey :
"e6f7f740df605b297e1aec7326688ef8d31bed76d8e00f8f2ca76ff712938e373995cd2684368479b0d1069ea1471fc9926c0ca6489bc728f0b94c14c2c42fa0"
});
const adapter = new jellyAeternity .Adapter ();
const { fixHash } = require ( "@jelly-swap/utils" );
const aeternityContract = new jellyAeternity .Contract (httpProvider);
async function start () {
// Subscribe for contract events and pass handle function
await aeternityContract .subscribe (e => {
console .log (e);
});
// Get past blockchain events
const swaps = await aeternityContract .getPastEvents ();
console .log (swaps);
//...
// { eventName: 'NEW_CONTRACT',
// network: 'AE',
// id:
// 'b15bc721ef3b6d50b110aebea870b0ddccb71221014a6e5ae76ee524fe9da990',
// sender: 'ak_2ifr2XxhrMskWdnXZqJE2mVhhwhXYvQD6nRGYLMR5mTSHW4RZz',
// receiver: 'ak_SxZpugqQpL6qBpDd5mUjs5mbHhCLjSK9V3DGLxk1kXyc2Uj42',
// outputNetwork: 'ETH',
// outputAddress: '0xF684C21Ec023E93da0B402ac0a274317eb51C2c7',
// inputAmount: '95285930000000000000',
// outputAmount: '100000000000000000',
// expiration: '1577530273701',
// hashLock:
// '0x1f379a22ab114074d40e4fe7eb5c2493a1ddd3c0b7066e222d2087f0330f66df',
// transactionHash: 'th_2TiizaRHoSEiFQy1woCGi87sGV97cR7E9jiSFVqSMq1TopA1yB' }
//...
const withdraws = await aeternityContract .getPastEvents ( "withdraw" , w => w);
console .log (withdraws);
//...
// { eventName: 'WITHDRAW',
// network: 'AE',
// id:
// '0xc44499faac054495162e19b13f949ea4dbc2a327c2cf0c674be716f0a853cf19',
// sender: 'ak_2ifr2XxhrMskWdnXZqJE2mVhhwhXYvQD6nRGYLMR5mTSHW4RZz',
// receiver: 'ak_2oJ2LR2N5jy5hZsxYnu9fynhUztbbuFyFp16ENPrkRidSVHCcL',
// hashLock:
// '0x97e7c1bb168c06e0d068c8d6b1f276eba8fc927f7cc6cb7943ee24d13e242329',
// secret:
// '0x1652d513caca3a90c18d93bd0ed358d546ff0bcc147e7128116da64fef3d4fc2',
// transactionHash: 'th_ozHApXME3zNxcp3QAL8PdE266DwmxiKFEw2WVaGpXEbm46Cjm' },
//...
const refunds = await aeternityContract .getPastEvents ( "refund" , r => r);
console .log (refunds);
//...
// { eventName: 'REFUND',
// network: 'AE',
// id:
// '0xeae5087c274a7d120f24b0568e23f35fcf57d8211888f745dfd5c0299af7f1c7',
// sender: 'ak_2ifr2XxhrMskWdnXZqJE2mVhhwhXYvQD6nRGYLMR5mTSHW4RZz',
// receiver: 'ak_29GUBTrWTMb3tRUUgbVX1Bgwi2hyVhB8Q1befNsjLnP46Ub1V8',
// hashLock:
// '0x573d07a76d833e5ce4a69008496c23f3167be3ea224cd5dab821e36fc54d6205',
// transactionHash: 'th_1DRrRDMUacMZCLUaHQFGgj7HLzfTVy1vLKWascPAHNU8DzbAP' },
//...
const currentBlock = await aeternityContract .getCurrentBlock ();
console .log (currentBlock);
//208446
const balance = await aeternityContract .getBalance (
"ak_SMwGaaRfryc8s7wPhpa1jzxAAtJfkWz2rZG5zrBny968Eqiqr"
);
console .log (balance);
//999073430000000000
const ids = [
"0x3bdf9efc4b3324a0d7453a2572a85bbbfc091f3f2731b956ea13631169f860cb" ,
"0a384aa9b6f7f9ca6c0cc748839ae2b1ec0a1b20f84d2381ad78b04e55d4d87d"
];
const fixedIds = ids .map (i => fixHash (i , false ));
const statuses = await aeternityContract .getStatus (fixedIds);
console .log ( "STATUSES" , statuses);
//STATUSES [ 'REFUNDED', 'EXPIRED' ]
// REFUNDED: 1,
// EXPIRED: 1
// ================ SWAP ================
const userInputSwap = {
inputAmount : "1" ,
outputAddress : "0xdd74dd2697206a910c42f9f5ef8c760a306483b8" ,
outputAmount : "1" ,
outputNetwork : "ETH" ,
secret :
"pond cram isolate kite float moon tongue firm spirit hand peace together" ,
sender : "ak_SMwGaaRfryc8s7wPhpa1jzxAAtJfkWz2rZG5zrBny968Eqiqr"
};
const swap = adapter .formatInput (userInputSwap);
console .log (swap);
// { inputAmount: '1000000000000000000',
// outputAddress: '0xdd74dd2697206a910c42f9f5ef8c760a306483b8',
// outputAmount: '1',
// outputNetwork: 'ETH',
// secret: 'pond cram isolate kite float moon tongue firm spirit hand peace together',
// sender: 'ak_SMwGaaRfryc8s7wPhpa1jzxAAtJfkWz2rZG5zrBny968Eqiqr',
// expiration: 1581337000814,
// hashLock: '0x2a0bb3c4377b6a1c854d24f06c93022fd8798397e315db1f51b6da2d40350907',
// receiver: 'ak_2ifr2XxhrMskWdnXZqJE2mVhhwhXYvQD6nRGYLMR5mTSHW4RZz',
// network: 'AE',
// options: { amount: '1000000000000000000' } }
//broadcast swap transaction
try {
await aeternityContract .newContract (swap);
} catch (e) {
console .log ( "Failed to get tx hash from AE explorer." );
}
// ================ REFUND ================
const refund = {
id : "b55da87ed3922def59ab1f3a55999082cb2abbe8ba42ccc492c9436644994f93"
};
try {
const refundHash = await aeternityContract .refund (refund);
console .log (refundHash);
} catch (e) {
console .log ( "Refund Error. Check timestamp and id params." );
}
// ================ WITHDRAW ================
const withdraw = {
id : "6a7206270cbc6efc60e117bcb762747dd7ca700e01d622f27ac35483ea222d2b" ,
secret : "4e9d424bfac1c8c5b7de6da1968ca6ac72d27c33e9552e91c12ad57266f2c9c6"
};
try {
const withdrawHash = await aeternityContract .withdraw (withdraw);
console .log (withdrawHash);
} catch (e) {
console .log ( "Withdraw Error. Check timestamp, id and secret params." );
}
}