Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: deprecate Network, use explicit passphrase (2) #207

Merged
merged 8 commits into from
Aug 1, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
As this project is pre 1.0, breaking changes may happen for minor version bumps.
A breaking change will get clearly notified in this log.

## Unreleased

Do not rely on global singleton Network. The following methods take optional network passphrase, and `console.warn` if it is not passed.
- static method `Keypair.master`
- constructor `Transaction`
- constructor `TransactionBuilder` and method `TransactionBuilder.setNetworkPassphrase`

Also, whole class `Network` has been deprecated.


## [v1.0.3](https://github.com/stellar/js-stellar-base/compare/v1.0.2...v1.0.3)

### Add
Expand Down
19 changes: 10 additions & 9 deletions docs/reference/base-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ title: Transaction Examples
- [Creating an account](#creating-an-account)
- [Assets](#assets)
- [Path payment](#path-payment)
- [Multi-Signature account](#multi-signature-account)
- [Multi-signature account](#multi-signature-account)
- [Set up multisig account](#set-up-multisig-account)

## Creating an account

Expand All @@ -19,15 +20,14 @@ const server = new StellarSdk.Server('https://horizon-testnet.stellar.org')
const source = StellarSdk.Keypair.fromSecret('SA3W53XXG64ITFFIYQSBIJDG26LMXYRIMEVMNQMFAQJOYCZACCYBA34L')
const destination = StellarSdk.Keypair.random()

StellarSdk.Network.useTestNetwork()

server.accounts()
.accountId(source.publicKey())
.call()
.then(({ sequence }) => {
const account = new StellarSdk.Account(source.publicKey(), sequence)
const transaction = new StellarSdk.TransactionBuilder(account, {
fee: StellarSdk.BASE_FEE
fee: StellarSdk.BASE_FEE,
networkPassphrase: Networks.TESTNET
})
.addOperation(StellarSdk.Operation.createAccount({
destination: destination.publicKey(),
Expand Down Expand Up @@ -78,12 +78,12 @@ In the example below we're sending 1000 XLM (at max) from `GABJLI6IVBKJ7HIC5NN7H
The [path payment](https://www.stellar.org/developers/learn/concepts/list-of-operations.html#path-payment) will cause the destination address to get 5.5 GBP. It will cost the sender no more than 1000 XLM. In this example there will be 3 exchanges, XLM -> USD, USD-> EUR, EUR->GBP.

```js
StellarSdk.Network.useTestNetwork();
var keypair = StellarSdk.Keypair.fromSecret(secretString);

var source = new StellarSdk.Account(keypair.publicKey(), "46316927324160");
var transaction = new StellarSdk.TransactionBuilder(source, {
fee: StellarSdk.BASE_FEE
fee: StellarSdk.BASE_FEE,
networkPassphrase: Networks.TESTNET
})
.addOperation(StellarSdk.Operation.pathPayment({
sendAsset: StellarSdk.Asset.native(),
Expand Down Expand Up @@ -125,14 +125,14 @@ In each example, we'll use the root account.


```js
StellarSdk.Network.useTestNetwork();
var rootKeypair = StellarSdk.Keypair.fromSecret("SBQWY3DNPFWGSZTFNV4WQZLBOJ2GQYLTMJSWK3TTMVQXEY3INFXGO52X")
var account = new StellarSdk.Account(rootkeypair.publicKey(), "46316927324160");

var secondaryAddress = "GC6HHHS7SH7KNUAOBKVGT2QZIQLRB5UA7QAGLA3IROWPH4TN65UKNJPK";

var transaction = new StellarSdk.TransactionBuilder(account, {
fee: StellarSdk.BASE_FEE
fee: StellarSdk.BASE_FEE,
networkPassphrase: Networks.TESTNET
})
.addOperation(StellarSdk.Operation.setOptions({
signer: {
Expand All @@ -154,7 +154,8 @@ transaction.sign(rootKeypair); // only need to sign with the root signer as the
// now create a payment with the account that has two signers

var transaction = new StellarSdk.TransactionBuilder(account, {
fee: StellarSdk.BASE_FEE
fee: StellarSdk.BASE_FEE,
networkPassphrase: Networks.TESTNET
})
.addOperation(StellarSdk.Operation.payment({
destination: "GBTVUCDT5CNSXIHJTDHYSZG3YJFXBAJ6FM4CKS5GKSAWJOLZW6XX7NVC",
Expand Down
13 changes: 7 additions & 6 deletions docs/reference/building-transactions.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,13 @@ The returned transaction will contain the sequence number of the source account.


```js
StellarSdk.Network.useTestNetwork();
// StellarBase.Network.usePublicNetwork(); if this transaction is for the public network
// Create an Account object from an address and sequence number.
var account=new StellarBase.Account("GD6WU64OEP5C4LRBH6NK3MHYIA2ADN6K6II6EXPNVUR3ERBXT4AN4ACD","2319149195853854");

var transaction = new StellarBase.TransactionBuilder(account, {
fee: StellarBase.BASE_FEE
fee: StellarBase.BASE_FEE,
networkPassphrase: Networks.TESTNET
})
// add a payment operation to the transaction
.addOperation(StellarBase.Operation.payment({
Expand Down Expand Up @@ -80,9 +80,10 @@ There are 5 types of memos:

```js
var memo = Memo.text('Happy birthday!');
var transaction = new StellarBase.TransactionBuilder(account, {
var transaction = new StellarBase.TransactionBuilder(account, {
memo: memo,
fee: StellarBase.BASE_FEE
fee: StellarBase.BASE_FEE,
networkPassphrase: Networks.TESTNET
})
.addOperation(StellarBase.Operation.payment({
destination: "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW",
Expand Down Expand Up @@ -142,15 +143,15 @@ var keypair = Keypair.random();


```js
StellarBase.Network.useTestNetwork();
var key1 = Keypair.fromSecret('SBK2VIYYSVG76E7VC3QHYARNFLY2EAQXDHRC7BMXBBGIFG74ARPRMNQM');
var key2 = Keypair.fromSecret('SAMZUAAPLRUH62HH3XE7NVD6ZSMTWPWGM6DS4X47HLVRHEBKP4U2H5E7');

// Create an Account object from an address and sequence number.
var account=new StellarBase.Account("GD6WU64OEP5C4LRBH6NK3MHYIA2ADN6K6II6EXPNVUR3ERBXT4AN4ACD","2319149195853854");

var transaction = new StellarBase.TransactionBuilder(account, {
fee: StellarBase.BASE_FEE
fee: StellarBase.BASE_FEE,
networkPassphrase: Networks.TESTNET
})
.addOperation(StellarBase.Operation.payment({
destination: "GASOCNHNNLYFNMDJYQ3XFMI7BYHIOCFW3GJEOWRPEGK2TDPGTG2E5EDW",
Expand Down
19 changes: 14 additions & 5 deletions src/keypair.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { sign, verify, generate } from './signing';
import * as base58 from './base58';
import { StrKey } from './strkey';
import xdr from './generated/stellar-xdr_generated';
import { hash } from './hashing';

/**
* `Keypair` represents public (and secret) keys of the account.
Expand Down Expand Up @@ -90,15 +91,23 @@ export class Keypair {

/**
* Returns `Keypair` object representing network master key.
* @param {string} [networkPassphrase] passphrase of the target stellar network (e.g. "Public Global Stellar Network ; September 2015").
* @returns {Keypair}
*/
static master() {
if (Network.current() === null) {
throw new Error(
'No network selected. Use `Network.use`, `Network.usePublicNetwork` or `Network.useTestNetwork` helper methods to select network.'
static master(networkPassphrase) {
// Deprecation warning. TODO: remove optionality with next major release.
if (!networkPassphrase) {
console.warn(
'Global `Network.current()` is deprecated. Please pass explicit argument instead, e.g. `Keypair.master(Networks.PUBLIC)` (see https://git.io/fj9fG for more info).'
);
if (Network.current() === null) {
throw new Error(
'No network selected. Use `Network.use`, `Network.usePublicNetwork` or `Network.useTestNetwork` helper methods to select network.'
);
}
networkPassphrase = Network.current().networkPassphrase();
}
return this.fromRawEd25519Seed(Network.current().networkId());
return this.fromRawEd25519Seed(hash(networkPassphrase));
}

/**
Expand Down
5 changes: 5 additions & 0 deletions src/network.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ let current = null;
* Creates a new `Network` object.
* @constructor
* @param {string} networkPassphrase Network passphrase
* @deprecated
Akuukis marked this conversation as resolved.
Show resolved Hide resolved
*/
export class Network {
constructor(networkPassphrase) {
Expand Down Expand Up @@ -52,6 +53,10 @@ export class Network {
* @returns {void}
*/
static use(network) {
console.warn(
'Global class `Network` is deprecated. Please pass explicit argument instead, e.g. `new Transaction(envelope, Networks.PUBLIC)` (see https://git.io/fj9fG for more info).'
);

current = network;
}

Expand Down
47 changes: 37 additions & 10 deletions src/transaction.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import map from 'lodash/map';
import each from 'lodash/each';
import isString from 'lodash/isString';
import { xdr, hash } from './index';
import xdr from './generated/stellar-xdr_generated';
import { hash } from './hashing';

import { StrKey } from './strkey';
import { Operation } from './operation';
Expand All @@ -17,13 +18,23 @@ import { Keypair } from './keypair';
* submitting to the network or forwarding on to additional signers.
* @constructor
* @param {string|xdr.TransactionEnvelope} envelope - The transaction envelope object or base64 encoded string.
* @param {string} [networkPassphrase] passphrase of the target stellar network (e.g. "Public Global Stellar Network ; September 2015").
*/
export class Transaction {
constructor(envelope) {
constructor(envelope, networkPassphrase) {
if (typeof envelope === 'string') {
const buffer = Buffer.from(envelope, 'base64');
envelope = xdr.TransactionEnvelope.fromXDR(buffer);
}

// Deprecation warning. TODO: remove optionality with next major release.
if (typeof networkPassphrase !== 'string') {
console.warn(
'Global `Network.current()` is deprecated. Please pass explicit argument instead, e.g. `new Transaction(envelope, Networks.PUBLIC)` (see https://git.io/fj9fG for more info).'
);
}
this._networkPassphrase = networkPassphrase;

// since this transaction is immutable, save the tx
this.tx = envelope.tx();
this.source = StrKey.encodeEd25519PublicKey(
Expand Down Expand Up @@ -51,6 +62,28 @@ export class Transaction {
this.signatures = map(signatures, (s) => s);
}

get networkPassphrase() {
if (this._networkPassphrase) {
return this._networkPassphrase;
}

console.warn(
'Global `Network.current()` is deprecated. Please pass explicit argument instead, e.g. `new Transaction(envelope, Networks.PUBLIC)` (see https://git.io/fj9fG for more info).'
);

if (Network.current() === null) {
throw new Error(
'No network selected. Use `Network.use`, `Network.usePublicNetwork` or `Network.useTestNetwork` helper methods to select network.'
);
}

return Network.current().networkPassphrase();
}

set networkPassphrase(networkPassphrase) {
this._networkPassphrase = networkPassphrase;
}

get memo() {
return Memo.fromXDRObject(this._memo);
}
Expand Down Expand Up @@ -86,7 +119,7 @@ export class Transaction {
* Example:
* ```javascript
* // `transactionXDR` is a string from the person generating the transaction
* const transaction = new Transaction(transactionXDR);
* const transaction = new Transaction(transactionXDR, networkPassphrase);
* const keypair = Keypair.fromSecret(myStellarSeed);
* return transaction.getKeypairSignature(keypair);
* ```
Expand Down Expand Up @@ -192,14 +225,8 @@ export class Transaction {
* @returns {Buffer}
*/
signatureBase() {
if (Network.current() === null) {
throw new Error(
'No network selected. Use `Network.use`, `Network.usePublicNetwork` or `Network.useTestNetwork` helper methods to select network.'
);
}

return Buffer.concat([
Network.current().networkId(),
hash(this.networkPassphrase),
xdr.EnvelopeType.envelopeTypeTx().toXDR(),
this.tx.toXDR()
]);
Expand Down
40 changes: 27 additions & 13 deletions src/transaction_builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import xdr from './generated/stellar-xdr_generated';
import { Keypair } from './keypair';
import { Transaction } from './transaction';
import { Memo } from './memo';
import { Network } from './network';

/**
* Minimum base fee for transactions. If this fee is below the network
Expand Down Expand Up @@ -52,18 +53,18 @@ export const TimeoutInfinite = 0;
* a payment to `destinationB`. The built transaction is then signed by `sourceKeypair`.</p>
*
* ```
* var transaction = new TransactionBuilder(source, { fee })
* .addOperation(Operation.createAccount({
destination: destinationA,
startingBalance: "20"
})) // <- funds and creates destinationA
.addOperation(Operation.payment({
destination: destinationB,
amount: "100",
asset: Asset.native()
})) // <- sends 100 XLM to destinationB
* .setTimeout(30)
* .build();
* var transaction = new TransactionBuilder(source, { fee, networkPassphrase: Networks.TESTNET })
* .addOperation(Operation.createAccount({
* destination: destinationA,
* startingBalance: "20"
* })) // <- funds and creates destinationA
* .addOperation(Operation.payment({
* destination: destinationB,
* amount: "100",
* asset: Asset.native()
* })) // <- sends 100 XLM to destinationB
* .setTimeout(30)
* .build();
*
* transaction.sign(sourceKeypair);
* ```
Expand All @@ -75,6 +76,7 @@ export const TimeoutInfinite = 0;
* @param {number|string|Date} [opts.timebounds.minTime] - 64 bit unix timestamp or Date object
* @param {number|string|Date} [opts.timebounds.maxTime] - 64 bit unix timestamp or Date object
* @param {Memo} [opts.memo] - The memo for the transaction
* @param {string} [opts.networkPassphrase] passphrase of the target stellar network (e.g. "Public Global Stellar Network ; September 2015").
*/
export class TransactionBuilder {
constructor(sourceAccount, opts = {}) {
Expand All @@ -93,6 +95,7 @@ export class TransactionBuilder {
this.timebounds = clone(opts.timebounds) || null;
this.memo = opts.memo || Memo.none();
this.timeoutSet = false;
this.networkPassphrase = opts.networkPassphrase || null;
}

/**
Expand Down Expand Up @@ -160,6 +163,17 @@ export class TransactionBuilder {
return this;
}

/**
* Set network nassphrase for the Transaction that will be built.
*
* @param {string} [networkPassphrase] passphrase of the target stellar network (e.g. "Public Global Stellar Network ; September 2015").
* @returns {TransactionBuilder}
*/
setNetworkPassphrase(networkPassphrase) {
this.networkPassphrase = networkPassphrase;
return this;
}

/**
* This will build the transaction.
* It will also increment the source account's sequence number by 1.
Expand Down Expand Up @@ -211,7 +225,7 @@ export class TransactionBuilder {
xtx.operations(this.operations);

const xenv = new xdr.TransactionEnvelope({ tx: xtx });
const tx = new Transaction(xenv);
const tx = new Transaction(xenv, this.networkPassphrase);

this.source.incrementSequenceNumber();

Expand Down
26 changes: 16 additions & 10 deletions test/unit/transaction_envelope_test.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
describe('TransactionEnvelope', function() {

it("can successfully decode an envelope", function(done) {

it('can successfully decode an envelope', function(done) {
// from https://github.com/stellar/js-stellar-sdk/issues/73
let xdr = "AAAAAPQQv+uPYrlCDnjgPyPRgIjB6T8Zb8ANmL8YGAXC2IAgAAAAZAAIteYAAAAHAAAAAAAAAAAAAAABAAAAAAAAAAMAAAAAAAAAAUVVUgAAAAAAUtYuFczBLlsXyEp3q8BbTBpEGINWahqkFbnTPd93YUUAAAAXSHboAAAAABEAACcQAAAAAAAAAKIAAAAAAAAAAcLYgCAAAABAo2tU6n0Bb7bbbpaXacVeaTVbxNMBtnrrXVk2QAOje2Flllk/ORlmQdFU/9c8z43eWh1RNMpI3PscY+yDCnJPBQ==";
let xdr =
'AAAAAPQQv+uPYrlCDnjgPyPRgIjB6T8Zb8ANmL8YGAXC2IAgAAAAZAAIteYAAAAHAAAAAAAAAAAAAAABAAAAAAAAAAMAAAAAAAAAAUVVUgAAAAAAUtYuFczBLlsXyEp3q8BbTBpEGINWahqkFbnTPd93YUUAAAAXSHboAAAAABEAACcQAAAAAAAAAKIAAAAAAAAAAcLYgCAAAABAo2tU6n0Bb7bbbpaXacVeaTVbxNMBtnrrXVk2QAOje2Flllk/ORlmQdFU/9c8z43eWh1RNMpI3PscY+yDCnJPBQ==';

var txe = StellarBase.xdr.TransactionEnvelope.fromXDR(xdr, 'base64');
expect(txe.tx().sourceAccount().value().length).to.be.equal(32)
expect(
txe
.tx()
.sourceAccount()
.value().length
).to.be.equal(32);
done();
});

it("calculates correct hash with non-utf8 strings", function() {
it('calculates correct hash with non-utf8 strings', function() {
// a84d534b3742ad89413bdbf259e02fa4c5d039123769e9bcc63616f723a2bcd5
let xdr = "AAAAAAtjwtJadppTmm0NtAU99BFxXXfzPO1N/SqR43Z8aXqXAAAAZAAIj6YAAAACAAAAAAAAAAEAAAAB0QAAAAAAAAEAAAAAAAAAAQAAAADLa6390PDAqg3qDLpshQxS+uVw3ytSgKRirQcInPWt1QAAAAAAAAAAA1Z+AAAAAAAAAAABfGl6lwAAAEBC655+8Izq54MIZrXTVF/E1ycHgQWpVcBD+LFkuOjjJd995u/7wM8sFqQqambL0/ME2FTOtxMO65B9i3eAIu4P";
let xdr =
'AAAAAAtjwtJadppTmm0NtAU99BFxXXfzPO1N/SqR43Z8aXqXAAAAZAAIj6YAAAACAAAAAAAAAAEAAAAB0QAAAAAAAAEAAAAAAAAAAQAAAADLa6390PDAqg3qDLpshQxS+uVw3ytSgKRirQcInPWt1QAAAAAAAAAAA1Z+AAAAAAAAAAABfGl6lwAAAEBC655+8Izq54MIZrXTVF/E1ycHgQWpVcBD+LFkuOjjJd995u/7wM8sFqQqambL0/ME2FTOtxMO65B9i3eAIu4P';
var tx = new StellarBase.Transaction(xdr);
StellarBase.Network.usePublicNetwork();
expect(tx.hash().toString('hex')).to.be.equal("a84d534b3742ad89413bdbf259e02fa4c5d039123769e9bcc63616f723a2bcd5");
})

expect(tx.hash().toString('hex')).to.be.equal(
'a84d534b3742ad89413bdbf259e02fa4c5d039123769e9bcc63616f723a2bcd5'
);
});
});