Socket
Socket
Sign inDemoInstall

@tangocrypto/cardano-wallet-js

Package Overview
Dependencies
89
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

    @tangocrypto/cardano-wallet-js

javascript/typescript client for the official cardano-wallet api


Version published
Weekly downloads
2
Maintainers
1
Install size
43.2 MB
Created
Weekly downloads
 

Readme

Source

cardano-wallet-js (powered by TANGO stake pool)

cardano-wallet-js is a javascript/typescript client for the official cardano-wallet

Introduction

The cardano-wallet exposes a REST api/CLI interface which allows clients to perform common tasks on the cardano-blockchain, such as:

  • creating or restoring a wallet
  • submitting a transaction with or without metadata
  • checking on the status of the node
  • listing transactions
  • listing wallets

Our project aims to provide an easy to use API for programmers, instead of exposing the raw REST structure to you.

Finally, it helps you to build desktop wallet clients - like Daedalus - with embedded cardano-wallet binaries, so you don't necessarily have to connect to a remote cardano-wallet server.

Warning

The cardano-wallet backend was not designed to be exposed as a public web service. The use case for it is close to 1 server <-> 1 client (or a few clients). Don't try creating and managing wallets if it's not running locally.

Requirements

Before start using the library you will need a cardano-wallet server running. If you have docker available you can just download the docker-composer.yml they provide and start it using docker-compose:

wget https://raw.githubusercontent.com/input-output-hk/cardano-wallet/master/docker-compose.yml
NETWORK=testnet docker-compose up

NOTE: You can find more information about different options to start the cardano-wallet server here

Installation

Using npm:

npm i cardano-wallet-js

Usage

To begin, start with a WalletServer. It allows you to connect to some remote cardano-wallet service.

Connecting to a cardano-wallet service

const { WalletServer } = require('cardano-wallet-js');
let walletServer = WalletServer.init('http://you.server.com');

Blockchain Information

First you can try is getting some blockchain information like: (network parameters, information and clock)

Get network information

let information = await walletServer.getNetworkInformation();
console.log(information);

This will print out something like this:

{
    "network_tip": {
        "time": "2021-04-12T21:59:25Z",
        "epoch_number": 125,
        "absolute_slot_number": 23895549,
        "slot_number": 265149
    },
    "node_era": "mary",
    "node_tip": {
        "height": {
            "quantity": 0,
            "unit": "block"
        },
        "time": "2019-07-24T20:20:16Z",
        "epoch_number": 0,
        "absolute_slot_number": 0,
        "slot_number": 0
    },
    "sync_progress": {
        "status": "syncing",
        "progress": {
            "quantity": 0,
            "unit": "percent"
        }
    },
    "next_epoch": {
        "epoch_start_time": "2021-04-14T20:20:16Z",
        "epoch_number": 126
    }
}

Get network parameters

let parameters = await walletServer.getNetworkParameters();
console.log(parameters);

This will print out something like this:

{
    "slot_length": {
        "quantity": 1,
        "unit": "second"
    },
    "decentralization_level": {
        "quantity": 100,
        "unit": "percent"
    },
    "genesis_block_hash": "96fceff972c2c06bd3bb5243c39215333be6d56aaf4823073dca31afe5038471",
    "blockchain_start_time": "2019-07-24T20:20:16Z",
    "desired_pool_number": 500,
    "epoch_length": {
        "quantity": 432000,
        "unit": "slot"
    },
    "eras": {
        "shelley": {
            "epoch_start_time": "2020-07-28T20:20:16Z",
            "epoch_number": 74
        },
        "mary": {
            "epoch_start_time": "2021-02-03T20:20:16Z",
            "epoch_number": 112
        },
        "byron": {
            "epoch_start_time": "2019-07-24T20:20:16Z",
            "epoch_number": 0
        },
        "allegra": {
            "epoch_start_time": "2020-12-15T20:20:16Z",
            "epoch_number": 102
        }
    },
    "active_slot_coefficient": {
        "quantity": 5,
        "unit": "percent"
    },
    "security_parameter": {
        "quantity": 2160,
        "unit": "block"
    },
    "minimum_utxo_value": {
        "quantity": 1000000,
        "unit": "lovelace"
    }
}

