Sirius Chain Developer Center 0.2.6

Sirius Chain Developer Center 0.2.6

  • Getting Started
  • Built-in Features
  • REST API Endpoints
  • Guides
  • Cheat Sheet

›Multisig Account

Account

  • Creating and opening an account
  • Getting account information
  • Getting the amount of XPX sent to an account
  • Reading transactions from an account

Account Restriction

  • Preventing spam attacks with account restrictions

Aggregate Transaction

  • Sending payouts with aggregate-complete transaction
  • Creating an escrow with aggregate bonded transaction
  • Asking for mosaics with aggregate-bonded transaction
  • Signing announced aggregate-bonded transactions

Block

  • Listening New Blocks
  • Getting block by height

Cross Chain Swaps

  • Atomic cross-chain swap between Sirius public and private chains

Metadata

  • Account Metadata
  • Mosaic Metadata
  • Namespace Metadata

Monitoring

  • Monitor transaction

Mosaic

  • Creating a mosaic
  • Getting the mosaic information
  • Getting the asset identifier behind a namespace with receipts
  • Modifying Mosaic Supply

Multisig Account

  • Converting an account to multisig
  • Modifying a multisig account
  • Creating a multi-level multisig-account
  • Sending a multisig transaction

Namespace

  • Registering a namespace
  • Registering a subnamespace
  • Getting the Namespace information
  • Linking a namespace to a mosaic
  • Linking namespace to account

Transfer Transaction

  • Transfer transaction
  • Sending an encrypted message

Modifying a multisig account

Modify an existing multisig account.

First, you are going to turn a 1-of-2 multisig account into a 2-of-2. Then, you will add a new cosignatory, becoming a 2-of-3. Finally, after removing a cosignatory, you will know how to perform all sort of modifications to multisig accounts.

Prerequisites

  • Text editor or IDE
  • XPX-Chain-SDK or XPX-Chain-CLI
  • Finish converting an account to multisig guide
  • Have on emultisignature account

Getting into some code

Editing minApproval

Alice and Bob are cosignatories of the 1-of-2 multisig account. This means that at least one of their account’s signatures is required to authorize multisig transactions. In other words, we can say that the minApproval parameter of the multisig is currently set to 1.

Multisig accounts are editable at the blockchain level. In this case, we want to make both cosignatories required, shifting to a 2-of-2 multisig instead. You can achieve this by increasing minApproval parameter in one unit.

Multisig 2 of 2

2-of-2 multisig account example

One of the accounts, for example Alice’s, will announce a modify multisig account transaction to increase minApprovalDelta.

  1. First, define Alice account as the cosignatory and the multisig account using its public key.
Golang
TypeScript
JavaScript
Java
conf, err := sdk.NewConfig(context.Background(), []string{"http://localhost:3000"})
if err != nil {
panic(err)
}

// Use the default http client
client := sdk.NewClient(nil, conf)

multisig, err := client.NewAccountFromPublicKey(os.Getenv("MULTISIG_ACCOUNT_PUBLIC_KEY"))
if err != nil {
panic(err)
}

cosignatory, err := client.NewAccountFromPrivateKey(os.Getenv("COSIGNATORY_PRIVATE_KEY"))
if err != nil {
panic(err)
}
const transactionHttp = new TransactionHttp('http://localhost:3000');

const cosignatoryPrivateKey = "<cosignatoryPrivateKey>";
const cosignatoryAccount = Account.createFromPrivateKey(cosignatoryPrivateKey, NetworkType.TEST_NET);

const multisigAccountPublicKey = "<multisigPublicKey>";
const multisigAccount = PublicAccount.createFromPublicKey(multisigAccountPublicKey, NetworkType.TEST_NET);
const transactionHttp = new TransactionHttp('http://localhost:3000');

const cosignatoryPrivateKey = "<cosignatoryPrivateKey>";
const cosignatoryAccount = Account.createFromPrivateKey(cosignatoryPrivateKey, NetworkType.TEST_NET);

const multisigAccountPublicKey = "<multisigPublicKey>";
const multisigAccount = PublicAccount.createFromPublicKey(multisigAccountPublicKey, NetworkType.TEST_NET);
    final TransactionHttp transactionHttp = new TransactionHttp("http://localhost:3000");

final String cosignatoryPrivateKey = "<cosignatoryPrivateKey>";
final String multisigAccountPublicKey = "<multisigPublicKey>";

final Account cosignatoryAccount = Account.createFromPrivateKey(cosignatoryPrivateKey, NetworkType.TEST_NET);
final PublicAccount multisigAccount = PublicAccount.createFromPublicKey(multisigAccountPublicKey, NetworkType.TEST_NET);
  1. Define a modify multisig account transaction to increase the minAprovalDelta in one unit.
Golang
TypeScript
JavaScript
Java
modifyMultisigAccountTransaction, err := client.NewModifyMultisigAccountTransaction(
sdk.NewDeadline(time.Hour),
1,
0,
[]*sdk.MultisigCosignatoryModification{ },
)
if err != nil {
panic(err)
}
const modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(),
1, // min to Approve
0, // min to remove cosignatory
[],
NetworkType.TEST_NET);
const modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(),
1, // min to Approve
0, // min to remove cosignatory
[],
NetworkType.TEST_NET);
 final ModifyMultisigAccountTransaction modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(2, HOURS),
1, // min to Approve
0, // min to remove cosignatory
Collections.emptyList(),
NetworkType.TEST_NET
);
  1. Wrap the modify multisig account transaction in an aggregate transaction, attaching the multisig public key as the signer.

An aggregate transaction is complete if, before announcing it to the network, all required cosignatories have signed it. If valid, it will be included in a block.

As only one cosignature is required (1-of-2), Alice can sign the transaction and announce it to the network.

Golang
TypeScript
JavaScript
Java
modifyMultisigAccountTransaction.ToAggregate(multisig)

aggregateTransaction, err := client.NewCompleteAggregateTransaction(sdk.NewDeadline(time.Hour), []sdk.Transaction{modifyMultisigAccountTransaction})
if err != nil {
panic(err)
}

signedTransaction, err := cosignatory.Sign(aggregateTransaction)
if err != nil {
panic(err)
}

_, err = client.Transaction.Announce(context.Background(), signedTransaction)
if err != nil {
panic(err)
}
const aggregateTransaction = AggregateTransaction.createComplete(
Deadline.create(),
[modifyMultisigAccountTransaction.toAggregate(multisigAccount)],
NetworkType.TEST_NET,
[]);

const signedTransaction = cosignatoryAccount.sign(aggregateTransaction, generationHash);

transactionHttp
.announce(signedTransaction)
.subscribe(x => console.log(x), err => console.error(err));
const aggregateTransaction = AggregateTransaction.createComplete(
Deadline.create(),
[modifyMultisigAccountTransaction.toAggregate(multisigAccount)],
NetworkType.TEST_NET,
[]);

const signedTransaction = cosignatoryAccount.sign(aggregateTransaction, generationHash);

transactionHttp
.announce(signedTransaction)
.subscribe(x => console.log(x), err => console.error(err));
    final AggregateTransaction aggregateTransaction = new TransactionBuilderFactory().aggregateComplete()
.innerTransactions(Arrays.asList(
modifyMultisigAccountTransaction.toAggregate(multisigAccount)
)).deadline(new Deadline(2, ChronoUnit.HOURS)).networkType(NetworkType.TEST_NET);

final SignedTransaction signedTransaction = cosignatoryAccount.sign(aggregateTransaction, generationHash);

transactionHttp.announce(signedTransaction).toFuture().get();

Once confirmed, the minApproval value of the multisig will be set to 2, having our 2-of-2 multisig.

Note:

If you want to decrease the minApproval parameter, set minApprovalDelta with a negative value. In this case -1.

Adding a new cosignatory

Alice and Bob want to add Carol as a cosignatory of the multisig account to achieve 2-of-3 cosignatures required.

Multisig 2 of 3

2-of-3 multisig account example

  1. Create a modify multisig account transaction adding Carol as a cosignatory. The multisig account will become a 2-of-3, since you are not increasing the minApprovalDelta.
Golang
TypeScript
JavaScript
Java
conf, err := sdk.NewConfig(context.Background(), []string{"http://localhost:3000"})
if err != nil {
panic(err)
}

// Use the default http client
client := sdk.NewClient(nil, conf)


