Last active
May 17, 2024 03:35
-
-
Save gre/aff677bd46324c7071544aa5011c51e4 to your computer and use it in GitHub Desktop.
live-common in a nutshell
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"private": true, | |
"name": "send-example", | |
"version": "1.0.0", | |
"main": "index.js", | |
"license": "MIT", | |
"dependencies": { | |
"@ledgerhq/hw-transport-node-hid-noevents": "canary", | |
"@ledgerhq/ledger-core": "alpha", | |
"@ledgerhq/live-common": "alpha", | |
"axios": "^0.19.0", | |
"rxjs": "^6.5.3" | |
}, | |
"scripts": { | |
"start": "node index.js" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const { first, map, reduce } = require("rxjs/operators"); | |
const { getCryptoCurrencyById, formatCurrencyUnit, parseCurrencyUnit } = require("@ledgerhq/live-common/lib/currencies"); | |
const { getCurrencyBridge, getAccountBridge } = require("@ledgerhq/live-common/lib/bridge"); | |
// our small example is a script that takes 3 params. | |
// example: node send.js bitcoin bc1abc..def 0.001 | |
if (!process.argv[4]) { | |
console.log(`Usage: currencyId recipient amount`); | |
process.exit(1); | |
} | |
const currencyId = process.argv[2]; | |
const currency = getCryptoCurrencyById(currencyId); | |
const recipient = process.argv[3]; | |
const amount = parseCurrencyUnit(currency.units[0], process.argv[4]); | |
const deviceId = ""; // in HID case | |
////////////////////////////////// | |
// live-common requires some setup. usually we put that in a live-common-setup.js | |
const { registerTransportModule } = require("@ledgerhq/live-common/lib/hw"); | |
const TransportNodeHid = require("@ledgerhq/hw-transport-node-hid-noevents").default; | |
const implementLibcore = require("@ledgerhq/live-common/lib/libcore/platforms/nodejs").default; | |
const { setNetwork } = require("@ledgerhq/live-common/lib/network"); | |
const { setSupportedCurrencies } = require("@ledgerhq/live-common/lib/data/cryptocurrencies"); | |
// configure which coins to enable | |
setSupportedCurrencies([currencyId]); | |
// provide a network function | |
setNetwork(require("axios")); | |
// provide a libcore implementation | |
implementLibcore({ | |
lib: () => require("@ledgerhq/ledger-core"), | |
dbPath: "./dbdata" | |
}); | |
// configure which transport are available | |
registerTransportModule({ | |
id: "hid", | |
open: devicePath => TransportNodeHid.open(devicePath), | |
disconnect: () => Promise.resolve() | |
}); | |
///////////////////////// | |
async function main() { | |
// currency bridge is the interface to scan accounts of the device | |
const currencyBridge = getCurrencyBridge(currency); | |
// some currency requires some data to be loaded (today it's not highly used but will be more and more) | |
await currencyBridge.preload(); | |
// NB scanAccountsOnDevice returns an observable but we'll just get the first account as a promise. | |
const scannedAccount = await currencyBridge | |
.scanAccountsOnDevice(currency, deviceId) | |
.pipe( | |
// there can be many accounts, for sake of example we take first non empty | |
first(e => e.type === "discovered" && e.account.balance.gt(0)), | |
map(e => e.account) | |
) | |
.toPromise(); | |
// account bridge is the interface to sync and do transaction on our account | |
const accountBridge = getAccountBridge(scannedAccount); | |
// Minimal way to synchronize an account. | |
// NB: our scannedAccount is already sync in fact, this is just for the example | |
const account = await accountBridge | |
.startSync(scannedAccount, false) | |
.pipe(reduce((a, f) => f(a), scannedAccount)) | |
.toPromise(); | |
console.log(`${account.name} new address: ${account.freshAddress}`); | |
console.log(`with balance of ${formatCurrencyUnit(account.unit, account.balance)}`); | |
// We prepare a transaction | |
let t = accountBridge.createTransaction(account); | |
t = accountBridge.updateTransaction(t, { amount, recipient }); | |
t = await accountBridge.prepareTransaction(account, t); | |
// We can always get the status. used for form validation and meta info (like calculated fees) | |
const status = await accountBridge.getTransactionStatus(account, t); | |
console.log({ status }); | |
// we can't broadcast the transaction if there are errors | |
const errors = Object.values(status.errors); | |
if (errors.length) { | |
throw errors[0]; | |
} | |
// We're good now, we can sign the transaction and broadcast it | |
const operation = await accountBridge | |
.signAndBroadcast(account, t, deviceId) | |
.pipe( | |
// there are many events. we just take the final broadcasted | |
first(e => e.type === "broadcasted"), | |
map(e => e.operation) | |
) | |
.toPromise(); | |
// the transaction is broadcasted! | |
// the resulting operation is an "optimistic" response that can be prepended to our account.operations[] | |
console.log("broadcasted", operation); | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment