GithubHelp home page GithubHelp logo

stellar / js-stellar-base Goto Github PK

View Code? Open in Web Editor NEW
103.0 41.0 133.0 8.37 MB

The lowest-level stellar helper library. It consists of classes to read, write, hash, and sign Stellar xdr

Home Page: https://stellar.github.io/js-stellar-base/

License: Apache License 2.0

JavaScript 81.93% RPC 16.82% TypeScript 1.05% Makefile 0.21%
stellar blockchain cryptocurrency javascript

js-stellar-base's Introduction

JS Stellar Base

Tests Code Climate Coverage Status Dependency Status

The stellar-base library is the lowest-level stellar helper library. It consists of classes to read, write, hash, and sign the xdr structures that are used in stellar-core. This is an implementation in JavaScript that can be used on either Node.js or web browsers.

Warning! The Node version of this package uses the sodium-native package, a native implementation of Ed25519 in Node.js, as an optional dependency. This means that if for any reason installation of this package fails, stellar-base will fallback to the much slower implementation contained in tweetnacl.

If you'd explicitly prefer not to install the sodium-native package, pass the appropriate flag to skip optional dependencies when installing this package (e.g. --no-optional if using npm install or --without-optional using yarn install).

If you are using stellar-base in a browser you can ignore this. However, for production backend deployments you should most likely be using sodium-native. If sodium-native is successfully installed and working, StellarBase.FastSigning variable will be equal true. Otherwise it will be false.

Quick start

Using yarn to include js-stellar-base in your own project:

yarn add @stellar/stellar-base

For browsers, use Bower to install it. It exports a variable StellarBase. The example below assumes you have stellar-base.js relative to your html file.

<script src="stellar-base.js"></script>
<script>
  console.log(StellarBase);
</script>

Install

To use as a module in a Node.js project

  1. Install it using yarn:
yarn add @stellar/stellar-base
  1. require/import it in your JavaScript:
var StellarBase = require('@stellar/stellar-base');

To self host for use in the browser

  1. Install it using bower:
bower install stellar-base
  1. Include it in the browser:
<script src="./bower_components/stellar-base/stellar-base.js"></script>
<script>
  console.log(StellarBase);
</script>

If you don't want to use install Bower, you can copy built JS files from the bower-js-stellar-base repo.

To use the cdnjs hosted script in the browser

  1. Instruct the browser to fetch the library from cdnjs, a 3rd party service that hosts js libraries:
<script src="https://cdnjs.cloudflare.com/ajax/libs/stellar-base/{version}/stellar-base.js"></script>
<script>
  console.log(StellarBase);
</script>

Note that this method relies using a third party to host the JS library. This may not be entirely secure.

Make sure that you are using the latest version number. They can be found on the releases page in Github.

To develop and test js-stellar-base itself

  1. Install Node 18.x

We support the oldest LTS release of Node, which is currently 18.x. Please likewise install and develop on Node 16 so you don't get surprised when your code works locally but breaks in CI.

If you work on several projects that use different Node versions, you might find helpful to install a NodeJS version manager:

  1. Install Yarn

This project uses Yarn to manages its dependencies. To install Yarn, follow the project instructions available at https://yarnpkg.com/en/docs/install.

  1. Clone the repo
git clone https://github.com/stellar/js-stellar-base.git
  1. Install dependencies inside js-stellar-base folder
cd js-stellar-base
yarn
  1. Observe the project's code style

While you're making changes, make sure to regularly run the linter to catch any linting errors (in addition to making sure your text editor supports ESLint)

yarn lint

as well as fixing any formatting errors with

yarn fmt

If you're working on a file not in src, limit your code to Node 6.16 ES! See what's supported here: https://node.green/. (Our npm library must support earlier versions of Node, so the tests need to run on those versions.)

Updating XDR definitions

  1. Make sure you have Docker installed and running.
  2. make reset-xdr

Usage

For information on how to use js-stellar-base, take a look at the docs in the docs folder.

Testing

To run all tests:

yarn test

To run a specific set of tests:

yarn test:node
yarn test:browser

Tests are also run automatically in Github Actions for every master commit and pull request.

Documentation

Documentation for this repo lives inside the docs folder.

Contributing

Please see the CONTRIBUTING.md for details on how to contribute to this project.

Publishing to npm

npm version [<newversion> | major | minor | patch | premajor | preminor | prepatch | prerelease]

A new version will be published to npm and Bower by GitHub Actions.

npm >= 2.13.0 required. Read more about npm version.

License

js-stellar-base is licensed under an Apache-2.0 license. See the LICENSE file for details.

js-stellar-base's People

Contributors

abuiles avatar andywer avatar bartekn avatar chadoh avatar charlie-wasp avatar dependabot[bot] avatar dydt avatar fnando avatar fredericheem avatar ire-and-curses avatar irisli avatar ivandepivan avatar jedmccaleb avatar jeesunikim avatar johansten avatar kalepail avatar leighmcculloch avatar marcelosalloum avatar morleyzhi avatar nullstyle avatar orbitlens avatar overcat avatar piyalbasu avatar pselden avatar ryanleecode avatar shaptic avatar silence48 avatar thejollyrogers avatar torstenstueber avatar vcarl 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-stellar-base's Issues

Improve operation builders for `manageOffer` and `createPassiveOffer` to allow for non-floating point prices

See: https://github.com/stellar/js-stellar-base/blob/master/src/operation.js#L256

Notice that the price argument is assumed to be a javascript number (i.e. a double-sized floating point number). To allow for more precise pricing, we should expand js-stellar-base to work with string inputs and bignumber inputs.

We should integrate https://github.com/MikeMcl/bignumber.js for big decimal arithmetic, and use it when converting user-input to prices.

Update fees

Should be set to 100 stroops per operation.

Asset management

This would be an API breaking change, but can you please take a look at how you handle assets?

Seriously, assets are delivered as:

source_asset_type
source_asset_code
source_asset_issuer

destination_asset_type
destination_asset_code
destination_asset_issuer

asset_type
asset_code
asset_issuer

Right now I've got three version of the same bloody code,

            if ($scope.send.asset.asset_type === 'native') {
                asset = StellarSdk.Asset.native();
            } else {
                asset = new StellarSdk.Asset(
                    $scope.send.asset.asset_code,
                    $scope.send.asset.asset_issuer
                );
            }

just to get an Asset out of the json I get back from your API.

Obviously I could make that into one version by adding optional prefixes to the object property accessed, but why should I have go to that extent to get something that basic done?

How about breaking that up into a json-stanza, for easy conversion to an Asset object?

source_asset.whatever
destination_asset.whatever
asset.whatever

And then adding an Asset.from_json()

Cannot create Transaction from TransactionEnvelope

var StellarBase = require('StellarBase');
var t = new StellarBase.Transaction('42cf0559790f6c3b64de15120df0bb25caab7dc2db4fb4a18a35e881bf323af7000003e800002daf0000000a0000000000000000000000010000000000000001dbf7da8de1508d8aa4c6030cf860d9d97b1476742809b0958e020977d4a3faff0000000000000000773594000000000142cf0559ae85a7bdb6e58ae6a3f2f58ab30740b093f1d9e7631cbda27e59ddde4c753068f675be655a4351947e8c3d2594c272771e7bc7be550213dbedaed13b0d1f3004');

Getting error: Uncaught TypeError: xdr.TransactionEnvelope.fromXdr is not a function

Problem signing transactions with sign()

If I try to sign a transaction outside of the TransactionBuilder, it fails. That is, this code:

var money_account = new StellarLib.Account("GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ", 27);
var transaction = new StellarLib.TransactionBuilder(money_account)
    .addOperation(StellarLib.Operation.payment({
      destination: "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW",
      asset: StellarLib.Asset.native(),
      amount: "40000000"
    }))
    // .addSigner(StellarLib.Keypair.fromSeed(rootSeedString))
    .build();
var signer = StellarLib.Keypair.fromSeed(rootSeedString);
transaction.sign([signer]);
server.submitTransaction(transaction)
  .catch(function (err){
    console.log(err);
  });

failed with this error:

dydt:workspace diyang$ node client_endpoints_examples.js 

/Users/diyang/workspace/js-stellar-lib/node_modules/stellar-base/lib/transaction.js:82
                    var sig = kp.signDecorated(txHash);
                                 ^
TypeError: Object [object Object] has no method 'signDecorated'
    at /Users/diyang/workspace/js-stellar-lib/node_modules/stellar-base/lib/transaction.js:82:34
    at arrayEach (/Users/diyang/workspace/js-stellar-lib/node_modules/lodash/index.js:1289:13)
    at /Users/diyang/workspace/js-stellar-lib/node_modules/lodash/index.js:3345:13
    at Transaction.sign (/Users/diyang/workspace/js-stellar-lib/node_modules/stellar-base/lib/transaction.js:81:31)
    at Object.<anonymous> (/Users/diyang/workspace/client_endpoints_examples.js:158:13)
    ...

But this:

var money_account = new StellarLib.Account("GCEZWKCA5VLDNRLN3RPRJMRZOX3Z6G5CHCGSNFHEYVXM3XOJMDS674JZ", 26);
var transaction = new StellarLib.TransactionBuilder(money_account)
    .addOperation(StellarLib.Operation.payment({
      destination: "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW",
      asset: StellarLib.Asset.native(),
      amount: "40000000"
    }))
    .addSigner(StellarLib.Keypair.fromSeed(rootSeedString))
    .build();
// var signer = StellarLib.Keypair.fromSeed(rootSeedString);
// transaction.sign([signer]);
server.submitTransaction(transaction)
  .catch(function (err){
    console.log(err);
  });

succeeded.

path payment example

"Just one quick last request. It would be great to see either some docs of examples of payments with specified paths, or even better, some example transactions in the live ledger."

Fix timebounds in transaction builder

When using the following options to build a transaction with timebounds:

{
  minTime: 12345,
  maxTime: 123456,
}

I get the error

XDR Write Error: 1234 is not an UnsignedHyper

Somewhere, js-stellar-base is not converting the string into an UnsignedHyper internally.

Add working example of building transaction from 0 to 1

(note: 0 means nothing. 1 means transaction created)

Right now, the docs has examples that cover the field from 0 to 1 but in order to actually go from 0 to 1, the user must combine together multiple examples. In this 0 to 1 analogy, the examples we have might look something like this: 0 to 0.6, 0.2 to 0.8, 0.4 to 1.0.

Here is an example of what I would consider building a transaction from 0 to 1. It includes signing and submission.

https://gist.github.com/irisli/71f04f472475201159e7

The example in this gist will have to be modified for js-stellar-base. Js-stellar-sdk can have a 0 to 1 that includes fetching account sequence number and transaction submission while the js-stellar-base can be a near subset (that excludes fetching seq number and submission).

dist directory removal

Could we remove and ignore the dist directory and its content ? It pollutes every pull request, and make every merge fails.

Settings memo for the tx builder seems to fail

Tried setting a memo for a tx in multiple ways, but it always throws an exception when building it.

Things I tried
b = new StellarBase.TransactionBuilder(id, memo: 'hello)
b = new StellarBase.TransactionBuilder(id, memo: (StellarBase.Memo.text('hello))
b.memo = 'hello'
b.memo = StellarBase.Memo.text('hello')

Source account for operations are not exposed.

Operation.operationToObject() doesn't expose operation source accounts, which makes it impossible to inspect transactions before you sign them, in order to verify that you're not signing anything malicious.

Keypair.isValidSeed()

I suggest to implement Keypair.isValidSeed():

  • there's already isValidPublicKey() so I expected a symmetrical isValidSeed().
  • The closest substitute is to "try" to create keypair with Keypair.fromSeed(), but that makes use of this keyword. Therefore, for example in mocha framework such test will always fail:
expect(questionableSeed).to.satisfy(stellarSdk.Keypair.fromSeed);

strkey.decodeCheck false positive

There is a strange behaviour of thirty-two package that breaks our strkey.decodeCheck method:

var base32 = require("thirty-two");

console.log(base32.decode('GB6OWYST45X57HCJY5XWOHDEBULB6XUROWPIKW77L5DSNANBEQGUPADT'));
console.log(base32.decode('GB6OWYST45X57HCJY5XWOHDEBULB6XUROWPIKW77L5DSNANBEQGUPADTA'));

Output:

<Buffer 30 7c eb 62 53 e7 6f df 9c 49 c7 6f 67 1c 64 0d 16 1f 5e 91 75 9e 85 5b ff 5f 47 26 81 a1 24 0d 47 80 73>
<Buffer 30 7c eb 62 53 e7 6f df 9c 49 c7 6f 67 1c 64 0d 16 1f 5e 91 75 9e 85 5b ff 5f 47 26 81 a1 24 0d 47 80 73>

Investigate this and update strkey.decodeCheck to throw errors for the second (incorrect) address.

Allow users to specify transaction fee instead of base fee

In the transaction builder, it is only possible to specify a transaction fee via the option fee.

https://github.com/stellar/js-stellar-base/blob/master/src/transaction_builder.js#L67

constructor(sourceAccount, opts={}) {
  if (!sourceAccount) {
    throw new Error("must specify source account for the transaction");
  }
  this.source        = sourceAccount;
  this.operations    = [];
  this.signers       = [];

  this.baseFee    = opts.fee || BASE_FEE;

Then later:
https://github.com/stellar/js-stellar-base/blob/master/src/transaction_builder.js#L106

build() {
  let sequenceNumber = new BigNumber(this.source.sequenceNumber()).add(1);

  var attrs = {
    sourceAccount: Keypair.fromAccountId(this.source.accountId()).xdrAccountId(),
    fee:           this.baseFee * this.operations.length,

This makes it impossible to specify an exact fee. Furthermore, it is confusing because opts.fee becomes interpreted as what should be opts.baseFee.

This automatic calculation of fee was introduced here: fa762a9.

Endpoint: Market Order for target volume

This query would allow someone who wishes to place a market order of a given volume to understand the cost they will pay.

Input: normal orderbook args, and volume to sell
Output: a set of pricelevels where volume available at that price level is less than the target volume

Check to see if keyword arguments are legitimate

It's possible to pass in options that are not valid without any errors. For example, setOptions (https://github.com/stellar/js-stellar-base/blob/master/src/operation.js#L213) does not take a thresholds object (even though the comments indicate that it does). Passing a thresholds object like so:

        var transaction = new StellarSdk.TransactionBuilder(account)
            // this operation funds the new account with XLM
            .addOperation(StellarSdk.Operation.setOptions({
                thresholds: {
                    weight: 1, // master key weight
                    low: 1,
                    medium: 2, // a payment is medium threshold
                    high: 2 // make sure to have enough weight to add up to the high threshold!
                }
            }))
            .build();

will fail silently.

node version must be 0.10x

This lib only works with node 0.10.x due to the ed25519 crypto lib that compiles only with that major version.

Document enums and flags (and make them simpler to use?)

This basically the same issue as lightsail-network/java-stellar-sdk#31, but for the JS SDK.

It's possible to use enums from the generated XDR classes to make code clearer, as in setting flags on an account:

StellarSdk.Operation.setOptions({
  setFlags: StellarSdk.xdr.AccountFlags.authRevocableFlag().value |
    StellarSdk.xdr.AccountFlags.authRequiredFlag().value
});

// or slightly less awkward if you make yourself a shortcut:
var flags = StellarSdk.xdr.AccountFlags;
StellarSdk.Operation.setOptions({
  setFlags: flags.authRevocableFlag().value | flags.authRequiredFlag().value
});

It'd be helpful if these were documented.

It might also be nice if working with these was easier, though that's maybe better handled as a separate issue? (maybe the setFlags option could take an object, or the flags were exposed at the root level, or the flags weren't methods and you didn't have to get the value property from them, etc.).

Set Options operation should take strings for numbers

In the setOptions function, if any of the integer options (e.g. setFlags, signer.weight, highThreshold) are strings, it will error out.

Try this code in https://stellar.org/developers. Then, try it again except with clearFlags as a native number (not stringed).

var account = new StellarSdk.Account('GC4M7MU4X7CQII66BHAAO4RRZG654UAS74B2ZAVIYCZYCTZFRB35C3OM',123);
var transaction = new StellarSdk.TransactionBuilder(account)
  .addOperation(StellarSdk.Operation.setOptions({
    clearFlags: '4',
  }))
  .build()
console.log(transaction.toEnvelope().toXDR('base64'))

utf-8 support in MEMO_TEXT

Overview

Although the XDR RFC only specifies that strings be ASCII many XDR libraries (like the native golang one) support utf-8. It works well since utf-8 is a superset of ASCII.

Even if there are few use cases for utf-8 in XDR strings, i think it's still important to support other languages in MEMO_TEXT.

I made a transaction containing 4 Chinese characters (12 bytes) and it comes out in multiple forms. Some of these forms are understandable since cURL outputs things differently such as the & but ideally, they should all show the Chinese characters

Apparent issues:

  • memo in a freshly created transaction is different from that in a transaction decoded from xdr

Code used to reproduce this

var sourceSecretKey = 'SCC2GLOCQLDIJPTQB6O2K2GVUXW52IWLSCKE76EMU5ILMED3CYQFHUFC';
var receiverPublicKey = 'GAIRISXKPLOWZBMFRPU5XRGUUX3VMA3ZEWKBM5MSNRU3CHV6P4PYZ74D';

// Calculate the source account's public key
var sourceKeypair = StellarSdk.Keypair.fromSeed(sourceSecretKey);
var sourcePublicKey = sourceKeypair.address()

// Configure StellarSdk to talk to the horizon instance hosted by Stellar.org
// To use the public (live) network, set the hostname to 'horizon.stellar.org'
var server = new StellarSdk.Server({
  hostname: 'horizon-testnet.stellar.org',
  secure: true,
  port: 443
});

server.loadAccount(sourcePublicKey)
  .then(function(account) {
    var transaction = new StellarSdk.TransactionBuilder(account)
      .addOperation(StellarSdk.Operation.payment({
        destination: receiverPublicKey,
        asset: StellarSdk.Asset.native(),
        amount: '350.1234567',
      }))
      .addMemo(StellarSdk.Memo.text('三代之時'))
      .build()

    // Sign this transaction with the secret key
    transaction.sign(sourceKeypair)

    // Let's see the XDR (encoded in base64) of the transaction we just built
    var txEnvelopeXDR = transaction.toEnvelope().toXDR('base64');

    console.log('Local transactionEnvelope memo just freshly created: ' + transaction.memo.value())
    console.log('Memo from Transaction built from xdr (Transaction->XDR->Transaction): ' 
      + new StellarSdk.Transaction(txEnvelopeXDR).memo.value());

    // Submit the transaction to the Horizon server. The Horizon server will then
    // submit the transaction into the network for us.
    server.submitTransaction(transaction)
      .then(function(result) {
        console.log('https://horizon-testnet.stellar.org' + result._links.transaction.href);
      })
      .catch(function (err){
        console.error(err);
      });
  })

JS Console output

Local transactionEnvelope memo just freshly created: 三代之時
Memo from Transaction built from xdr (Transaction->XDR->Transaction):   cKB
https://horizon-testnet.stellar.org/transactions/307d256a81a734e8e249b911cbe5150db3f25fdf7d9cfe6a06103ba36bcc3dbe

Transaction in cURL

image

Transaction in browser

image

Transaction in laboratory

image

OperationResult has no method 'read'

this is the same section of code we were looking at earlier
//aSwitch =
{ name: 'txFailed', value: -2 }
// arm =
arm: results
// armType =
{ _childType:
{ [Function: ChildUnion]
unionName: 'OperationResult',
_switchOn:
{ [Function: ChildEnum]
enumName: 'OperationResultCode',
_members: [Object],
_byValue: {},
opInner: [Function],
opBadAuth: [Function],
opNoAccount: [Function] },
_switches: {},
_arms: { tr: [Object] },
opInner: [Function],
opBadAuth: [Function],
opNoAccount: [Function] },
_maxLength: 2147483647 }
TypeError: Object [object Object] has no method 'read'
at Function.read (/Users/andrewrogers/Code/stellar/js-stellar-lib/node_modules/stellar-base/node_modules/js-xdr/lib/union.js:109:29)

The XDR in question looks like:

xdr.union("TransactionResultResult", {
switchOn: xdr.lookup("TransactionResultCode"),
switchName: "code",
switches: {
txSuccess: "results",
txFailed: "results" },
arms: {
results: xdr.varArray(xdr.lookup("OperationResult"), 2147483647) },
defaultArm: xdr"void" });

Fix XDR encapsulation violations

There are a number of encapsulation violations, that is, a number of objects within this project that access the private state of different object. For reason's I don't want to fully document here--google "why is encapsulation important" for reasoning--we should fix this.

How do you detect this violation? We use a leading underscore to denote a property that is private to an object. For example, every object that is an instance of an XDR struct keeps its internal attribute state in a property named _attributes. The only acceptable accessor to these properties is the object itself, thus, the only valid access of that private statement is of the form this._attributes. Anytime you see notThis._somePrivateAttribute we have an encapsulation violation.

While I have not enumerated every instance of this violation in the codebase, I have identified some patterns:

  1. Accessing the value of an XDR union. There are several instances where the value of a union is accessed through the private value _value. Instead, you should call the accessor method value(). Thus body._value becomes body.value()
  2. Accessing the switch (i.e. disciminant) of a union. Like 1, you should not be referring to someUnion._switch directly, instead using someUnion.switch()
  3. Accessing xdr struct attributes through the _attributes private attributes. Each attribute on a struct has a helper accessor method that should be used. Instead of signer._attributes.weight it should be signer.weight().

There are probably more patterns... as you see them, feel free to ask a question about how to resolve the problem.

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.