0.1.5 • Published 11 months ago

mitum-sdk v0.1.5

Weekly downloads
-
License
GPL-3.0-or-later
Repository
github
Last release
11 months ago

mitum-sdk

mitum-sdk is Javascript SDK that helps create operations for mitum models.

  • Mitum Currency
  • Mitum Currency Extension

Installation

This project has been developed in the following environments:

$ node --version
v19.8.1

$ npm --version
9.5.1

You can install this package locally using this command:

$ npm i

You can install mitum-sdk using this command:

$ npm i mitum-sdk

Test

Before testing, check TEST_ID, TEST_NODE, TEST_GENESIS, TEST_ACCOUNT, and etc in esm/mitum.config.js or csj/mitum.config.js.

You can test mitum-sdk using this command:

$ npm test

> mitum-sdk@0.1.0 test
> jest

 PASS  ...
 PASS  ...
 ...
 PASS  ...

Test Suites: 42 passed, 42 total
Tests:       123 passed, 123 total
Snapshots:   0 total
Time:        3.995 s, estimated 4 s
Ran all test suites.

Index

Title
1Generate KeyPairs
-Random KeyPair
-From private key
-From seed
2Get address from public keys
3Generate currency operations
-create-account
-key-updater
-transfer
-currency-register
-currency-policy-updater
-suffrage-inflation
-create-contract-account
-withdraw
4Generate seal
5Add sign to operation json
+Appendix
+License

To set the mitum version of all hints and the network id, refer to Set version of hints and Set network id of operations.

Generate KeyPairs

mitum-sdk supports two signature methods:

  • mitum1: m1 (btc)
  • mitum2: m2 (btc, ether)

You can generate key pairs in the following ways:

  • Generate a random KeyPair
  • Generate a KeyPair from a private key
  • Generate a KeyPair from a seed

  • btc private key: keympr

  • btc public key: keympu

  • ether private key: keyepr

  • ether public key: keyepu

The following functions are prepared for key pair generation.

import { KPGen } from "mitum-sdk";

// m1 btc key pair
var ekp1 = KPGen.random();
var ekp2 = KPGen.randomN(/* the number of keypairs */);
var ekp3 = KPGen.fromPrivateKey(/* string private key */);
var ekp4 = KPGen.fromSeed(/* string seed */);

// m2 btc key pair
const { m2 } = KPGen;
var skp1 = m2.random();
var skp2 = m2.randomN(/* the number of keypairs */);
var skp3 = m2.fromPrivateKey(/* string private key */);
var skp4 = m2.fromSeed(/* string seed */);

// m2 ether key pair
const { m2ether } = KPGen;
var ukp1 = m2ether.random();
var ukp2 = m2ether.randomN(/* the number of keypairs */);
var ukp3 = m2ether.fromPrivateKey(/* string private key */);
var ukp4 = m2ether.fromSeed(/* string seed */);

If you need a key pair for m2 and m2-ether signatures, use KPGen.m2.(function) and KPGen.m2ether.(function) instead of KPGen.(function).

Random KeyPair

Get a random KeyPair

import { KPGen } from "mitum-sdk";

const keypair = KPGen.random(); // KeyPair instance

const priv = keypair.privateKey; // Key instance
const pub = keypair.publicKey; // Key instance

const priveStr = priv.toString(); // KwSKzHfNFKELkWs5gqbif1BqQhQjGhruKubqqU7AeKu5JPR36vKrmpr
const pubStr = pub.toString(); // 22PVZv7Cizt7T2VUkL4QuR7pmfrprMqnFDEXFkDuJdWhSmpu

Get N random KeyPairs with an address

import { KPGen } from "mitum-sdk";

const n = 5

// keys: Keys[Keys] instance; with 5 MKey(pub, weight) and threshold
// keypairs: Array; 5 KeyPair(priv, pub)
const { keys, keypairs } = KPGen.randomN(5);

const address = keys.address // Address instance

From private key

import { KPGen } from "mitum-sdk";

const keypair = KPGen.fromPrivateKey("KwkuLfcHsxY3yGLT2wYWNgbuGD3Q1j3c7DJvaRLfmT8ujmayJUaJmpr"); // KeyPair instance

const priv = keypair.privateKey; // Key instance
const pub = keypair.publicKey; // Key instance

const priveStr = priv.toString(); // KwkuLfcHsxY3yGLT2wYWNgbuGD3Q1j3c7DJvaRLfmT8ujmayJUaJmpr
const pubStr = pub.toString(); // r3W57ffVSjnyMFQ6132ZoPj1jnbFhoSFCnDYYRq2tXQVmpu

From seed

The seed string length must be at least 36.

import { KPGen } from "mitum-sdk";

const keypair = KPGen.fromSeed("Hello, world! ㅍㅅㅍ~ Hello, world! ㅍㅅㅍ~"); // KeyPair instance

const priv = keypair.privateKey; // Key instance
const pub = keypair.publicKey; // Key instance

const priveStr = priv.toString(); // L1BpsqZVzgMhkVCCvR1pyFLHNxBPYi5758uFzPdeLpjejfLxzd7Xmpr
const pubStr = pub.toString(); // j3XadE7SLSDS5B7hgTrXmAvZBGWE38WDNyLQKWxn6N96mpu

Get address from public keys

Each general account in Mitum Currency consists of the following elements:

  • public keys
  • weights: each weight is paired with a public key
  • threshold
  • address

The address is calculated based on the account's public keys, weights, and threshold.

In the case of a multi-sig account, the sum of the weights of all public keys that signed the operation must be greater than or equal to the threshold. Otherwise, the operation will not be processed.

Each weight and threshold range is 0 < weight, threshold <= 100. An account can have up to 10 public keys.

To obtain an address from public keys, you must use the following classes:

import { PubKey, Keys } from "mitum-sdk";

var pub = new PubKey(/* public key; string */, /* weight; number */);
var keys = new Keys(/* pub keys; PubKey Array */, /* threshold; number */);
var address = keys.address.toString(); // btc
var etherAddress = keys.etherAddress.toString(); // ether

Let's do the following as an example.

  • 5 public keys
  • each weight: 20
  • threshold: 60

Since 20 * 3 = 60, you must sign the operation with at least three keys when using this account to transfer the operation.

import { PubKey, Keys } from "mitum-sdk";

const pubs = [
  	{
    	weight: 20,
		key: "23RWZ9McmTt5EpPYdLBeGYDn7nwyEB6qiPdU8DMjZ3dnkmpu",
	},
	{
		weight: 20,
		key: "vcsQ2fYSU5YVW5zRtpACXSLHtppkjCUo3tJ5witmAyZPmpu",
	},
	{
		weight: 20,
		key: "23jEC2vNwdfJn7PAKcFjy5CTVmELWdiAm6ZENEMr62cnsmpu",
	},
	{
		weight: 20,
		key: "282UNbzEAZQf3GdWJRPUrSaHWF88u297WTQbxfkytpcTsmpu",
	},
	{
	  	weight: 20,
		key: "bkPHGdsHSzRGe3NZ2hkzTSPyJx42BRaXetzy1bgBmbaAmpu",
	},
];
const threshold = 60;

const mpubs = pubs.map(pub => new PubKey(pub.key, pub.weight));
const mkeys = new Keys(mpubs, threshold); // Keys[Keys] instance

const address = mkeys.address; // (btc) Address instance
const stringAddress = address.toString(); // btc type string address

const etherAddress = mkeys.etherAddress; // (ether) Address instance
const etherStringAddress = etherAddress.toString(); // ether type string address

Generate Currency Operations

Mitum Currency can handle a total of six operations.

You can use this package to create the following operations:

For general accounts:

  • create-account
  • key-updater
  • transfer

For contract accounts:

  • create-contract-account
  • withdraw

For node:

  • currency-register
  • currency-policy-updater
  • suffrage-inflation

See Appendix for other instructions on how to use Operation.

If you are wondering how to enter the memo field when creating an operation, please refer to part, Is memo essential for operation generation?.

create-account

create-account is an operation to create a new general account.

The rules for account creation are as described in 2. Get address from public keys.

First, suppose you create an account with the following settings:

  • 5 public keys
  • each weight: 20
  • threshold: 100
  • initial balance: 1000 MCC, 500 PEN
import { TimeStamp, KPGen, Amount, Currency, Operation } from "mitum-sdk";

// create 5 new public keys
const { keys, keypairs } = KPGen.randomN(5);

const mccAmount = new Amount("MCC", "1000");
const penAmount = new Amount("PEN", "500");

const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";

const item = new Currency.CreateAccountsItem(keys, [mccAmount, penAmount]);
const fact = new Currency.CreateAccountsFact(token, senderAddress, [item]);

const operation = new Operation(fact);
operation.sign(senderPrivate);

// see appendix
// operation.export(/* file path; string */);
// operation.request(/* digest api address; string */, /* headers; obj */);

KPGen.randomN(n) and KPGen.m2.randomN(n) always return Keys with a threshold 100.

To generate Keys with thresholds and weights, use PubKey and Keys as follows:

import { /* KPGen, */ PubKey, Keys, Currency } from "mitum-sdk";

// const randomPub = KPGen.random().publicKey.toString();

const pub1 = "your public key1";
const pub2 = "your public key2";
...

const key1 = new PubKey(pub1, /* weight; number */);
const key2 = new PubKey(pub2, /* weight; number */);
...

const keys = new Keys([key1, key2, ...], /* threshold; number */)

const item = new Currency.CreateAccountsItem(keys, /* amounts; Amount Array */);

The example above is for mitum1.

When creating an item for sending to mitum2, you must specify the address-type as follows.

If you are creating an item for mitum1, put emtpy string in the address-type or leave it blank at all.

import { ..., Currency, ADDRESS_TYPE } from "mitum-sdk";

const m1Item = new Currency.CreateAccountsItem(keys, [mccAmount, penAmount]); // m1 btc type account
// const m1Item = new Currency.CreateAccountsItem(keys, [mccAmount, penAmount], '');
// const m1Item = new Currency.CreateAccountsItem(keys, [mccAmount, penAmount], null);

const m2Item = new Currency.CreateAccountsItem(keys, [mccAmount, penAmount], ADDRESS_TYPE.btc); // m2 btc type account
const m2etherItem = new Currency.CreateAccountsItem(keys, [mccAmount, penAmount], ADDRESS_TYPE.ether); // m2 ether type account

key-updater

key-updater is an operation to replace keys from an existing regular account with other keys.

See 2. Get address from public keys for rules for the new key set.

First, suppose you add a new key to your account as follows:

  • currency account keys: only 1 key (weight: 100; threshold: 100)
  • account keys after updating: 2 key (one is old, one is new; each weight: 50, threshold: 100)
  • currency to pay the fee: MCC
import { TimeStamp, PubKey, Keys, Currency, Operation } from "mitum-sdk";

const pub1 = "22PVZv7Cizt7T2VUkL4QuR7pmfrprMqnFDEXFkDuJdWhSmpu"; // new pub1
const pub2 = "yX3YBvu597eNgwuuJpsnZunZcDkABVeqfmiyveKuNregmpu"; // new pub2
const keys = [new PubKey(pub1, 50), new PubKey(pub2, 50)];

const token = new TimeStamp().UTC(); // any unique string
const targetAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const targetPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";

const fact = new Currency.KeyUpdaterFact(token, targetAddress, new Keys(keys, 100), "MCC");

const operation = new Operation(fact);
operation.sign(targetPrivate);

transfer

transfer is an operation to transfer tokens to another account.

For each type of token(aka. currency id), a fee based on the token policy is withdrawn together.

Suppose you transfer tokens to a general account as follows:

  • receiver: 8iRVFAPiHKaeznfN3CmNjtFtjYSPMPKLuL6qkaJz8RLumca
  • tokens to transfer: 1000 MCC, 100 PEN
import { TimeStamp, Amount, Currency, Operation } from "mitum-sdk";

const receiver = "8iRVFAPiHKaeznfN3CmNjtFtjYSPMPKLuL6qkaJz8RLumca";
const mccAmount = new Amount("MCC", "1000");
const penAmount = new Amount("PEN", "100");

const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";

const item = new Currency.TransfersItem(receiver, [mccAmount, penAmount]);
const fact = new Currency.TransfersFact(token, senderAddress, [item]);

const operation = new Operation(fact);
operation.sign(senderPrivate);

currency-register

current-register is the operation to register the currency id and policy of the new token.

When registering a new token, you can choose one of the fee policies:

  • nil (no fee)
  • fixed (fixed fee)
  • ratio (proportional fee)

(1) Feeer

First, you need to create a feeer that contains the contents of each fee policy.

import { Currency } from "mitum-sdk";

const feeReceiver = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca"; // receiver address to receive fees;

/* nil */
const nilFeeer = new Currency.NilFeeer();

/* fixed */
const fee = "10";
const fixedFeeer = new Currency.FixedFeeer(feeReceiver, fee);

/* ration */
const feeRatio = 0.5; // 0 <= fee ratio <= 1; float
const minFee = "1"; // minimum fee
const maxFee = "10000"; // maximum fee
const ratioFeeer = new Currency.RatioFeeer(feeReceiver, feeRatio , minFee, maxFee);

(2) Operation

Then, create an operation.

import { TimeStamp, Amount, Currency, Operation, SIG_TYPE } from "mitum-sdk";

// creating feeer
// ...
// done!

const currency = "MCC"; // currency id to register
const minBalance = "33"; // new account min balance(amount)
const initialSupply = "999999999999999999999999999999999999";
const genesis = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca"; // genesis account address

const policy = new Currency.CurrencyPolicy(minBalance, feeer); // feeer: NilFeeer || FixedFeeer || RatioFeeer 
const amount = new Amount(currency, initialSupply);
const design = new Currency.CurrencyDesign(amount, genesis, policy);

const token = new TimeStamp().UTC(); // any unique string
const fact = new Currency.CurrencyRegisterFact(token, design);

const operation = new Operation(fact);
operation.sign("KxaTHDAQnmFeWWik5MqWXBYkhvp5EpWbsZzXeHDdTDb5NE1dVw8wmpr", { node: "node0sas" }); // node private, node address

currency-policy-updater

currency-policy-updater is an operation that allows you to update policies of already registered tokens.

Here, the way to create a feeer is the same as currency-register.

import { TimeStamp, Currency, Operation, SIG_TYPE } from "mitum-sdk";

const currency = "MCC"; // currency id to update `policy`

// creating feeer
// ...
// done!

const minBalance = "33"; // new account min balance(amount)
const policy = new Currency.CurrencyPolicy(minBalance, feeer); // feeer: NilFeeer || FixedFeeer || RatioFeeer 

const token = new TimeStamp().UTC(); // any unique string
const fact = new Currency.CurrencyPolicyUpdaterFact(token, currency, policy);

const operation = new Operation(fact);
operation.sign("KxaTHDAQnmFeWWik5MqWXBYkhvp5EpWbsZzXeHDdTDb5NE1dVw8wmpr", { node: "node0sas" }); // node private, node address

suffrage-inflation

suffrage-inflation is an operation to supply additional tokens to the network.

You can specify accounts to deposit additional supplies to that account.

Assume that you supply tokens as follows:

  • supply MCC: receiver1, 10000000 tokens
  • supply PEN: receiver2, 500000 tokens
  • supply TXT: receiver3, 999998888 tokens
  • supply BTS: receiver4, 292929292 tokens
  • supply TST: receiver5, 999991888 tokens
import { TimeStamp, Amount, Currency, Operation, SIG_TYPE } from "mitum-sdk";

const receiver1 = "receiver1's account address";
...
const receiver5 = "receiver5's account address";

const mcc = new Amount("MCC", "10000000");
const pen = new Amount("PEN", "500000");
const txt = new Amount("TXT", "999998888");
const bts = new Amount("BTS", "292929292");
const tst = new Amount("TST", "999991888");

const imcc = new Currency.SuffrageInflationItem(receiver1, mcc);
const ipen = new Currency.SuffrageInflationItem(receiver2, pen);
const itxt = new Currency.SuffrageInflationItem(receiver3, txt);
const ibts = new Currency.SuffrageInflationItem(receiver4, bts);
const itst = new Currency.SuffrageInflationItem(receiver5, tst);


const token = new TimeStamp().UTC(); // any unique string
const fact = new Currency.SuffrageInflationFact(token, [imcc, ipen, itxt, ibts, itst]);

const operation = new Operation(fact);
operation.sign("KxaTHDAQnmFeWWik5MqWXBYkhvp5EpWbsZzXeHDdTDb5NE1dVw8wmpr", { node: "node0sas" }); // node private, node address

create-contract-account

create-contract-account is an operation to create a new contract account provided by Mitum Currency Extension.

The rules for contract account creation are as described in 2. Get address from public keys. (exactly the same as general account)

First, suppose you create a contract account with the following settings:

  • 5 public keys
  • each weight: 20
  • threshold: 100
  • initial balance: 1000 MCC, 500 PEN

Here, the weight and threshold are only used to generate the account address and do not affect the behavior of the account at all after the account is registered.

import { TimeStamp, KPGen, Amount, Currency, Operation } from "mitum-sdk";

// create 5 new public keys
const { keys, keypairs } = KPGen.randomN(5); // use KPGen.m2.randomN(5) for m2 key pairs

const mccAmount = new Amount("MCC", "1000");
const penAmount = new Amount("PEN", "500");

const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";

const item = new Currency.CreateContractAccountsItem(keys, [mccAmount, penAmount]);
const fact = new Currency.CreateContractAccountsFact(token, senderAddress, [item]);

const operation = new Operation(fact);
operation.sign(senderPrivate);

Like create-account, the item creation method of create-contact-account for mitum1 and mitum2 is distinguished.

The method of creating an item is exactly the same as create-account.

const { ..., Currency, ADDRESS_TYPE } from "mitum-sdk";

const m1Item = new Currency.CreateContractAccountsItem(keys, [mccAmount, penAmount]); // contract account with m1 btc type address
// const m1Item = new Currency.CreateContractAccountsItem(keys, [mccAmount, penAmount], '');
// const m1Item = new Currency.CreateContractAccountsItem(keys, [mccAmount, penAmount], null);

const m2Item = new Currency.CreateContractAccountsItem(keys, [mccAmount, penAmount], ADDRESS_TYPE.btc); // contract account with m2 btc type address
const m2etherItem = new Currency.CreateContractAccountsItem(keys, [mccAmount, penAmount], ADDRESS_TYPE.ether); // contract account with m2 ether type address

withdraw

withdraw is an operation for withdrawing tokens from a contract account.

Overall, it is similar to transfer.

Suppose your contract account is DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqdmca and you want to withdraw the token from this account as follows:

  • contract account: DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca
  • tokens to transfer: 1000 MCC, 100 PEN
import { TimeStamp, Amount, Currency, Operation } from "mitum-sdk";

const contractAccount = "8iRVFAPiHKaeznfN3CmNjtFtjYSPMPKLuL6qkaJz8RLumca";
const mccAmount = new Amount("MCC", "1000");
const penAmount = new Amount("PEN", "100");

const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";

const item = new Currency.WithdrawsItem(contractAccount, [mccAmount, penAmount]);
const fact = new Currency.WithdrawsFact(token, senderAddress, [item]);

const operation = new Operation(fact);
operation.sign(senderPrivate);

Generate Seal

seal is not used in mitum2. Therefore, only operations with sig-type: DEFAULT or M1 can be added to seal.

Here's how to create a seal:

import { Seal } from "mitum-sdk";

const nodePrivateKey = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";

const seal = new Seal([operation0, operation1, operation2, ...]); // Operation instances or json objects
seal.sign(nodePrivateKey);

// seal.dict(); seal object

Add sign to operation json

You can add a new signature to a operation json using Signer class.

import { Signer } from "mitum-sdk";

const json = { /* your operation json */ };

const signer = new Signer("KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr");

const general = signer.sign(json); // m1 and m2 general operation
const m2node = signer.M2NodeSign(json, "node address"); // m2 node operation

Appendix

Is memo essential for operation generation?

For the operation of mitum1, the memo field is required and is always included in the seed bytes when the operation hash is created.

If there's no memo field or the value is null, it is considered an empty string.

On the other hand, for operation of mitum2, the memo field is considered an extra field and a field name other than memo is also available.

However, in this case, when you create an operation hash, all extra fields are not included in the seed bytes at all.

In other words, memo in mitum1 affects the operating hash value, but not at all in mitum2.

When you create an operation with mitum-sdk, if the memo value is empty or if you don't need it at all, you can omit the parameter, and you only need to insert the value if necessary.

For example:

const operation = new Operation(fact); // memo = null || memo = ''
const operation = new Operation(fact, memo); // memo -> not empty

Set version of hints

To change the mitum version of every objects, add the following code to the part where the app is initialized or required.

The default version is v0.0.1.

import { useV } from "mitum-sdk";

useV("v0.0.2");

Set network id of operations

To apply your network id to operations, add the following code to the part where the app is initialized or required.

The default id is mitum.

import { useId } from "mitum-sdk";

useId("mainnet");

Options and other methods for Operation

If your operation is for mitum1 and accounts of mitum2, you don't need to include the option for the code sign(priv, option). Just leave it null.

However, if the operation is a node operation(not account operation) of mitum2, you must include the option { node: "node address; string" }.

const operation = new Operation(/* fact, etc... */);

/* mitum1(account, node), mitum2(account) */
operation.sign(/* sender's private key */);
operation.sign(/* sender's private key */, null);

/* mitum2(node) */
operation.sign(/* sender's private key */, { node: "node addres" });
  • Set fact-signs without signing

All fact-signs must have the same instance type(M1FactSign | M2FactSign | M2NodeFactSign).

operation.setFactSigns(/* FactSign instances */);

FactSign can be created by...

import { FactSign } from "mitum-sdk";

const m1fs = new M1FactSign(/* signer */, /* signature; buffer */, /* signed_at */);
const m2fs = new M2FactSign(/* signer */, /* signature; buffer */, /* signed_at */);
const m2nodefs = new M2NodeFactSign(/* node address */, /* signer */, /* signature; buffer */, /* signed_at */);
  • Send the operation directly to the network via Digest API.
operation.request(/* digest api address */, /* headers */); // `headers` can be null or undefined
  • You can export operation json to a file.
operation.export(/* file path */);

The request and export methods are also available in Seal instance.

License

GNU GENERAL PUBLIC LICENSE Version 3

0.1.4

12 months ago

0.1.5

11 months ago

0.1.0

1 year ago

0.1.2

1 year ago

0.1.1

1 year ago

0.0.8

1 year ago

0.0.5

1 year ago

0.1.3

1 year ago

0.0.7

1 year ago

0.0.6

1 year ago

0.0.4

1 year ago

0.0.3

1 year ago

0.0.2

1 year ago

0.0.1

1 year ago