Skip to content

Commit

Permalink
Move MuxedAccount to a separate file and drop the `createSubaccount…
Browse files Browse the repository at this point in the history
…` method. (#487)

* Drop method signature from interface
  • Loading branch information
Shaptic authored Jan 11, 2022
1 parent 510fcd4 commit 9538dee
Show file tree
Hide file tree
Showing 5 changed files with 154 additions and 162 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,17 @@ There are several other breaking changes:

- `TransactionBuilder.enableMuxedAccounts()` is removed
- `decodeAddressToMuxedAccount()` and `encodeMuxedAccountToAddress()` no longer accept a second boolean parameter
- `Account.createSubaccount()` and `MuxedAccount.createSubaccount()` are removed ([#487](https://github.com/stellar/js-stellar-base/pull/487)). You should prefer to create them manually:

```js
let mux1 = new MuxedAccount(someAccount, '1');

// before:
let mux2 = mux1.createSubaccount('2');

// now:
let mux2 = new MuxedAccount(mux1.baseAccount(), '2');
```

## [v6.0.6](https://github.com/stellar/js-stellar-base/compare/v6.0.5..v6.0.6)

Expand Down
159 changes: 0 additions & 159 deletions src/account.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@ import isString from 'lodash/isString';
import BigNumber from 'bignumber.js';

import { StrKey } from './strkey';
import {
decodeAddressToMuxedAccount,
encodeMuxedAccountToAddress,
encodeMuxedAccount,
extractBaseAddress
} from './util/decode_encode_muxed_account';

/**
* Create a new Account object.
Expand Down Expand Up @@ -66,157 +60,4 @@ export class Account {
incrementSequenceNumber() {
this.sequence = this.sequence.add(1);
}

/**
* Creates a muxed "sub"account with this base address and an ID set.
*
* @param {string} id - the ID of the new muxed account
* @return {MuxedAccount} a new instance w/ the specified parameters
*
* @see MuxedAccount
*/
createSubaccount(id) {
return new MuxedAccount(this, id);
}
}

/**
* Represents a muxed account for transactions and operations.
*
* A muxed (or *multiplexed*) account (defined in
* [CAP-27](https://stellar.org/protocol/cap-27) and
* [SEP-23](https://stellar.org/protocol/sep-23)) is one that resolves a single
* Stellar `G...`` account to many different underlying IDs.
*
* For example, you may have a single Stellar address for accounting purposes:
* GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ
*
* Yet would like to use it for 4 different family members:
* 1: MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAGZFQ
* 2: MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAALIWQ
* 3: MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAPYHQ
* 4: MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAQLQQ
*
* This object makes it easy to create muxed accounts from regular accounts,
* duplicate them, get/set the underlying IDs, etc. without mucking around with
* the raw XDR.
*
* Because muxed accounts are purely an off-chain convention, they all share the
* sequence number tied to their underlying G... account. Thus, this object
* *requires* an {@link Account} instance to be passed in, so that muxed
* instances of an account can collectively modify the sequence number whenever
* a muxed account is used as the source of a @{link Transaction} with {@link
* TransactionBuilder}.
*
* @constructor
*
* @param {Account} account - the @{link Account} instance representing the
* underlying G... address
* @param {string} id - a stringified uint64 value that represents the
* ID of the muxed account
*
* @see https://developers.stellar.org/docs/glossary/muxed-accounts/
*/
export class MuxedAccount {
constructor(baseAccount, id) {
const accountId = baseAccount.accountId();
if (!StrKey.isValidEd25519PublicKey(accountId)) {
throw new Error('accountId is invalid');
}

this.account = baseAccount;
this._muxedXdr = encodeMuxedAccount(accountId, id);
this._mAddress = encodeMuxedAccountToAddress(this._muxedXdr);
this._id = id;
}

/**
* Parses an M-address into a MuxedAccount object.
*
* @param {string} mAddress - an M-address to transform
* @param {string} sequenceNum - the sequence number of the underlying {@link
* Account}, to use for the underlying base account (@link
* MuxedAccount.baseAccount). If you're using the SDK, you can use
* `server.loadAccount` to fetch this if you don't know it.
*
* @return {MuxedAccount}
*/
static fromAddress(mAddress, sequenceNum) {
const muxedAccount = decodeAddressToMuxedAccount(mAddress);
const gAddress = extractBaseAddress(mAddress);
const id = muxedAccount
.med25519()
.id()
.toString();

return new MuxedAccount(new Account(gAddress, sequenceNum), id);
}

/**
* @return {Account} the underlying account object shared among all muxed
* accounts with this Stellar public key (G... address)
*/
baseAccount() {
return this.account;
}

/**
* @return {string} the M-address representing this account's (G-address, ID)
*/
accountId() {
return this._mAddress;
}

id() {
return this._id;
}

setId(id) {
if (!isString(id)) {
throw new Error('id should be a string representing a number (uint64)');
}

this._muxedXdr = encodeMuxedAccount(this.account.accountId(), id);
this._mAddress = encodeMuxedAccountToAddress(this._muxedXdr);
this._id = id;
return this;
}

/**
* Accesses the underlying account's sequence number.
* @return {string} strigified sequence number for the underlying account
*/
sequenceNumber() {
return this.account.sequenceNumber();
}

/**
* Increments the underlying account's sequence number by one.
* @return {void}
*/
incrementSequenceNumber() {
return this.account.incrementSequenceNumber();
}

/**
* Creates another muxed "sub"account from the base with a new ID set
*
* @param {string} id - the ID of the new muxed account
* @return {MuxedAccount} a new instance w/ the specified parameters
*/
createSubaccount(id) {
return new MuxedAccount(this.account, id);
}

/**
* @return {xdr.MuxedAccount} the XDR object representing this muxed account's
* G-address and uint64 ID
*/
toXDRObject() {
return this._muxedXdr;
}

equals(otherMuxedAccount) {
return this.accountId() === otherMuxedAccount.accountId();
}
}
3 changes: 2 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ export {
AuthClawbackEnabledFlag
} from './operation';
export * from './memo';
export { Account, MuxedAccount } from './account';
export { Account } from './account';
export { MuxedAccount } from './muxed_account';
export { Claimant } from './claimant';
export { Networks } from './network';
export { StrKey } from './strkey';
Expand Down
142 changes: 142 additions & 0 deletions src/muxed_account.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
import isString from 'lodash/isString';

import xdr from './generated/stellar-xdr_generated';
import { Account } from './account';
import { StrKey } from './strkey';
import {
decodeAddressToMuxedAccount,
encodeMuxedAccountToAddress,
encodeMuxedAccount,
extractBaseAddress
} from './util/decode_encode_muxed_account';

/**
* Represents a muxed account for transactions and operations.
*
* A muxed (or *multiplexed*) account (defined rigorously in
* [CAP-27](https://stellar.org/protocol/cap-27) and briefly in
* [SEP-23](https://stellar.org/protocol/sep-23)) is one that resolves a single
* Stellar `G...`` account to many different underlying IDs.
*
* For example, you may have a single Stellar address for accounting purposes:
* GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ
*
* Yet would like to use it for 4 different family members:
* 1: MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAGZFQ
* 2: MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAALIWQ
* 3: MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAPYHQ
* 4: MA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJUAAAAAAAAAAAAQLQQ
*
* This object makes it easy to create muxed accounts from regular accounts,
* duplicate them, get/set the underlying IDs, etc. without mucking around with
* the raw XDR.
*
* Because muxed accounts are purely an off-chain convention, they all share the
* sequence number tied to their underlying G... account. Thus, this object
* *requires* an {@link Account} instance to be passed in, so that muxed
* instances of an account can collectively modify the sequence number whenever
* a muxed account is used as the source of a @{link Transaction} with {@link
* TransactionBuilder}.
*
* @constructor
*
* @param {Account} account - the @{link Account} instance representing the
* underlying G... address
* @param {string} id - a stringified uint64 value that represents the
* ID of the muxed account
*
* @link https://developers.stellar.org/docs/glossary/muxed-accounts/
*/
export class MuxedAccount {
constructor(baseAccount, id) {
const accountId = baseAccount.accountId();
if (!StrKey.isValidEd25519PublicKey(accountId)) {
throw new Error('accountId is invalid');
}

this.account = baseAccount;
this._muxedXdr = encodeMuxedAccount(accountId, id);
this._mAddress = encodeMuxedAccountToAddress(this._muxedXdr);
this._id = id;
}

/**
* Parses an M-address into a MuxedAccount object.
*
* @param {string} mAddress - an M-address to transform
* @param {string} sequenceNum - the sequence number of the underlying {@link
* Account}, to use for the underlying base account (@link
* MuxedAccount.baseAccount). If you're using the SDK, you can use
* `server.loadAccount` to fetch this if you don't know it.
*
* @return {MuxedAccount}
*/
static fromAddress(mAddress, sequenceNum) {
const muxedAccount = decodeAddressToMuxedAccount(mAddress);
const gAddress = extractBaseAddress(mAddress);
const id = muxedAccount
.med25519()
.id()
.toString();

return new MuxedAccount(new Account(gAddress, sequenceNum), id);
}

/**
* @return {Account} the underlying account object shared among all muxed
* accounts with this Stellar address
*/
baseAccount() {
return this.account;
}

/**
* @return {string} the M-address representing this account's (G-address, ID)
*/
accountId() {
return this._mAddress;
}

id() {
return this._id;
}

setId(id) {
if (!isString(id)) {
throw new Error('id should be a string representing a number (uint64)');
}

this._muxedXdr.med25519().id(xdr.Uint64.fromString(id));
this._mAddress = encodeMuxedAccountToAddress(this._muxedXdr);
this._id = id;
return this;
}

/**
* Accesses the underlying account's sequence number.
* @return {string} strigified sequence number for the underlying account
*/
sequenceNumber() {
return this.account.sequenceNumber();
}

/**
* Increments the underlying account's sequence number by one.
* @return {void}
*/
incrementSequenceNumber() {
return this.account.incrementSequenceNumber();
}

/**
* @return {xdr.MuxedAccount} the XDR object representing this muxed account's
* G-address and uint64 ID
*/
toXDRObject() {
return this._muxedXdr;
}

equals(otherMuxedAccount) {
return this.accountId() === otherMuxedAccount.accountId();
}
}
2 changes: 0 additions & 2 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export class Account {
accountId(): string;
sequenceNumber(): string;
incrementSequenceNumber(): void;
createSubaccount(id: string): MuxedAccount;
}

export class MuxedAccount {
Expand All @@ -22,7 +21,6 @@ export class MuxedAccount {
accountId(): string;
sequenceNumber(): string;
incrementSequenceNumber(): void;
createSubaccount(id: string): MuxedAccount;

baseAccount(): Account;
id(): string;
Expand Down

0 comments on commit 9538dee

Please sign in to comment.