Code Monkey home page Code Monkey logo

js-algorand-sdk's Introduction

js-algorand-sdk

CircleCI npm version

AlgoSDK is the official JavaScript library for communicating with the Algorand network. It's designed for modern browsers and Node.js.

Installation

$ npm install algosdk

This package provides TypeScript types, but you will need TypeScript version 4.2 or higher to use them properly.

Browser

Include a minified browser bundle directly in your HTML like so:

<script
  src="https://unpkg.com/[email protected]/dist/browser/algosdk.min.js"
  integrity="sha384-OP8U0zDUgTdYdeyxnrhicwju6SuPxm2tx4WaTYDeP5JiMS/OyifldTK5Y3vzPK9K"
  crossorigin="anonymous"
></script>

or

<script
  src="https://cdn.jsdelivr.net/npm/[email protected]/dist/browser/algosdk.min.js"
  integrity="sha384-OP8U0zDUgTdYdeyxnrhicwju6SuPxm2tx4WaTYDeP5JiMS/OyifldTK5Y3vzPK9K"
  crossorigin="anonymous"
></script>

Information about hosting the package for yourself, finding the browser bundles of previous versions, and computing the SRI hash is available here.

Quick Start

const token = 'Your algod API token';
const server = 'http://127.0.0.1';
const port = 8080;
const client = new algosdk.Algodv2(token, server, port);

(async () => {
  console.log(await client.status().do());
})().catch((e) => {
  console.log(e);
});

Documentation

Documentation for this SDK is available here: https://algorand.github.io/js-algorand-sdk/. Additional resources are available on https://developer.algorand.org.

Examples

Running examples requires access to a running node. Follow the instructions in Algorand's developer resources to install a node on your computer.

As portions of the codebase are written in TypeScript, example files cannot be run directly using node. Please refer to the instructions described in the examples/README.md file for more information regarding running the examples.

SDK Development

Building

To build a new version of the library, run:

npm run build

Generating Documentation

To generate the documentation website, run:

npm run docs

The static website will be located in the docs/ directory.

Testing

We have two test suites: mocha tests in this repo, and the Algorand SDK test suite from https://github.com/algorand/algorand-sdk-testing.

Node.js

To run the mocha tests in Node.js, run:

npm test

To run the SDK test suite in Node.js, run:

make docker-test

Browsers

The test suites can also run in browsers. To do so, set the environment variable TEST_BROWSER to one of our supported browsers. Currently we support testing in chrome and firefox. When TEST_BROWSER is set, the mocha and SDK test suites will run in that browser.

For example, to run mocha tests in Chrome:

TEST_BROWSER=chrome npm test

And to run SDK tests in Firefox:

TEST_BROWSER=firefox make docker-test

Code Style

This project enforces a modified version of the Airbnb code style.

We've setup linters and formatters to help catch errors and improve the development experience:

  • Prettier โ€“ ensures that code is formatted in a readable way.
  • ESLint โ€” checks code for antipatterns as well as formatting.

If using the Visual Studio Code editor with the recommended extensions, ESLint errors should be highlighted in red and the Prettier extension should format code on every save.

Precommit Hook

The linters and formatters listed above should run automatically on each commit to catch errors early and save CI running time.

License

js-algorand-sdk is licensed under an MIT license. See the LICENSE file for details.

js-algorand-sdk's People

Contributors

ahangsu avatar aldur avatar algo-devops-service avatar algobarb avatar algochoi avatar algoidurovic avatar algojack avatar algolucky avatar algorandskiy avatar algorotem avatar barnjamin avatar bricerisingalgorand avatar egieseke avatar eric-warehime avatar evanjrichard avatar excalq avatar fabrice102 avatar fgamundi avatar fionnachan avatar jasonpaulos avatar jasonweathersby avatar jdtzmn avatar joe-p avatar michaeldiamant avatar mjiang102628 avatar onetechnical avatar rotemh avatar shiqizng avatar vervious avatar winder avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-algorand-sdk's Issues

can't encode an object with an undefined value

	let transaction2 = algosdk.makePaymentTxn(myAccountB.addr, 
		myAccountA.addr, params.minFee, 200000, undefined, 
		params.lastRound, params.lastRound + 1000, new Uint8Array(0), 
		params.genesishashb64, params.genesisID);

algosdk.encodeObj(transaction2) fails because of the undefined value.

Transaction Group support for ASA Transfers

The 'get_obj_for_encoding' method on the Transaction class does not seem to set the 'grp' parameter for ASA transfers. This causes a transaction group to fail with the error message 'TransactionPool.Remember: transactionGroup: [0] had zero Group but was submitted in a group of 2'.

I had to monkey patch the method to get it to work,

for (let mp of txns) {
    let orig = mp.get_obj_for_encoding;
    let replace = function() {
        let obj = orig.bind(this)();
        obj.grp = this.group;
        return obj;
    };
    mp.get_obj_for_encoding = replace.bind(mp);
}

Expose LogicSig.fromByte

We can create and serialize a LogicSig object using the 'makeLogicSig' method,

// create LogicSig object and sign with our secret key
let program = Uint8Array.from([1, 32, 1, 0, 34]);  // int 0 => never transfer money
let lsig = algosdk.makeLogicSig(program);
lsig.sign(keys.secretKey);

assert lsig.verify(sender_pk);

console.log(lsig.toByte()); // Serialized LogicSig

However, the deserialization method 'fromByte' is declared as a static method as can be seen in the code below.

static fromByte(encoded) {

As the LogicSig class is not exposed on the algosdk module, we had to import the internal 'src/logicsig.js' module. Could we have this class or the fromByte method exposed on the algosdk object?

Fix main on package.json

Please change main property to 'index.js'.

Android and iOS packager cannot find the module if this field points to the wrong/missing entry point.

public ALGO node

Is there any public ALGO node with a free token that can bu used for tests?

Does not install with latest Node 12 LTS

Hi,

This release added a dependency on keccak256 which in turn uses an outdated version of the native keccak library (1.4.0) causing node-gyp to fail compilation.

The native version v3.0.0 has this issue fixed but the middleware library does not use it.

Regards,
Mauro.

Transaction Group support for LogicSig signed transactions

Making a transaction group where one or more of the transactions are signed by a LogicSig does not work.

The 'signLogicSigTransaction' function internally creates a transaction object from a transaction dictionary and returns the txID & encoded blob. However, the Transaction class constructor does not support passing the groupID as a parameter and sets the internal group parameter to undefined as can be seen in the code below.

this.group = undefined;

This causes the encoded transaction to fail with the error 'empty txgroup' when submitted to the network.

To workaround this issue, we import the internal 'src/transaction.js' & 'src/encoding/encoding.js' modules and reimplement the 'signLogicSigTransaction' function to ensure the groupID is set on the transaction object.

Shorter seed

Is there a way to use a shorter seed?
(Like 12 words instead of 25 words)

empty notefield raises error

in transactionsByAddress, an empty notefield results in an error because noteb64ToNote checks for undefined, and empty notefield decodes to null (null !== undefined but null == undefined)

JS max integer values

I'm writing a client validation library for sanitizing user input for this SDK and ran into an edge case that I believe is worth a mention here.

When trying to set the maximum number of assets that you're allowed to issue to 18446744073709551616, javascript hits its max integer value, which rounds and loses precision.

Basically,

parseInt('18446744073709551616')  // returns 18446744073709552000

The traditional way I understand to get around this is to convert to BigInt instead, but if this SDK is intended for browser use it will also need to be packaged with a polyfill to handle some less capable browsers. If this SDK is also using the standard Number type it could cause downstream issues from a conversion like this.

Happy to help how I can, but i'd love your feedback to see if i'm missing something obvious.

sign transaction in react-native

Hi,

I have developed algorand wallet in react-native, and I find I can't sign the transaction in ios simulator. I find the problem is Buffer.from(). I run the test code in the node env and I can send the transaction. I have compared the transaction's blob and find the node's transaction's blob is different from the react-native's transaction's blob. How should I solve this problem?

thanks a lot.

JS Support of Indexer v2 [5]

  • implementation plan informed by oapi design
  • update algod rest client
  • write indexer rest client
  • write tests: positive tests that hit all end points and negative tests that exercise listed errors (longest part)
  • write handlers, update models
  • cleanup and docs
  • review design with team and address comments

N.B. this ticket scope does not include integration tests, just unit tests.

Implement algorand-sdk-testing tests for new features

  • Create Asset -> Ask for details -> Verify Equality
  • Create Asset -> Ask for details -> Verfy Equality -> Update Asset -> Verify Equality
  • Create -> Destroy
  • Create -> Approve Acceptance -> Transfer -> Verify Equality
  • Freeze account -> Transfer in and out -> Make sure they both fail
  • Unfreeze the account -> transfer in and out -> Make sure they succeed
  • Create -> Mint -> Veriy -> Burn -> Verfy
  • Create with Frozen by default -> Approve Acceptance -> Unfreeze -> Transfer in and out -> Verify
  • Create -> Approve acceptance -> Transfer in -> Revoke -> Verify
  • Create -> attempt to transfer to non-accepting account-> verify failure

HTTPS Support on API

Currently, most web apps will be deployed as HTTPS, which prevents calling HTTP REST calls. If we are not going to implement HTTPS on our REST calls What is the suggestion for handling this? Proxy? Looking for something I can document on our developer site. Many Hackathon users are having this issue.

Npm package has an unnecesary file.

I was developing using the js-algorand-sdk npm package when I found the 123.js file inside the package. As far as I can see, it is an unnecessary file.

Thanks, Manuel.

Can't convert msgpack-encoded transaction dict to a Transaction object

In below example, transaction.Transaction is created, then msgpack-encoded, and written to file. It is then read from file. The user would then like to convert this to a transaction.Transaction so it can be used as a normal transaction object. However, there is no way to convert back to a transaction.Transaction. Recommending exporting or wrapping static method Transaction.from_obj_for_encoding()

Full example from @JasonWeathersby, who was trying to write and read goal clerk sign-compatible transactions :

const algosdk = require('algosdk');

const fs = require('fs');
var client = null;
async function setupClient() {
	if( client == null){
    	const token = "f1dee49e36a82face92fdb21cd3d340a1b369925cd12f3ee7371378f1665b9b1";
		const server = "http://localhost";
		const port = 8080; 
		//const ALGOD_API_ADDR = "algod-address<PLACEHOLDER>";
		//const ALGOD_API_TOKEN = "algod-token<PLACEHOLDER>";
		//const port = port-number<PLACEHOLDER>;

		let algodClient = new algosdk.Algod(token, server, port);
		client = algodClient;
	} else {
		return client;
	}
    return client;
}

function recoverAccount(){
	const passphrase = "situate hill unaware food trigger random similar utility sing lazy person rapid immense ugly outer tilt opinion aerobic candy galaxy come heavy garden about same";//"your-25-word-mnemonic<PLACEHOLDER>";
    let myAccount = algosdk.mnemonicToSecretKey(passphrase);
    return myAccount;
}
// Function used to wait for a tx confirmation
var waitForConfirmation = async function(algodclient, txId) {
    while (true) {
		let lastround = (await algodclient.status()).lastRound;
        let pendingInfo = await algodclient.pendingTransactionInformation(txId);
        if (pendingInfo.round != null && pendingInfo.round > 0) {
            //Got the completed Transaction
            console.log("Transaction " + pendingInfo.tx + " confirmed in round " + pendingInfo.round);
            break;
        }
        await algodclient.statusAfterBlock(lastround + 1);
    }
};
async function writeUnsignedTransctionToFile() {

	try{
		const receiver = "GD64YIY3TWGDMCNPP553DZPPR6LDUSFQOIJVFDPPXWEG3FVOJCCDBBHU5A";
		let algodClient = await setupClient();
		let myAccount = await recoverAccount();
		console.log("My address: %s", myAccount.addr)

		let params = await algodClient.getTransactionParams();

		let txn = algosdk.makePaymentTxn(myAccount.addr, 
			receiver, params.minFee, 100000, undefined, 
			params.lastRound, params.lastRound + 1000, new Uint8Array(0), 
			params.genesishashb64, params.genesisID);
        let sTxn = {
            "txn":txn.get_obj_for_encoding()
        };
		fs.writeFileSync('./unsignedfromjs4.txn', algosdk.encodeObj( sTxn ));	
	}catch( e ){
		console.log( e );
	}
}; 
async function readUnsignedTransctionFromFile() {

	try{
		let algodClient = await setupClient();
		let myAccount = await recoverAccount(); 
		console.log("My address: %s", myAccount.addr)

		let sTxn = algosdk.decodeObj(fs.readFileSync('./unsignedfromjs4.txn')); 
		let unsignedTxn = sTxn.txn;


		console.log( unsignedTxn ); 
		let signedTxn = algosdk.signTransaction(unsignedTxn, myAccount.sk);
		
		let txId = signedTxn.txID;
		console.log("Signed transaction with txID: %s", txId);

		await algodClient.sendRawTransaction(signedTxn.blob);

		// Wait for transaction to be confirmed
		await waitForConfirmation(algodClient, txId);
	} catch ( e ){
		console.log( e );
	}	
}; 
async function writeSignedTransctionToFile() {

	try{
		const receiver = "GD64YIY3TWGDMCNPP553DZPPR6LDUSFQOIJVFDPPXWEG3FVOJCCDBBHU5A";
		let algodClient = await setupClient();
		let myAccount = await recoverAccount();
		console.log("My address: %s", myAccount.addr)

		let params = await algodClient.getTransactionParams();

		let txn = {
			"from": myAccount.addr,
			"to": receiver,
			"fee": params.minFee,
			"flatFee": true,
			"amount": 1000000,
			"firstRound": params.lastRound,
			"lastRound": params.lastRound + 1000,
			"genesisID": params.genesisID,
			"genesisHash": params.genesishashb64
		};
		let signedTxn = algosdk.signTransaction(txn, myAccount.sk);
		fs.writeFileSync('./signedfromjs.stxn', signedTxn.blob );	
	} catch( e ) {
		console.log(e);
	}
}; 
async function readSignedTransctionFromFile() {

	try{
		let algodClient = await setupClient();
		
		let stx = algosdk.decodeObj(fs.readFileSync("./signed.stxn"));
		let tx = await algodClient.sendRawTransaction(stx);
		console.log("Signed transaction with txID: %s", tx.txId);

		// Wait for transaction to be confirmed
		await waitForConfirmation(algodClient, tx.txId);
	} catch( e ) {
		console.log(e);
	}	
}; 

async function testUnsigned(){
    await writeUnsignedTransctionToFile();
    await readUnsignedTransctionFromFile();
}
async function testSigned(){
    await writeSignedTransctionToFile();
    await readSignedTransctionFromFile();
}
testUnsigned();
//testSigned();

[Research] Make transaction objects consistent

Maybe relates to #70. There's been a class of bugs/UX-problems users and dev-rel have been experiencing: some functions expect arguments to pass to a Transaction constructor, some functions expect an already-constructed Transaction, and it's not clear which are which.

For example: main.js:signTransaction(txn, sk) expects txn to be a dictionary of arguments. However, the main.js:make[VariousKindsOf]Transaction functions return an object, not a dictionary of arguments. So, this type of pseudocode would error, which seems to surprise developers:

let txn = makeAssetCreateTxn(arguments, arguments, arguments, etc.)
let signedTxn  = signTransaction(txn, sk) //errors. developers should use txn.signTxn(sk) instead.

Possible solution: Add constructor from Transaction object to Transaction object, so that when the Transaction constructor unexpectedly receives another Transaction, rather than a dictionary of args, the result is not an error.
Possible solution: This might be fixable with better documentation/a different design. There's nothing actually broken here, the problem is that people get surprised when certain functions don't work together. For example, I'm now noticing that main.js:signTransaction, which expects txn to be a dictionary of arguments, says it expects @param txn object with either payment or key registration fields which makes it sound like it needs a Transaction object.

msgpack decodeObj error for certain note data

In Algorand testnet, various blocks including, but not limited to, round 2728533 to round 2729468 seem to contain transactions with note fields such that algosdk.decodeObj(transaction.note) returns a RangeError: Extra 15 bytes located in buffer[1]

I tried using the note field from the same blocks and transactions using the Go SDK and the error didn't show up.

Tx POST missing Content-type header

The algod /v1/transactions POST endpoint expects a binary content, but the Content-Type: x-binary header is not set by the JS SDK when making that request (sendRawTransaction and sendRawTransactions). Right now the algod node API works without this header, but other APIs might not (e.g. PureStake API).
The Java SDK already does that, so it would be update this SDK to match that behavior.

package msgpack error

****/node_modules/@msgpack/msgpack/dist/Decoder.js:85
for await (const buffer of stream) {
^^^^^

SyntaxError: Unexpected reserved word
at createScript (vm.js:80:10)
at Object.runInThisContext (vm.js:139:10)
at Module._compile (module.js:616:28)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at Object. (****/node_modules/@msgpack/msgpack/dist/decode.js:3:19)

Empty blocks can't be accessed

I have a piece of JS that goes out and gets the latest block # then retrieves the contents. The last few weeks there has been scripts keeping a constant flow of txns in each block but today it stopped and I'm unable to get anything about a block.

The code:
async function getLatest() { try { let latest = (await algodclient.status()).lastRound; let temp = (await algodclient.block(latest)); console.log(temp.round) } catch (e) { console.log(e) } }

The error:
TypeError: Cannot read property 'length' of undefined at Algod.block (/Users/tdb/node_modules/algosdk/src/client/algod.js:163:57) at process.internalTickCallback (internal/process/next_tick.js:77:7)

The error is in this function, where it expects a value for txn array length:

/** * block gets the block info for the given round This call blocks * @param roundNumber * @returns {Promise<*>} */ this.block = async function (roundNumber) { if (!Number.isInteger(roundNumber)) throw Error("roundNumber should be an integer"); let res = await c.get("/v1/block/" + roundNumber); if (res.statusCode === 200) { for(var i = 0; i < **res.body.txns.transactions.length**; i++) { res.body.txns.transactions[i] = noteb64ToNote(res.body.txns.transactions[i]); } } return res.body; };

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.