Here we propose the example of simple transaction from default account(ed25519) to any other account
Keypair creation process
Generate keypair
import {crypto} from 'web1337';
let mnemonic = ""; // mnemonic should be empty in case you generate a new pair
let mnemonicPassword = "HelloKlyntar"; // set the password for your mnemonic
let bip44Path = [44,7331,0,0]; // 7331 is KLY ID and the next values - derivation path
let keypair = await crypto.ed25519.generateDefaultEd25519Keypair(mnemonic,mnemonicPassword,bip44Path);
console.log(JSON.parse(keypair));
By default, you get the new mnemonic and key pair with m/44'/7331'/0'/0' path. But, to generate many accounts from a single seed do this:
Get the mnemonic from the first generation
Change the path to 1,2,3... to build the HD chain of accounts
For example:
Get the first keypair in future chain:
import {crypto} from 'web1337';
let mnemonic = ""; // mnemonic should be empty in case you generate a new pair
let mnemonicPassword = "HelloKlyntar"; // DO NOT USE IN REAL USE CASES
let bip44Path = [44,7331,0,0]; // 7331 is KLY ID and the next values - derivation path
let keypair = await crypto.ed25519.generateDefaultEd25519Keypair(mnemonic,mnemonicPassword,bip44Path);
console.log(JSON.parse(keypair));
For the first pair in future chain of accounts we don't set the mnemonic and BIP-44 path. Mnemonic will be randomly generated and path will be m/44'/7331'/0'/0'. The last parameter is the password that will be used to get the seed from your mnemonic.
That's why - choose the password with the high entropy, ommiting typical passwords from well known wordlists to make brute force impossible. Also, DON'T SHARE YOUR MNEMONIC PHRASE - YOU WILL LOST CONTROL OF YOUR ACCOUNT.
Example of simplest transaction - from default account to default account
let web1337 = new Web1337({
chainID:'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
workflowVersion:0,
nodeURL: 'http://localhost:7332'
}); // need node endpoint to return the correct nonce. If you know your nonce - you can omit it
const keypair = {
pub:"9GQ46rqY238rk2neSwgidap9ww5zbAN4dyqyC7j5ZnBK",
prv:"MC4CAQAwBQYDK2VwBCIEILdhTMVYFz2GP8+uKUA+1FnZTEdN8eHFzbb8400cpEU9",
};
const payload = {
to: "Ai1Pk9RzmgeiSAptc1W69NAmSB52GqjNqGdGQGgqxQA1",
amount: 13.37
};
const fee = 0.03;
const nonce = await web1337.getAccount(keypair.pub).then(account=>account.nonce+1);
const txType = "TX";
let tx = web1337.createEd25519Transaction(txType,keypair.pub,keypair.prv,nonce,fee,payload);
console.log(tx);
let sendStatus = await web1337.sendTransaction(tx);
console.log(sendStatus);
// After that - you can check the tx receipt
// TxID - it's a BLAKE3 hash of transaction signature
let receipt = await web1337.getTransactionReceiptById(web1337.blake3(tx.sig));
console.log(receipt);
isOk - status to check if tx successfully processed or not
Optional fields:
reason - in case tx failed you can use this reason to understand why
createdContractAddress - only in txs where contract was deployed. It might be WASM or EVM contract
extraDataToReceipt - optional object with extra data (for example - result of contract call)
Check explorer:
If you check this tx in explorer you should see:
Ed25519 => BLS(multisig address) transaction
A transfer transaction to a multisig address is literally 1 step more complicated. So, when you are going to send something to a multisig address, depending on whether the recipient's account already exists on the network, you need to specify an additional rev_t field that indicates the reverse threshold.
What is reverse threshold?
Imagine that you and your 3 friends are going to manage some resources together, whether it be native KLY coins or some tokens. For this, it is obviously worth using a multisig address.
Let's assume that you agree that the decision is considered accepted if the voting threshold of 3/4 is reached (3 out of 4 friends agree to spend coins or call some kind of smart contract). So, if the threshold is 3/4, then the reverse threshold in this case will be 1 (because 4-3 = 1).
Here are some examples for other cases:
Reverse threshold = 3 for a situation where you need 7/10 agreements
Reverse threshold = 2 for a situation where you need 3/5 agreements
And so on
The reverse threshold was introduced in response to the ability of BLS signatures and public keys to aggregation. Since the situation is often such that
T>TāN
where:
N is the number of sides of the multi-signature
T is the threshold
and when checking the signature we need to know whether the threshold has been reached, then we need to do this:
Present the consenting parties as an aggregated public key and an aggregated BLS signature
In a separate array, present the public BLS keys of those who do not agree with the decision (or could not vote for some reason)
Going back to the 4 friends example, if we have a threshold of 3/4, then it makes more sense to aggregate 3 signatures and 3 public keys into 1 and separately present 1 public key of the one who disagrees than to provide 3 separate keys and signatures from 4.
Let's look at a specific example
You and 3 your friends generate multisig pairs(public + private key) locally. Let's do it with Web1337:
import {crypto} from 'web1337';
let privateKey1 = await crypto.bls.generatePrivateKey();
let publicKey1 = crypto.bls.derivePubKeyFromHexPrivateKey(privateKey1);
let privateKey2 = await crypto.bls.generatePrivateKey();
let publicKey2 = crypto.bls.derivePubKeyFromHexPrivateKey(privateKey2);
let privateKey3 = await crypto.bls.generatePrivateKey();
let publicKey3 = crypto.bls.derivePubKeyFromHexPrivateKey(privateKey3);
let privateKey4 = await crypto.bls.generatePrivateKey();
let publicKey4 = crypto.bls.derivePubKeyFromHexPrivateKey(privateKey4);
console.log(`Pair 1 => ${privateKey1} : ${publicKey1}`);
console.log(`Pair 2 => ${privateKey2} : ${publicKey2}`);
console.log(`Pair 3 => ${privateKey3} : ${publicKey3}`);
console.log(`Pair 4 => ${privateKey4} : ${publicKey4}`);
Now, you need to aggregate your 4 public keys to get the root public key and receive payments for collective usage.
let publicKey1 = '0xabe301a20289d1e014c69906febbee42626e084dc93f70c689803e163963101fc90a3674576f86ff90ba9c71310685f1';
let privateKey1 = '69bfb956053e034b1b7d8b634c9bb8acd1b5743fab64245fad4b1472f63799a9';
let publicKey2 = '0x8486ccde87fe2603815587a64bd43596d45b383d12563e6b513a9ca033ec9974490f9d577125bbd2b80ada893476a603';
let privateKey2 = '001b9abf2e6d23e13b30a4d35242a11848530f5e40a0fea8c3c50d2902c6c056';
let publicKey3 = '0x87960819a282b2092825c73ac3afbe2e1d5680dff8e00c1f10851ab0b025ae45ac46698d6c0dfda229e2a187bde9690c';
let privateKey3 = '5eca1e38f579064091c4c84eab47b5b5f2a0256847674e6f590879c2dc1605e0';
let publicKey4 = '0x965c986dc91c1a45b6a6d24bb7b8509e9c80f6e77827de1e70737bdeeb23ef3362864da538da57a57384c17dcc9a3fc7';
let privateKey4 = '1635f5c69f695673e83184aba52316a9d2a458016e791ae0180d8c42d05a144c';
let rootPubKey = crypto.bls.aggregatePublicKeys([publicKey1,publicKey2,publicKey3,publicKey4]);
console.log('RootPubKey => ',rootPubKey);
When you need to send something to multisig account you need to set the reverse threshold if account still not exists or use rev_t property of already existed account
So, if account 0xb89c4bf0b9dab0224201d06d46ed6cb49b94f34f8dc8feb0d7bad77caab5b41fc16531dce9ba2cba5784359d2b701cc4 still not in state - use this template:
let web1337 = new Web1337({
chainID:'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
workflowVersion:0,
nodeURL: 'http://localhost:7332'
}); // need node endpoint to return the correct nonce. If you know your nonce - you can omit it
const keypair = {
pub:"9GQ46rqY238rk2neSwgidap9ww5zbAN4dyqyC7j5ZnBK",
prv:"MC4CAQAwBQYDK2VwBCIEILdhTMVYFz2GP8+uKUA+1FnZTEdN8eHFzbb8400cpEU9",
};
// In our example with 4 friends, since we want 3/4 agreements
// to use account, the reverse threshold will be 4-3=1
// Use the formula rev_t = N-T where N - number of sides, T-threshold
const reverseThreshold = 1;
const payload = {
to: "0xb89c4bf0b9dab0224201d06d46ed6cb49b94f34f8dc8feb0d7bad77caab5b41fc16531dce9ba2cba5784359d2b701cc4",
amount: 13.37,
rev_t: reverseThreshold
};
const fee = 0.03;
const nonce = await web1337.getAccount(keypair.pub).then(account=>account.nonce+1);
const txType = "TX";
let tx = web1337.createEd25519Transaction(txType,keypair.pub,keypair.prv,nonce,fee,payload);
console.log(tx);
And then, use the value of rev_t to build the transaction as above
Ed25519 => TBLS(thresholdsig address) transaction
In this transaction you send something to TBLS root public key which controled by group of N members
We'll talk more about TBLS in the next parts. Just now you need to know the 48-byte root public key
let web1337 = new Web1337({
chainID:'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
workflowVersion:0,
nodeURL: 'http://localhost:7332'
}); // need node endpoint to return the correct nonce. If you know your nonce - you can omit it
const keypair = {
pub:"9GQ46rqY238rk2neSwgidap9ww5zbAN4dyqyC7j5ZnBK",
prv:"MC4CAQAwBQYDK2VwBCIEILdhTMVYFz2GP8+uKUA+1FnZTEdN8eHFzbb8400cpEU9",
};
const payload = {
to: "b89c4bf0b9dab0224201d06d46ed6cb49b94f34f8dc8feb0d7bad77caab5b41fc16531dce9ba2cba5784359d2b701cc4",
amount: 13.37
};
const fee = 0.03;
const nonce = await web1337.getAccount(keypair.pub).then(account=>account.nonce+1);
const txType = "TX";
let tx = web1337.createEd25519Transaction(txType,keypair.pub,keypair.prv,nonce,fee,payload);
console.log(tx);
In this transaction you send your assets to the BLAKE3 hash of public key of some post-quantum signatures schemes like DIlithium or BLISS (we support 2 algorithms)
NOW ATTENTION:
In case you fund a NEW post-quantum account you need to add the post-quantum pubkey of recipient to payload
By default, you recipient have locally keypair like this:
Case 1: His account already in state and has balance
In case recipient account already exists, just ask him for address.
In this case your payload of transaction will look like this:
let payload = {
to: "1826d3782d53b127c53129fe67f4a3e3c1140feb2af36a0517077297a6e867e5",
amount: 13.37
}
Case 2: Recipient account will be new and didn't exists before tx
So, if you fund new account the payload of your transaction should be:
let payload = {
to: "1826d3782d53b127c53129fe67f4a3e3c1140feb2af36a0517077297a6e867e5",
amount: 13.37,
pqcPub:"001b4609d500e31a0a188911900aac07fb06f91566038104e90c01031707d6154701701a15046d07f5089f0c730c8515e712c90b5a130d10081bca0ab40c8f0027101501870ccb17041d691bac0c30162d11ff0566198710f308cd08b30be804261a040c530cb8042e16841623069200b9175410a5016a171e1ceb10f813261bae0acc06be176214471d7013530d92180a0dbd15c800fd09f700ed0a8616141a14095b08a71c3317031d78106602ef1c1f1a53097016df192905b50ad40b5c1d1c027e026b0ecb115417ae1b6f1c1101c60d3f1c12016010a309f8183411840d7d12d414071a5b10d1162111f712951b36066209500e1d137d1dbf055417e6075c0ce307460ff9040715b51d0000cc11cf1bd1194c0a2d19e901191c5306040c8002be0d19024f10b31b19152912fe06900de21b2e10110ab111f80b6403ac1b8505221bac09830e3501a1175705c7138e1db6035c09871c4c121706b70b560ac70c001d2305b0107117ef02c1178a13f010bb193004ca02bc035e036f109419770a2017f11dd00cb3016405b41604091206c61603085208fa0df0130912cb14cd187914b009e306440a3018ca0c5810c305400507103b1113016c0ead00100e3f02b6003410981cdf04c50d0213d61984110c0ba700ae0c8912f618a01a231bc81066010a1d051242103013ac05c30dae14030f890e1117b319a002a707f30923"
}
In case PQC account of recipient do not exist - include additional field pqcPub to payload to let the network to create pubkey:address pair in state
We'll talk about PQC accounts later. Just now, as a sender you just need to know only the address of recipient - it's 256-bit BLAKE3 hash of public key
let web1337 = new Web1337({
chainID:'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
workflowVersion:0,
nodeURL: 'http://localhost:7332'
}); // need node endpoint to return the correct nonce. If you know your nonce - you can omit it
const keypair = {
pub:"9GQ46rqY238rk2neSwgidap9ww5zbAN4dyqyC7j5ZnBK",
prv:"MC4CAQAwBQYDK2VwBCIEILdhTMVYFz2GP8+uKUA+1FnZTEdN8eHFzbb8400cpEU9",
};
const payload = {
to: "4218fb0aaace62c4bfafbdd9adb05b99a9bf1a33eeae074215a51cb644b9a85c",
amount: 13.37
};
const fee = 0.03;
const nonce = await web1337.getAccount(keypair.pub).then(account=>account.nonce+1);
const txType = "TX";
let tx = web1337.createEd25519Transaction(txType,keypair.pub,keypair.prv,nonce,fee,payload);
console.log(tx);