Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

algosdk

Package Overview
Dependencies
Maintainers
1
Versions
70
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

algosdk - npm Package Compare versions

Comparing version 1.2.2 to 1.3.0

addr.html

8

CHANGELOG.md

@@ -0,1 +1,9 @@

# 1.3.0
## Added
- Support for key registration transactions
- Support for flat fees
- Signing and verifying bytes
## Fixed
- deleteMultisig uses post instead of get
- "MultiSig" standardized to "Multisig"
# 1.2.2

@@ -2,0 +10,0 @@ ## Added

2

package.json
{
"name": "algosdk",
"version": "1.2.2",
"version": "1.3.0",
"description": "algosdk is Algorand's official javascript SDK",

@@ -5,0 +5,0 @@ "main": "index.js",

@@ -45,3 +45,3 @@ const client = require('./client');

/**
* helathCheck returns an empty object iff the node is running
* healthCheck returns an empty object iff the node is running
* @returns {Promise<*>}

@@ -106,5 +106,6 @@ */

* @param last number, optional
* @param maxTxns number, optional
* @returns {Promise<*>}
*/
this.transactionByAddress = async function (addr, first=null, last=null) {
this.transactionByAddress = async function (addr, first=null, last=null, maxTxns=null) {

@@ -117,3 +118,3 @@ if (( first !== null ) && (!Number.isInteger(first) )){

}
let res = await c.get("/v1/account/" + addr + "/transactions", { 'firstRound': first, 'lastRound': last });
let res = await c.get("/v1/account/" + addr + "/transactions", { 'firstRound': first, 'lastRound': last, 'max': maxTxns });
if (res.statusCode === 200 && res.body.transactions !== undefined) {

@@ -128,2 +129,21 @@ for (let i = 0; i < res.body.transactions.length; i++) {

/**
* transactionsByAddressAndDate returns all transactions for a PK [addr] in the [fromDate, toDate] date range.
* The date is a string in the YYYY-MM-DD format.
* @param addr string
* @param fromDate string
* @param toDate string
* @param maxTxns number, optional
* @returns {Promise<*>}
*/
this.transactionByAddressAndDate = async function (addr, fromDate, toDate, maxTxns=null) {
let res = await c.get("/v1/account/" + addr + "/transactions", { 'fromDate': fromDate, 'toDate': toDate, 'max': maxTxns });
if (res.statusCode === 200 && res.body.transactions !== undefined) {
for (let i = 0; i < res.body.transactions.length; i++) {
res.body.transactions[i] = noteb64ToNote(res.body.transactions[i]);
}
}
return res.body;
};
/**
* transactionById returns the a transaction information of a specific txid [txId]

@@ -140,3 +160,3 @@ * Note - This method is allowed only when Indexer is enabled.

/**
* transactionInformation returns the a transaction information of a specific txid and an address
* transactionInformation returns the transaction information of a specific txid and an address
* @param addr

@@ -155,2 +175,15 @@ * @param txid

/**
* pendingTransactionInformation returns the transaction information for a specific txid of a pending transaction
* @param txid
* @returns {Promise<*>}
*/
this.pendingTransactionInformation = async function (txid) {
let res = await c.get("/v1/transactions/pending/" + txid);
if (res.statusCode === 200) {
res.body = noteb64ToNote(res.body);
}
return res.body;
};
/**
* accountInformation returns the passed account's information

@@ -157,0 +190,0 @@ * @param addr string

@@ -354,3 +354,20 @@ const client = require('./client');

/**
* deleteMultisig accepts a wallet handle, wallet password, and multisig
* address, and deletes the information about this multisig address from the
* wallet (including address and secret key).
* @param walletHandle
* @param walletPassword
* @param addr
* @returns {Promise<*>}
*/
this.deleteMultisig = async function (walletHandle, walletPassword, addr) {
let req = {
"wallet_handle_token": walletHandle,
"address": addr,
"wallet_password": walletPassword
};
let res = await c.delete("/v1/multisig", req);
return res.body;
};
}

@@ -357,0 +374,0 @@ module.exports = {Kmd};

@@ -10,2 +10,3 @@ const nacl = require('./nacl/naclWrappers');

const kmd = require('./client/kmd');
const utils = require('./utils/utils');

@@ -15,8 +16,9 @@ let Algod = algod.Algod;

const SIGN_BYTES_PREFIX = Buffer.from([77, 88]); // "MX"
const MICROALGOS_TO_ALGOS_RATIO = 1e6;
// Errors
const ERROR_MULTISIG_BAD_SENDER = new Error("The transaction sender address and multisig preimage do not match.");
const ERROR_INVALID_MICROALGOS = new Error("Microalgos should be positive and less than 2^53 - 1.")
/**
* GenerateAddress returns a new Algorand address and its corresponding secret key
* generateAccount returns a new Algorand address and its corresponding secret key
* @returns {{sk: Uint8Array, addr: string}}

@@ -33,3 +35,3 @@ */

* @param addr Algorand address
* @returns {boolean}n true if valid, false otherwise
* @returns {boolean} true if valid, false otherwise
*/

@@ -84,7 +86,13 @@ function isValidAddress(addr) {

/**
* signTransaction takes an object with the following fields: to, amount, fee per byte, firstRound, lastRound,
* and note(optional),GenesisID(optional) and a secret key and returns a signed blob
* @param txn object with the following fields - to, amount, fee per byte, firstRound, lastRound, and note(optional)
* signTransaction takes an object with either payment or key registration fields and
* a secret key and returns a signed blob.
*
* Payment transaction fields: to, amount, fee, firstRound, lastRound, genesisHash,
* note(optional), GenesisID(optional), closeRemainderTo(optional)
*
* Key registration fields: fee, firstRound, lastRound, voteKey, selectionKey, voteFirst,
* voteLast, voteKeyDilution, genesisHash, note(optional), GenesisID(optional)
* @param txn object with either payment or key registration fields
* @param sk Algorand Secret Key
* @returns object contains the binary signed transaction and it's txID
* @returns object contains the binary signed transaction and its txID
*/

@@ -113,6 +121,33 @@ function signTransaction(txn, sk) {

/**
* signBytes takes arbitrary bytes and a secret key, prepends the bytes with "MX" for domain separation, signs the bytes
* with the private key, and returns the signature.
* @param bytes Uint8array
* @param sk Algorand secret key
* @returns binary signature
*/
function signBytes(bytes, sk) {
let toBeSigned = Buffer.from(utils.concatArrays(SIGN_BYTES_PREFIX, bytes));
let sig = nacl.sign(toBeSigned, sk);
return sig;
}
/**
* verifyBytes takes arbitraray bytes, an address, and a signature and verifies if the signature is correct for the public
* key and the bytes (the bytes should have been signed with "MX" prepended for domain separation).
* @param bytes Uint8Array
* @param signature binary signature
* @param addr string address
* @returns bool
*/
function verifyBytes(bytes, signature, addr) {
toBeVerified = Buffer.from(utils.concatArrays(SIGN_BYTES_PREFIX, bytes));
let pk = address.decode(addr).publicKey;
return nacl.verify(toBeVerified, signature, pk);
}
/**
* signMultisigTransaction takes a raw transaction (see signTransaction), a multisig preimage, a secret key, and returns
* a multisig transaction, which is a blob representing a transaction and multisignature account preimage. The returned
* multisig txn can accumulate additional signatures through mergeMultisigTransactions or appendMultisigTransaction.
* @param txn object with the following fields - to, amount, fee per byte, firstRound, lastRound, and note(optional)
* @param txn object with either payment or key registration fields
* @param version multisig version

@@ -150,3 +185,3 @@ * @param threshold multisig threshold

* @param version multisig version
* @param threshold mutlisig threshold
* @param threshold multisig threshold
* @param addrs a list of Algorand addresses representing possible signers for this multisig. Order is important.

@@ -208,2 +243,25 @@ * @param sk Algorand secret key

/**
* microalgosToAlgos converts microalgos to algos
* @param microalgos number
* @returns number
*/
function microalgosToAlgos(microalgos) {
if (microalgos < 0 || !Number.isSafeInteger(microalgos)){
throw ERROR_INVALID_MICROALGOS;
}
return microalgos/MICROALGOS_TO_ALGOS_RATIO
}
/**
* algosToMicroalgos converts algos to microalgos
* @param algos number
* @returns number
*/
function algosToMicroalgos(algos) {
let microalgos = algos*MICROALGOS_TO_ALGOS_RATIO;
return Math.round(microalgos)
}
module.exports = {

@@ -216,2 +274,4 @@ isValidAddress,

signBid,
signBytes,
verifyBytes,
encodeObj,

@@ -228,2 +288,5 @@ decodeObj,

ERROR_MULTISIG_BAD_SENDER,
ERROR_INVALID_MICROALGOS,
microalgosToAlgos,
algosToMicroalgos,
};

@@ -33,4 +33,8 @@ const nacl = require('tweetnacl');

module.exports = {genericHash, randomBytes, keyPair, sign, keyPairFromSeed, keyPairFromSecretKey, bytesEqual};
function verify(message, signature, verifyKey) {
return nacl.sign.detached.verify(message, signature, verifyKey);
}
module.exports = {genericHash, randomBytes, keyPair, sign, keyPairFromSeed, keyPairFromSecretKey, bytesEqual, verify};
// constants

@@ -37,0 +41,0 @@ module.exports.PUBLIC_KEY_LENGTH = nacl.sign.publicKeyLength;

@@ -14,3 +14,3 @@ const address = require("./encoding/address");

class Transaction {
constructor({from, to, fee, amount, firstRound, lastRound, note, genesisID, genesisHash, closeRemainderTo}) {
constructor({from, to, fee, amount, firstRound, lastRound, note, genesisID, genesisHash, closeRemainderTo, voteKey, selectionKey, voteFirst, voteLast, voteKeyDilution, type="pay", flatFee=false}) {
this.name = "Transaction";

@@ -20,3 +20,3 @@ this.tag = Buffer.from([84, 88]); // "TX"

from = address.decode(from);
to = address.decode(to);
if (to !== undefined) to = address.decode(to);

@@ -29,3 +29,3 @@ if (closeRemainderTo !== undefined) closeRemainderTo = address.decode(closeRemainderTo);

if (!Number.isSafeInteger(amount) || amount < 0) throw Error("Amount must be a positive number and smaller than 2^53-1");
if (amount !== undefined && (!Number.isSafeInteger(amount) || amount < 0)) throw Error("Amount must be a positive number and smaller than 2^53-1");
if (!Number.isSafeInteger(fee) || fee < 0) throw Error("fee must be a positive number and smaller than 2^53-1");

@@ -41,10 +41,17 @@ if (!Number.isSafeInteger(firstRound) || firstRound < 0) throw Error("firstRound must be a positive number");

}
if (voteKey !== undefined) {
voteKey = Buffer.from(voteKey, "base64");
}
if (selectionKey !== undefined) {
selectionKey = Buffer.from(selectionKey, "base64");
}
Object.assign(this, {
from, to, fee, amount, firstRound, lastRound, note, genesisHash, genesisID, closeRemainderTo
from, to, fee, amount, firstRound, lastRound, note, genesisHash, genesisID, closeRemainderTo, voteKey, selectionKey, voteFirst, voteLast, voteKeyDilution, type
});
// Modify Fee
this.fee *= this.estimateSize();
if (!flatFee){
this.fee *= this.estimateSize();
}
// If suggested fee too small and will be rejected, set to min tx fee

@@ -57,25 +64,49 @@ if (this.fee < ALGORAND_MIN_TX_FEE) {

get_obj_for_encoding() {
let txn = {
"amt": this.amount,
"fee": this.fee,
"fv": this.firstRound,
"lv": this.lastRound,
"note": Buffer.from(this.note),
"rcv": Buffer.from(this.to.publicKey),
"snd": Buffer.from(this.from.publicKey),
"type": "pay",
"gen": this.genesisID,
"gh": this.genesisHash,
};
if (this.type == "pay") {
let txn = {
"amt": this.amount,
"fee": this.fee,
"fv": this.firstRound,
"lv": this.lastRound,
"note": Buffer.from(this.note),
"rcv": Buffer.from(this.to.publicKey),
"snd": Buffer.from(this.from.publicKey),
"type": "pay",
"gen": this.genesisID,
"gh": this.genesisHash,
};
// parse close address
if (this.closeRemainderTo !== undefined) txn.close = Buffer.from(this.closeRemainderTo.publicKey);
// allowed zero values
if (!txn.note.length) delete txn.note;
if (!txn.amt) delete txn.amt;
if (!txn.fee) delete txn.fee;
if (!txn.gen) delete txn.gen;
// parse close address
if (this.closeRemainderTo !== undefined) txn.close = Buffer.from(this.closeRemainderTo.publicKey);
// allowed zero values
if (!txn.note.length) delete txn.note;
if (!txn.amt) delete txn.amt;
if (!txn.fee) delete txn.fee;
if (!txn.gen) delete txn.gen;
return txn;
return txn;
}
else if (this.type == "keyreg") {
let txn = {
"fee": this.fee,
"fv": this.firstRound,
"lv": this.lastRound,
"note": Buffer.from(this.note),
"snd": Buffer.from(this.from.publicKey),
"type": this.type,
"gen": this.genesisID,
"gh": this.genesisHash,
"votekey": this.voteKey,
"selkey": this.selectionKey,
"votefst": this.voteFirst,
"votelst": this.voteLast,
"votekd": this.voteKeyDilution
};
// allowed zero values
if (!txn.note.length) delete txn.note;
if (!txn.fee) delete txn.fee;
if (!txn.gen) delete txn.gen;
return txn;
}
}

@@ -88,3 +119,5 @@

txn.amount = txnForEnc.amt;
txn.genesisID = txnForEnc.gen;
txn.genesisHash = txnForEnc.gh;
txn.type = txnForEnc.type;
txn.fee = txnForEnc.fee;

@@ -94,7 +127,17 @@ txn.firstRound = txnForEnc.fv;

txn.note = new Uint8Array(txnForEnc.note);
txn.to = address.decode(address.encode(new Uint8Array(txnForEnc.rcv)));
txn.from = address.decode(address.encode(new Uint8Array(txnForEnc.snd)));
if (txnForEnc.close !== undefined) txn.closeRemainderTo = address.decode(address.encode(new Uint8Array(txnForEnc.close)));
txn.genesisID = txnForEnc.gen;
txn.genesisHash = txnForEnc.gh;
if (txnForEnc.type === "pay") {
txn.amount = txnForEnc.amt;
txn.to = address.decode(address.encode(new Uint8Array(txnForEnc.rcv)));
if (txnForEnc.close !== undefined) txn.closeRemainderTo = address.decode(address.encode(new Uint8Array(txnForEnc.close)));
}
else if (txnForEnc.type === "keyreg") {
txn.voteKey = txnForEnc.votekey;
txn.selectionKey = txnForEnc.selkey;
txn.voteKeyDilution = txnForEnc.votekd;
txn.voteFirst = txnForEnc.votefst;
txn.voteLast = txnForEnc.votelst;
}
return txn;

@@ -101,0 +144,0 @@ }

const algosdk = require("./src/main");
console.log(algosdk.isValidAddress("HH3XQFKYAQK34WIH6X752FJY3ZVL5LSTFKC5ABLWMIA37YLVWFAAWZH6X4"));
const params = {
version: 1,
threshold: 2,
addrs: [
"NP3GVAWXXC7EEVOHSZIHSCDRO3I3ZCXXM5DWAAJLJHNQSJOV2CP5HWUWK4",
"ZCFKADPCOJBKVJIXTKJMDYQGLULNEYEXPNXIZFW75XMHTQFETVAGICKB2Q",
"ZIQKQM4ICEC7Z2CZEPKT4NZKHW7OCM3KNW3Q6J7D2IUXD2SWZ2X4GHHVHU",
],
};
let outAddr = algosdk.multisigAddress(params);
console.log(outAddr)

@@ -111,2 +111,49 @@ let assert = require('assert');

it('should correctly serialize and deserialize from msgpack representation with flat fee', function() {
let o = {
"from": "XMHLMNAVJIMAW2RHJXLXKKK4G3J3U6VONNO3BTAQYVDC3MHTGDP3J5OCRU",
"to": "UCE2U2JC4O4ZR6W763GUQCG57HQCDZEUJY4J5I6VYY4HQZUJDF7AKZO5GM",
"fee": 2063,
"amount": 847,
"firstRound": 51,
"lastRound": 61,
"note": new Uint8Array([123, 12, 200]),
"genesisHash": "JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=",
"genesisID": "",
"flatFee": true
};
let expectedTxn = new transaction.Transaction(o);
let encRep = expectedTxn.get_obj_for_encoding();
const encTxn = encoding.encode(encRep);
const decEncRep = encoding.decode(encTxn);
let decTxn = transaction.Transaction.from_obj_for_encoding(decEncRep);
const reencRep = decTxn.get_obj_for_encoding();
assert.deepStrictEqual(reencRep, encRep);
});
it('should correctly serialize and deserialize a key registration transaction from msgpack representation', function() {
let o = {
"from": "XMHLMNAVJIMAW2RHJXLXKKK4G3J3U6VONNO3BTAQYVDC3MHTGDP3J5OCRU",
"fee": 10,
"firstRound": 51,
"lastRound": 61,
"note": new Uint8Array([123, 12, 200]),
"genesisHash": "JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=",
"voteKey": "5/D4TQaBHfnzHI2HixFV9GcdUaGFwgCQhmf0SVhwaKE=",
"selectionKey": "oImqaSLjuZj63/bNSAjd+eAh5JROOJ6j1cY4eGaJGX4=",
"voteFirst": 123,
"voteLast": 456,
"voteKeyDilution": 1234,
"genesisID": "",
"type": "keyreg"
};
let expectedTxn = new transaction.Transaction(o);
let encRep = expectedTxn.get_obj_for_encoding();
const encTxn = encoding.encode(encRep);
const decEncRep = encoding.decode(encTxn);
let decTxn = transaction.Transaction.from_obj_for_encoding(decEncRep);
const reencRep = decTxn.get_obj_for_encoding();
assert.deepStrictEqual(reencRep, encRep);
});
it('reserializes correctly no genesis ID', function() {

@@ -113,0 +160,0 @@ let o = {

@@ -57,4 +57,46 @@ let assert = require('assert');

});
it('should return a blob that matches the go code when using a flat fee', function () {
let sk = "advice pudding treat near rule blouse same whisper inner electric quit surface sunny dismiss leader blood seat clown cost exist hospital century reform able sponsor";
let golden = "gqNzaWfEQPhUAZ3xkDDcc8FvOVo6UinzmKBCqs0woYSfodlmBMfQvGbeUx3Srxy3dyJDzv7rLm26BRv9FnL2/AuT7NYfiAWjdHhui6NhbXTNA+ilY2xvc2XEIEDpNJKIJWTLzpxZpptnVCaJ6aHDoqnqW2Wm6KRCH/xXo2ZlZc0EmKJmds0wsqNnZW6sZGV2bmV0LXYzMy4womdoxCAmCyAJoJOohot5WHIvpeVG7eftF+TYXEx4r7BFJpDt0qJsds00mqRub3RlxAjqABVHQ2y/lqNyY3bEIHts4k/rW6zAsWTinCIsV/X2PcOH1DkEglhBHF/hD3wCo3NuZMQg5/D4TQaBHfnzHI2HixFV9GcdUaGFwgCQhmf0SVhwaKGkdHlwZaNwYXk=";
let o = {
"to": "PNWOET7LLOWMBMLE4KOCELCX6X3D3Q4H2Q4QJASYIEOF7YIPPQBG3YQ5YI",
"fee": 1176,
"amount": 1000,
"firstRound": 12466,
"lastRound": 13466,
"genesisID": "devnet-v33.0",
"genesisHash": "JgsgCaCTqIaLeVhyL6XlRu3n7Rfk2FxMeK+wRSaQ7dI=",
"closeRemainderTo": "IDUTJEUIEVSMXTU4LGTJWZ2UE2E6TIODUKU6UW3FU3UKIQQ77RLUBBBFLA",
"note": new Uint8Array(Buffer.from("6gAVR0Nsv5Y=", "base64")),
"flatFee": true
};
sk = algosdk.mnemonicToSecretKey(sk);
let js_dec = algosdk.signTransaction(o, sk.sk);
assert.deepStrictEqual(Buffer.from(js_dec.blob), Buffer.from(golden, "base64"));
// // Check txid
let tx_golden = "5FJDJD5LMZC3EHUYYJNH5I23U4X6H2KXABNDGPIL557ZMJ33GZHQ";
assert.deepStrictEqual(js_dec.txID, tx_golden);
});
});
describe('Sign and verify bytes', function () {
it('should verify a correct signature', function () {
let account = algosdk.generateAccount();
let toSign = new Uint8Array(Buffer.from([1, 9, 25, 49]));
let signed = algosdk.signBytes(toSign, account.sk);
assert.equal(true, algosdk.verifyBytes(toSign, signed, account.addr))
});
it('should not verify a corrupted signature', function () {
let account = algosdk.generateAccount();
let toSign = Buffer.from([1, 9, 25, 49]);
let signed = algosdk.signBytes(toSign, account.sk);
signed[0] = (signed[0] + 1)%256;
assert.equal(false, algosdk.verifyBytes(toSign, signed, account.addr))
});
});
describe('Multisig Sign', function () {

@@ -61,0 +103,0 @@ it('should return a blob that matches the go code', function () {

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc