mitum-feefi-sdk is Javascript SDK that helps create operations for mitum-feefi model.
You can create operations of the following models with this SDK:
- Mitum Currency
- Mitum Currency Extension
- Mitum Feefi
This project has been developed in the following environments:
$ node --version
v19.8.1
$ npm --version
9.5.1Before installing mitum-feefi-sdk, if you cannot install mitum-sdk using npm, you must install it locally first.
$ git clone https://github.com/ProtoconNet/mitum-sdk-js
$ cd mitum-sdk-js
$ npm i
$ npm i -gYou can install this package locally using this command:
$ git clone https://github.com/ProtoconNet/mitum-feefi-sdk-js
$ cd mitum-feefi-sdk-js
$ npm iRun the following command if you installed mitum-sdk locally:
$ npm link mitum-sdkThen, if you installed mitum-sdk locally, run npm link mitum-sdk.
Or, You can install mitum-feefi-sdk by npm: Not yet published
$ npm i mitum-feefi-sdkBefore testing, check TEST_ID, TEST_NODE, TEST_GENESIS, TEST_ACCOUNT, and etc in esm/mitum.config.js.
You can test mitum-feefi-sdk using this command:
$ npm testTo set the mitum version of all hints and the network id, refer to Set version of hints and Set network id of operations.
mitum-feefi-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: [key]mpr
-
btc public key: [key]mpu
-
ether private key: [key]epr
-
ether public key: [key]epu
The following functions are prepared for key pair generation.
import { KPGen } from "mitum-feefi-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).
import { KPGen } from "mitum-feefi-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(); // 22PVZv7Cizt7T2VUkL4QuR7pmfrprMqnFDEXFkDuJdWhSmpuimport { KPGen } from "mitum-feefi-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 instanceimport { KPGen } from "mitum-feefi-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(); // r3W57ffVSjnyMFQ6132ZoPj1jnbFhoSFCnDYYRq2tXQVmpuThe seed string length must be at least 36.
import { KPGen } from "mitum-feefi-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(); // j3XadE7SLSDS5B7hgTrXmAvZBGWE38WDNyLQKWxn6N96mpuEach 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.
- btc address: [address]mca
- ether address: [address]eca
- zero address: [address]-Xmca
To obtain an address from public keys, you must use the following classes:
import { PubKey, Keys } from "mitum-feefi-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(); // etherLet'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-feefi-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 // Address instance;
const stringAddress = address.toString(); // string address
const etherAddress = mkeys.etherAddress; // (ether) Address instance
const etherStringAddress = etherAddress.toString(); // ether type string addressSee mitum-sdk-js.
Feefi can handle a total of 7 operations.
- pool-register
- pool-policy-updater
- pool-deposits
- pool-withdraw
- airdrop-register
- airdrop-withdraw
- airdrop-close
See Appendix for other instructions on how to use Operation.
pool-register is an operation to register a pool in a contract account.
import { TimeStamp, Feefi, Operation } from "mitum-feefi-sdk";
const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";
const poolAddress = "5hybo4cLkcoJN9UKesbySGAm6NepYFqVh9UWTmKhoATfmca";
const initialFee = "1000000";
const incomeCid = "MCC";
const outlayCid = "PEN";
const currency = "PEN"; // currency id for fee
const fact = new Feefi.PoolRegisterFact(token, senderAddress, poolAddress, initFee, incomeCid, outlayCid, currency);
const operation = new Operation(fact);
operation.sign(senderPrivate);
// see appendix
// operation.export(/* file path; string */);
// operation.request(/* digest api address; string */, /* headers; obj */);pool-policy-updater is an operation to update a pool policy.
import { TimeStamp, Feefi, Operation } from "mitum-feefi-sdk";
const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";
const poolAddress = "5hybo4cLkcoJN9UKesbySGAm6NepYFqVh9UWTmKhoATfmca";
const initialFee = "1000000";
const incomeCid = "MCC";
const outlayCid = "PEN";
const currency = "PEN"; // currency id for fee
const item = new Feefi.PoolPolicyUpdaterItem();
const fact = new Feefi.PoolPolicyUpdaterFact(token, senderAddress, poolAddress, initialFee, incomeCid, outlayCid, currency);
const operation = new Operation(fact);
operation.sign(senderPrivate);pool-deposits is an operation to deposit an amount in a pool.
import { TimeStamp, Amount, Feefi, Operation } from "mitum-feefi-sdk";
const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";
const poolAddress = "5hybo4cLkcoJN9UKesbySGAm6NepYFqVh9UWTmKhoATfmca";
const incomeCid = "MCC";
const outlayCid = "PEN";
const amount = "10000" // amount to deposit
const fact = new Feefi.PoolDepositsFact(token, senderAddress, poolAddress, incomeCid, outlayCid, amount);
const operation = new Operation(fact);
operation.sign(senderPrivate);pool-withdraw is an operation to withdraw the amount from the pool.
import { TimeStamp, Amount, Feefi, Operation } from "mitum-feefi-sdk";
const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";
const poolAddress = "5hybo4cLkcoJN9UKesbySGAm6NepYFqVh9UWTmKhoATfmca";
const incomeCid = "MCC";
const outlayCid = "PEN";
const am1 = new Amount("MCC", "10000"); // amount to withdraw
const am2 = new Amount("PEN", "1000");
const fact = new Feefi.PoolWithdrawFact(token, senderAddress, poolAddress, incomeCid, outlayCid, [am1, am2]);
const operation = new Operation(fact);
operation.sign(senderPrivate);airdrop-register is an operation to for registering airdrops.
import { TimeStamp, Amount, Feefi, Operation } from "mitum-feefi-sdk";
const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";
const poolAddress = "5hybo4cLkcoJN9UKesbySGAm6NepYFqVh9UWTmKhoATfmca";
const incomeCid = "MCC";
const outlayCid = "PEN";
const amount = new Amount("MCC", "10000");
const start = "2023-01-12T02:03:40Z";
const end = "2023-01-12T02:05:40Z";
const fact = new Feefi.AirdropRegisterFact(token, senderAddress, poolAddress, incomeCid, outlayCid, start, end, amount);
const operation = new Operation(fact);
operation.sign(senderPrivate);airdrop-withdraw is an operation for withdrawing from airdrop.
import { TimeStamp, Amount, Feefi, Operation } from "mitum-feefi-sdk";
const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";
const poolAddress = "5hybo4cLkcoJN9UKesbySGAm6NepYFqVh9UWTmKhoATfmca";
const incomeCid = "MCC";
const outlayCid = "PEN";
const amount = new Amount("MCC", "10000");
const fact = new Feefi.AirdropWithdrawFact(token, senderAddress, poolAddress, incomeCid, outlayCid, amount);
const operation = new Operation(fact);
operation.sign(senderPrivate);airdrop-close is an operation to close airdrop.
import { TimeStamp, Feefi, Operation } from "mitum-feefi-sdk";
const token = new TimeStamp().UTC(); // any unique string
const senderAddress = "DBa8N5of7LZkx8ngH4mVbQmQ2NHDd6gL2mScGfhAEqddmca";
const senderPrivate = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";
const poolAddress = "5hybo4cLkcoJN9UKesbySGAm6NepYFqVh9UWTmKhoATfmca";
const incomeCid = "MCC";
const outlayCid = "PEN";
const currency = "MCC"; // currency id for fee
const fact = new Feefi.AirdropCloseFact(token, senderAddress, poolAddress, incomeCid, outlayCid, currency);
const operation = new Operation(fact);
operation.sign(senderPrivate);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-feefi-sdk";
const nodePrivateKey = "KzFERQKNQbPA8cdsX5tCiCZvR4KgBou41cgtPk69XueFbaEjrczbmpr";
const seal = new Seal([operation0, operation1, operation2, ...]); // Operation instances or json objects
seal.sign(nodePrivateKey);
// seal.dict(); seal objectYou can add a new signature to a operation json using Signer class.
import { Signer } from "mitum-feefi-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 operationFor 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 emptyTo 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-feefi-sdk";
useV("v0.0.2");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-feefi-sdk";
useId("mainnet");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-feefi-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.