Get network clock

let clock = await walletServer.getNetworkClock();
console.log(clock);

This will print out something like this:

{
    "status": "available",
    "offset": {
        "quantity": 405623,
        "unit": "microsecond"
    }
}

Useful operations

Generate Recovery Phrases

const { Seed } = require('cardano-wallet-js');

// generate a recovery phrase of 15 words (default)
let recoveryPhrase = Seed.generateRecoveryPhrase();
console.log(recoveryPhrase);

Output:
>> "hip dust material keen buddy fresh thank program stool ill regret honey multiply venture imitate"

IMPORTANT: The recovery phrase is the only way you can restore you wallet and you SHOULD KEEP IT SECURE AND PRIVATE. You'll get a complete different recovery phrase each time you execute the method.

For convinience you can convert the recovery phrase into an array using this:

let words = Seed.toMnemonicList(recoveryPhrase);
console.log(words);

Output:
>> ['hip', 'dust', 'material', 'keen', 'buddy', 'fresh', 'thank', 'program', 'stool', 'ill', 'regret', 'honey', 'multiply', 'venture', 'imitate']

Wallet

Create/restore a wallet:

const { Seed, WalletServer } = require('cardano-wallet-js');

let walletServer = WalletServer.init('http://you.server.com');
let recoveryPhrase = Seed.generateRecoveryPhrase();
let mnemonic_sentence = Seed.toMnemonicList(recoveryPhrase);
let passphrase = 'tangocrypto';
let name = 'tangocrypto-wallet';

let wallet = await walletServer.createOrRestoreShelleyWallet(name, mnemonic_sentence, passphrase);

List wallets:

let wallets = await walletServer.wallets();

Get wallet by Id:

let wallets = await walletServer.wallets();
let id = wallets[0].id;
let wallet = await walletServer.getShelleyWallet(id);

Get wallet's utxo statistics:

let statistics = await wallet.getUtxoStatistics();

Statistics will contain the UTxOs distribution across the whole wallet, in the form of a histogram similar to the one below.

100 ─
     │
     │                                 ┌───┐
  10 ─                         ┌───┐   │   │                   ┌───┐
     │                 ┌───┐   │   │   │   │                   │   │
     │                 │   │   │   │   │   │   ┌───┐           │   │
   1 ─ ┌───┐           │   │   │   │   │   │   │   │           │   │
     │ │   │           │   │   │   │   │   │   │   │           │   │
     │ │   │ │       │ │   │ │ │   │ ╷ │   │ ╷ │   │ ╷       ╷ │   │
     └─┘   └─│───────│─┘   └─│─┘   └─│─┘   └─│─┘   └─│───────│─┘   └────
           10μ₳    100μ₳   1000μ₳   0.1110100

Remove wallet:

await wallet.delete();

Rename wallet:

let newName = 'new-name';
wallet = await wallet.rename(newName);

Change wallet passphrase:

let oldPassphrase = 'tangocrypto';
let newPassphrase = 'new-passphrase';
wallet = await wallet.updatePassphrase(oldPassphrase, newPassphrase);

NOTE: the wallet itself doesn't hold the passphrase, you can check it's correctly updated trying to call a method needing the passphrase e.g: sendPayment

Wallet addresses

Cardano wallets are Multi-Account Hierarchy Deterministic that follow a variation of BIP-44 described here. All the addresses are derived from a root key (is like a key factory) which you can get from the recovery phrase. Also the wallets will always have 20 "consecutive" unused address, so anytime you use one of them new address will be "discovered" to keep the rule.

let addresses = await wallet.getAddresses(); // list will contain at least 20 address

Get unused addresses:

let unusedAddresses = await wallet.getUnusedAddresses();

Get used addresses:

let usedAddresses = await wallet.getUsedAddresses();

You can create/discover next unused address:

// you'll get the n-th address where n is the current addresses list length 
let address = await wallet.getNextAddress();    

// you can also pass the specific index
 let address = await wallet.getAddressAt(45);  

Wallet balances

// get available balance. The balance you can expend
let totalBalance = wallet.getAvailableBalance();

// get rewards balance. The balance available to withdraw
let rewardBalance = wallet.getRewardBalance();

// get total balance. Total balance is the sum of available balance plus reward balance
let totalBalance = wallet.getTotalBalance();

Wallet delegation

The wallet have information about whether already delegate on a stake pool or not

let delegation = wallet.getDelegation();
console.log(delegation);

It the wallet is not delegate to any stake pool the output should be something similar to this:

{
    "next": [],
    "active": {
        "status": "not_delegating"
    }
}

If you start delegating (see Stake pool section) the action will not take effect inmediatelly but the next property will indicate when the delegation will finally take effect. The delegation meanwhile should look like this:

{
 "next": [
  {
   "status": "delegating",
   "changes_at": {
    "epoch_start_time": "2021-04-15T15:03:27Z",
    "epoch_number": 10
   },
   "target": "pool1as50x0wtumtyqzs7tceeh5ry0syh8jnvpnuu9wlxswxuv48sw4w"
  }
 ],
 "active": {
  "status": "not_delegating"
 }
}

NOTE: Property changes_at will indicate the epoch at the delegation will take effect

If we ask again after/during the epoch 10, we should get the delgation in place:

// refresh the wallet if you are using the same object. This will fecth the info from the blockchain
await wallet.refresh();

let delegation = wallet.getDelegation();
console.log(delegation);

Output:

{
  next: [],
  active: {
    status: 'delegating',
    target: 'pool1as50x0wtumtyqzs7tceeh5ry0syh8jnvpnuu9wlxswxuv48sw4w'
  }
}

Stake Pool

Get stake pool ranking list by member rewards:

let stake = 1000000000;
let pools = await walletServer.getStakePools(stake);

NOTE: You'll get pool ordered by non_myopic_member_rewards which basically means from heighest to lower expected rewards. By default the wallet server isn't configured to fecth the pool's metadata (e.g. ticker, name, homepage) but you can specify it through the update settings functionality, see Update Settings section below.

Estimate delegation fee:

let fee = await wallet.estimateDelegationFee();

NOTE: The very first time you delegate to a pool you'll be charged an extra 2 ADA. This extra fee won't be included on the response.

Delegate to stake pool:

let passphrase = 'tangocrypto';
// choose the first pool from the previous ranking list, but you can select whatever you want.
let pool = pools[0]; 
let transaction = await wallet.delegate(pool.id, passphrase);

NOTE: The transacion status initially is set to pending, so you should keep tracking the transaction using the id in order to make sure the final status (e.g. in_ledger). You can learn more about the transacion's life cycle here. For delegate to another stake pool use the same method above specifying a different stake pool.

Withdraw stake pool's rewards:

let passphrase = 'tangocrypto';

// select the address to receive the rewards
let address = (await wallet.getUsedAddresses())[0];

// get the reward balance available to withdraw
let rewardBalance = wallet.getRewardBalance();

let transaction = await wallet.withdraw(passphrase, [address], [rewardBalance]);

NOTE: You can send the rewards to multiple addresses splitting up the rewardBalance for each one. Also you can send it to any valid address whether it's in your wallet or not.

Stop delegating:

let transaction = await wallet.stopDelegation(passphrase);

Stake pool maintenance actions:

let maintenanceActions = await walletServer.stakePoolMaintenanceActions();

Possible values are:

 - not_applicable -> we're currently not querying a SMASH server for metadata
 - not_started -> the Garbage Collection hasn't started yet, try again in a short while
 - restarting -> the Garbage Collection thread is currently restarting, try again in short while
 - has_run -> the Garbage Collection has run successfully

NOTE: Maintenance actions will depend on whether or not the wallet server is using a Stakepool Metadata Aggregation Server (SMASH).

Manually trigger Garbage Collection:

await walletServer.triggerStakePoolGarbageCollection();

Wallet transactions

Get wallet transactions:

// get all wallet transactions
let transactions = await wallet.getTransactions(start, end);

