Send Signa
1 min
One of the most crucial operations is the transfer of Signa from one account to another. So, without much blabla, we hop directly into the code.
const {Address, AddressPrefix, LedgerClientFactory} = require("@signumjs/core");
const {Amount, CurrencySymbol} = require("@signumjs/util");
const {generateMasterKeys} = require("@signumjs/crypto");
const LedgerHostUrls = {
TestNet: 'http://localhost:6876',
MainNet: 'https://europe.signum.network',
}
async function sendSigna(args) {
try {
const {ledgerType, recipient, amount, feeType, passphrase} = args
// we create our client depending on the parameter
const ledger = LedgerClientFactory.create({
nodeHost: LedgerHostUrls[ledgerType])
}
// we check if incoming account is either a Signum Address, or Numeric Id
// eventually, we convert to Numeric Id, if the value is invalid an error will be thrown
const recipientId = Address.create(recipient).getNumericId()
// now we check if the account exists. If it does not exist the method throws an
// exception and the further flow is interrupted.
// Using exception to assert certain conditions is IMHO more robust than checking returned
// values with if-statements. The code is much cleaner
console.info("Verifying recipient...")
await ledger.account.getAccount({accountId: recipientId})
// before we can send we need to get the private signing key from the user
const {publicKey, signPrivateKey} = generateMasterKeys(passphrase)
// as a next step, we use the systems fee suggestion mechanism to give us the current costs for the chosen
// fee type. In this example we let it flexible, but you can fix the fee costs to a minimum, i.e. 0,00735 SIGNA
const suggestedFees = await ledger.network.getSuggestedFees()
// we assume that the feeType is either ['Minimum', 'Cheap', 'Standard', 'Priority']
const selectedFeePlanck = suggestedFees[feeType.toLowerCase()]
// Now, we execute the transaction
// within the method the local signing flow is being executed, i.e.
// the private key is used only locally for signinh, but never sent over the network
const {transaction} = await ledger.transaction.sendAmountToSingleRecipient({
recipientId,
amountPlanck: Amount.fromSigna(amount).getPlanck(),
feePlanck: selectedFeePlanck,
senderPrivateKey: signPrivateKey,
senderPublicKey: publicKey
});
// now, some final nice message
const addressPrefix = ledgerType === 'MainNet' ? AddressPrefix.MainNet : AddressPrefix.TestNet
console.info(`Successfully sent ${amount} ${CurrencySymbol} to ${Address.create(recipientId, addressPrefix).getReedSolomonAddress()} - Transaction Id: ${transaction}`)
console.info(`You paid a total of ${Amount.fromSigna(amount).add(Amount.fromPlanck(selectedFeePlanck)).toString()}`)
} catch (e) {
// If the API returns an exception,
// the return error object is of type HttpError
handleError(e);
}
}
// // Our entry point has to be async, as our subsequent calls are.
// // This pattern keeps your app running until all async calls are executed
(async () => {
await sendSigna({
ledgerType: 'TestNet',
recipient: 'TS-QAJA-QW5Y-SWVP-4RVP4',
amount: 100.00,
feeType: 'cheap',
passphrase: 'YourVerySecretPassphraseWhichCannotBeRevealedHere'
});
})();
So, the crucial part is the signing of the transaction. It is required to get the signPrivateKey from the key set, that's being derived from the seed.
The private keys must never be passed to other persons, or even hard coded into code. You need to establish mechanism to secure either the private keys, or the seed that generates the keys. Without the seed/private key it is not possible to sign a transaction, i.e. all balance of that account is not accessible.