multisig, err := client.NewAccountFromPublicKey(os.Getenv("MULTISIG_ACCOUNT_PUBLIC_KEY"))
if err != nil {
panic(err)
}

cosignatory, err := client.NewAccountFromPrivateKey(os.Getenv("COSIGNATORY_PRIVATE_KEY"))
if err != nil {
panic(err)
}

newCosignatory, err := client.NewAccountFromPrivateKey(os.Getenv("NEW_COSIGNATORY_PRIVATE_KEY"))
if err != nil {
panic(err)
}

multisigCosignatoryModification := sdk.MultisigCosignatoryModification{sdk.Add, newCosignatory.PublicAccount}
const nodeUrl = 'http://localhost:3000';
const transactionHttp = new TransactionHttp(nodeUrl);
const listener = new Listener(nodeUrl);

const cosignatoryPrivateKey = "<cosignatoryPrivateKey>";
const cosignatoryAccount = Account.createFromPrivateKey(cosignatoryPrivateKey, NetworkType.TEST_NET);

const multisigAccountPublicKey = "<multisigPublicKey>";
const multisigAccount = PublicAccount.createFromPublicKey(multisigAccountPublicKey, NetworkType.TEST_NET);

const newCosignatoryPublicKey = "<newCosignatoryPublicKey>";
const newCosignatoryAccount = PublicAccount.createFromPublicKey(newCosignatoryPublicKey, NetworkType.TEST_NET);

const multisigCosignatoryModification = new MultisigCosignatoryModification(MultisigCosignatoryModificationType.Add,newCosignatoryAccount);
const nodeUrl = 'http://localhost:3000';
const transactionHttp = new TransactionHttp(nodeUrl);
const listener = new Listener(nodeUrl);

const cosignatoryPrivateKey = "<cosignatoryPrivateKey>";
const cosignatoryAccount = Account.createFromPrivateKey(cosignatoryPrivateKey, NetworkType.TEST_NET);

const multisigAccountPublicKey = "<multisigPublicKey>";
const multisigAccount = PublicAccount.createFromPublicKey(multisigAccountPublicKey, NetworkType.TEST_NET);

const newCosignatoryPublicKey = "<newCosignatoryPublicKey>";
const newCosignatoryAccount = PublicAccount.createFromPublicKey(newCosignatoryPublicKey, NetworkType.TEST_NET);

const multisigCosignatoryModification = new MultisigCosignatoryModification(MultisigCosignatoryModificationType.Add,newCosignatoryAccount);
    // Replace with the multisig public key
final String cosignatoryPrivateKey = "<cosignatoryPrivateKey>";
final String multisigAccountPublicKey = "<multisigPublicKey>";
final String newCosignatoryPublicKey = "<newCosignatoryPublicKey>";

final Account cosignatoryAccount = Account.createFromPrivateKey(cosignatoryPrivateKey, NetworkType.TEST_NET);
final PublicAccount newCosignatoryAccount = PublicAccount.createFromPublicKey(newCosignatoryPublicKey, NetworkType.TEST_NET);
final PublicAccount multisigAccount = PublicAccount.createFromPublicKey(multisigAccountPublicKey, NetworkType.TEST_NET);

final MultisigCosignatoryModification multisigCosignatoryModification = new MultisigCosignatoryModification(
MultisigCosignatoryModificationType.ADD,
newCosignatoryAccount
);
  1. Create a modify multisig account transaction adding the previous modification.
Golang
TypeScript
JavaScript
Java
modifyMultisigTransaction, err := client.NewModifyMultisigAccountTransaction(
sdk.NewDeadline(time.Hour),
0,
0,
[]*sdk.MultisigCosignatoryModification{
&multisigCosignatoryModification,
},
)
if err != nil {
panic(err)
}
const modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(),
0,
0,
[multisigCosignatoryModification],
NetworkType.TEST_NET);
const modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(),
0,
0,
[multisigCosignatoryModification],
NetworkType.TEST_NET);
    final ModifyMultisigAccountTransaction modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(2, HOURS),
0,
0,
Collections.singletonList(multisigCosignatoryModification),
NetworkType.TEST_NET
);
  1. Wrap the modify multisig account transaction in an aggregate bonded transaction and sign it.
Golang
TypeScript
JavaScript
Java
modifyMultisigTransaction.ToAggregate(multisig)

aggregateTransaction, err := client.NewBondedAggregateTransaction(sdk.NewDeadline(time.Hour), []sdk.Transaction{modifyMultisigTransaction})
if err != nil {
panic(err)
}

signedAggregateTransaction, err := cosignatory.Sign(aggregateTransaction)
if err != nil {
panic(err)
}
const aggregateTransaction = AggregateTransaction.createBonded(
Deadline.create(),
[modifyMultisigAccountTransaction.toAggregate(multisigAccount)],
NetworkType.TEST_NET);

const signedTransaction = cosignatoryAccount.sign(aggregateTransaction);
const aggregateTransaction = AggregateTransaction.createBonded(
Deadline.create(),
[modifyMultisigAccountTransaction.toAggregate(multisigAccount)],
NetworkType.TEST_NET);

const signedTransaction = cosignatoryAccount.sign(aggregateTransaction);
    final AggregateTransaction aggregateTransaction = new TransactionBuilderFactory().aggregateBonded()
.innerTransactions(Arrays.asList(
modifyMultisigAccountTransaction.toAggregate(multisigAccount)
)).deadline(new Deadline(2, ChronoUnit.HOURS)).networkType(NetworkType.TEST_NET);

final SignedTransaction signedTransaction = cosignatoryAccount.sign(aggregateTransaction);
  1. Before sending an aggregate bonded transaction, Alice needs to lock at least 10 xpx. This transaction is required to prevent network spamming and ensure that transactions are cosigned. After the hash lock transaction has been confirmed, announce the aggregate transaction.
Golang
TypeScript
JavaScript
Java
lockFundsTransaction, err := client.NewLockFundsTransaction(
sdk.NewDeadline(time.Hour),
sdk.XpxRelative(10),
sdk.Duration(1000),
signedAggregateTransaction,
)
if err != nil {
panic(err)
}

signedLockFundsTransaction, err := cosignatory.Sign(lockFundsTransaction)
if err != nil {
panic(err)
}

_, err = client.Transaction.Announce(context.Background(), signedLockFundsTransaction)
if err != nil {
panic(err)
}
const lockFundsTransaction = LockFundsTransaction.create(
Deadline.create(),
NetworkCurrencyMosaic.createRelative(10),
UInt64.fromUint(1000),
signedTransaction,
NetworkType.TEST_NET);

const lockFundsTransactionSigned = cosignatoryAccount.sign(lockFundsTransaction);

listener.open().then(() => {

transactionHttp
.announce(lockFundsTransactionSigned)
.subscribe(x => console.log(x), err => console.error(err));

listener
.confirmed(cosignatoryAccount.address)
.pipe(
filter((transaction) => transaction.transactionInfo !== undefined
&& transaction.transactionInfo.hash === lockFundsTransactionSigned.hash),
mergeMap(ignored => transactionHttp.announceAggregateBonded(signedTransaction))
)
.subscribe(announcedAggregateBonded => console.log(announcedAggregateBonded),
err => console.error(err));
});
const lockFundsTransaction = LockFundsTransaction.create(
Deadline.create(),
NetworkCurrencyMosaic.createRelative(10),
UInt64.fromUint(1000),
signedTransaction,
NetworkType.TEST_NET);

const lockFundsTransactionSigned = cosignatoryAccount.sign(lockFundsTransaction);

listener.open().then(() => {

transactionHttp
.announce(lockFundsTransactionSigned)
.subscribe(x => console.log(x), err => console.error(err));

listener
.confirmed(cosignatoryAccount.address)
.pipe(
filter((transaction) => transaction.transactionInfo !== undefined
&& transaction.transactionInfo.hash === lockFundsTransactionSigned.hash),
mergeMap(ignored => transactionHttp.announceAggregateBonded(signedTransaction))
)
.subscribe(announcedAggregateBonded => console.log(announcedAggregateBonded),
err => console.error(err));
});
    final LockFundsTransaction lockFundsTransaction = LockFundsTransaction.create(
Deadline.create(2, HOURS),
NetworkCurrencyMosaic.createRelative(BigInteger.valueOf(10)),
BigInteger.valueOf(1000),
signedTransaction,
NetworkType.TEST_NET
);

final SignedTransaction lockFundsTransactionSigned = cosignatoryAccount.sign(lockFundsTransaction);

final TransactionHttp transactionHttp = new TransactionHttp("http://localhost:3000");

transactionHttp.announce(lockFundsTransactionSigned).toFuture().get();

final Listener listener = new Listener("http://localhost:3000");

listener.open().get();

// listen to confirmed transaction which is the LockFundsTransaction in this case
final Transaction transaction = listener.confirmed(cosignatoryAccount.getAddress()).toFuture().get();

// announce signed transaction
transactionHttp.announceAggregateBonded(signedTransaction).toFuture().get();
  1. Cosign the aggregate transaction hash with Carols’s account. She has to opt-in to become a multisig cosignatory.
CLI
xpx2-cli transaction cosign --hash A6A374E66B32A3D5133018EFA9CD6E3169C8EEA339F7CCBE29C47D07086E068C --profile carol
  1. Cosign the aggregate transaction with Bob’s account. The amount of xpx locked becomes available again on Alice’s account and Carol is added to the multisig.
CLI
xpx2-cli transaction cosign --hash A6A374E66B32A3D5133018EFA9CD6E3169C8EEA339F7CCBE29C47D07086E068C --profile bob

Removing a cosignatory

Once you have finished this guide, delete a cosignatory from the multisig. Multisig accounts can be converted again into regular accounts by removing all cosignatories. Make sure you own the multisig private key!

The following code shows how to remove a cosignatory of a 2-of-3 multisig account with minRemoval set to 1. The multisig modification transaction is wrapped in an aggregate complete, as only one account is required to delete others from the multisig.

Note:

The minRemoval parameter indicates the number of required signatures to delete an account from the multisig. You can increase or decrease it the same way you modify minApproval parameter.

Golang
TypeScript
JavaScript
Java
conf, err := sdk.NewConfig(context.Background(), []string{"http://localhost:3000"})
if err != nil {
panic(err)
}

// Use the default http client
client := sdk.NewClient(nil, conf)

multisig, err := client.NewAccountFromPublicKey(os.Getenv("MULTISIG_ACCOUNT_PUBLIC_KEY"))
if err != nil {
panic(err)
}

cosignatory, err := client.NewAccountFromPrivateKey(os.Getenv("COSIGNATORY_PRIVATE_KEY"))
if err != nil {
panic(err)
}

cosignatoryToRemove, err := client.NewAccountFromPublicKey(os.Getenv("COSIGNATORY_PUBLIC_KEY"))
if err != nil {
panic(err)
}

multisigCosignatoryModification := sdk.MultisigCosignatoryModification{sdk.Remove, cosignatoryToRemove}

modifyMultisigAccountTransaction, err := client.NewModifyMultisigAccountTransaction(
sdk.NewDeadline(time.Hour),
0,
0,
[]*sdk.MultisigCosignatoryModification{ &multisigCosignatoryModification },
)
if err != nil {
panic(err)
}
modifyMultisigAccountTransaction.ToAggregate(multisig)

aggregateTransaction, err := client.NewCompleteAggregateTransaction(sdk.NewDeadline(time.Hour), []sdk.Transaction{modifyMultisigAccountTransaction})
if err != nil {
panic(err)
}

signedTransaction, err := cosignatory.Sign(aggregateTransaction)
if err != nil {
panic(err)
}

_, err = client.Transaction.Announce(context.Background(), signedTransaction)
if err != nil {
panic(err)
}
const transactionHttp = new TransactionHttp('http://localhost:3000');

const multisigAccountPublicKey = "<multisigPublicKey>";
const multisigAccount = PublicAccount.createFromPublicKey(multisigAccountPublicKey, NetworkType.TEST_NET);

const cosignatoryToRemovePublicKey = "<cosignatoryToRemovePublicKey>";
const cosignatoryToRemove = PublicAccount.createFromPublicKey(cosignatoryToRemovePublicKey, NetworkType.TEST_NET);

const cosignatoryPrivateKey = "<cosignatoryPrivateKey>";;
const cosignatoryAccount = Account.createFromPrivateKey(cosignatoryPrivateKey, NetworkType.TEST_NET);

const multisigCosignatoryModification = new MultisigCosignatoryModification(MultisigCosignatoryModificationType.Remove,cosignatoryToRemove);

const modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(),
0,
0,
[multisigCosignatoryModification],
NetworkType.TEST_NET);

const aggregateTransaction = AggregateTransaction.createComplete(
Deadline.create(),
[modifyMultisigAccountTransaction.toAggregate(multisigAccount)],
NetworkType.TEST_NET,
[]);

const signedTransaction = cosignatoryAccount.sign(aggregateTransaction, generationHash);

transactionHttp.announce(signedTransaction)
.subscribe(x => console.log(x), err => console.error(err));
const transactionHttp = new TransactionHttp('http://localhost:3000');

const multisigAccountPublicKey = "<multisigPublicKey>";
const multisigAccount = PublicAccount.createFromPublicKey(multisigAccountPublicKey, NetworkType.TEST_NET);

const cosignatoryToRemovePublicKey = "<cosignatoryToRemovePublicKey>";
const cosignatoryToRemove = PublicAccount.createFromPublicKey(cosignatoryToRemovePublicKey, NetworkType.TEST_NET);

const cosignatoryPrivateKey = "<cosignatoryPrivateKey>";
const cosignatoryAccount = Account.createFromPrivateKey(cosignatoryPrivateKey, NetworkType.TEST_NET);

const multisigCosignatoryModification = new MultisigCosignatoryModification(MultisigCosignatoryModificationType.Remove,cosignatoryToRemove);

const modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(),
0,
0,
[multisigCosignatoryModification],
NetworkType.TEST_NET);

const aggregateTransaction = AggregateTransaction.createComplete(
Deadline.create(),
[modifyMultisigAccountTransaction.toAggregate(multisigAccount)],
NetworkType.TEST_NET,
[]);

const signedTransaction = cosignatoryAccount.sign(aggregateTransaction, generationHash);

transactionHttp
.announce(signedTransaction)
.subscribe(x => console.log(x), err => console.error(err));
    // Replace with the multisig public key
final String multisigAccountPublicKey = "<multisigPublicKey>";;

// Replace with the cosignatory private key
final String cosignatoryPrivateKey = "<cosignatoryPrivateKey>";

final Account cosignatoryAccount = Account.createFromPrivateKey(cosignatoryPrivateKey, NetworkType.TEST_NET);
final PublicAccount multisigPublicAccount = PublicAccount.createFromPublicKey(multisigAccountPublicKey, NetworkType.TEST_NET);

final MultisigCosignatoryModification multisigCosignatoryModification = new MultisigCosignatoryModification(
MultisigCosignatoryModificationType.REMOVE,
PublicAccount.createFromPublicKey("<cosignatoryToRemovePublicKey>", NetworkType.TEST_NET)
);

final ModifyMultisigAccountTransaction modifyMultisigAccountTransaction = ModifyMultisigAccountTransaction.create(
Deadline.create(2, HOURS),
0,
0,
Collections.singletonList(multisigCosignatoryModification),
NetworkType.TEST_NET
);

final AggregateTransaction aggregateTransaction = new TransactionBuilderFactory().aggregateComplete()
.innerTransactions(Arrays.asList(
modifyMultisigAccountTransaction.toAggregate(multisigPublicAccount)
)).deadline(new Deadline(2, ChronoUnit.HOURS)).networkType(NetworkType.TEST_NET);

final SignedTransaction signedTransaction = cosignatoryAccount.sign(aggregateTransaction, generationHash);

final TransactionHttp transactionHttp = new TransactionHttp("http://localhost:3000");

transactionHttp.announce(signedTransaction).toFuture().get();

What’s next?

Learn more about multi-level multisig accounts.

← Converting an account to multisigCreating a multi-level multisig-account →
  • Prerequisites
  • Getting into some code
    • Editing minApproval
    • Adding a new cosignatory
    • Removing a cosignatory
  • What’s next?
  • Join #general discussion
  • Ask development questions
  • Follow the dev updates
  • Explore Github
Protocol
BlockConsensus AlgorithmsCryptographyInflationNodeReceiptTransactionValidating
Built-in Features
AccountAccount FilterAggregate TransactionCross-Chain SwapsExchange MarketMetadataMosaicMultisig AccountNamespaceSuper contractTransfer Transaction
References
REST APISDKsXPX-Chain-CLICheat Sheet
Documentation Forked From NEM
Copyright © 2020 ProximaX