// filter by start and end date
let start = new Date(2021, 0, 1); // January 1st 2021;
let end = new Date(Date.now());
let transactions = await wallet.getTransactions(start, end);

Get transaction details:

let transaction = await wallet.getTransaction(tx.id);

Get payment fees:

// receiver address
let address = 'addr1q99q78gt2898zgu2dcswf2yuxj6vujcqece38rycc7wsncl5lx8y....';
let amount = 5000000; // 5 ADA
let estimatedFees = await wallet.estimateFee([address], [amount]);

Send payment transfer:

let passphrase = 'tangocrypto';

// receiver address
let addresses = ['addr1q99q78gt2898zgu2dcswf2yuxj6vujcqece38rycc7wsncl5lx8y....'];
let amounts = [5000000]; // 5 ADA

let transaction = await wallet.sendPayment(passphrase, addresses, amounts);

NOTE: You can pass a list of address and amount. We expect both list have the same length where elemetns on each list is index related to the other. You can think of it as sending amounts[i] to addresses[i].

Send payment transfer with metadata:

Metadata can be expressed as a JSON object with some restrictions:

  • All top-level keys must be integers between 0 and 2^64 - 1.
  • Each metadata value is tagged with its type.
  • Strings must be at most 64 bytes when UTF-8 encoded.
  • Bytestrings are hex-encoded, with a maximum length of 64 bytes.

For more information check here.

let passphrase = 'tangocrypto';

// receiver address
let addresses = ['addr1q99q78gt2898zgu2dcswf2yuxj6vujcqece38rycc7wsncl5lx8y....'];
let amounts = [5000000]; // 5 ADA

let metadata = ['abc', '2512a00e9653fe49a44a5886202e24d77eeb998f', 123];
let transaction = await wallet.sendPayment(passphrase, addresses, amounts, metadata);

WARNING: Please note that metadata provided in a transaction will be stored on the blockchain forever. Make sure not to include any sensitive data, in particular personally identifiable information (PII).

Send a more complex metadata object:

let passphrase = 'tangocrypto';

// receiver address
let addresses = ['addr1q99q78gt2898zgu2dcswf2yuxj6vujcqece38rycc7wsncl5lx8y....'];
let amounts = [5000000]; // 5 ADA

let metadata: any = {0: 'hello', 1: Buffer.from('2512a00e9653fe49a44a5886202e24d77eeb998f', 'hex'), 4: [1, 2, {0: true}], 5: {'key': null, 'l': [3, true, {}]}, 6: undefined};
let transaction = await wallet.sendPayment(passphrase, addresses, amounts, metadata);

NOTE: Values like boolean, null and undefined are passed as string (e.g "true", "null", "undefined").

Forget transaction: If for some reason your transaction hang on status pending, for a long period, you can consider to "cancel" it.

wallet.forgetTransaction(transaction.id)

Importantly: A transaction, when sent, cannot be cancelled. One can only request forgetting about it in order to try spending (concurrently) the same UTxO in another transaction. But, the transaction may still show up later in a block and therefore, appear in the wallet.

Test

Stack

you'll need to install stak >= 1.9.3 you can find it here: https://docs.haskellstack.org/en/stable/README/ You may need to install the libsodium-dev, libghc-hsopenssl-dev, gmp, sqlite and systemd development libraries for the build to succeed.

The setup steps are quite simple: clone: cardano-wallet execute: stack install cardano-wallet:exe:local-cluster Set a specific port export CARDANO_WALLET_PORT=7355 so the wallet always start at the same port. run ~/.local/bin/local-cluster

Support our project

  • Delegate with us:
    Ticker: TANGO
    Pool Id: bd5f6b254798e3ddde1a9c3609fa9d6e468d638bd9103afb02e29ae5
    You can find us on Adapools.org
  • Donate ADA to:
    addr1qxw567xyzgqchtyddeha90ugsr8uyu7h4uh8wg5su8qz7yykq2ndwcmedv72l7263vj96tl6cyn74l2mw5kp8h7fk8rqevat3x

Keywords

FAQs

Last updated on 24 Apr 2021

Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc