Threshold signatures may seem more complex than the multi-signatures described earlier. And yet, with a large number of parties involved, it is recommended to use TBLS, since the size of such a transaction will be much smaller.
For example, if we have 100 parties that together manage a certain account and it was decided that the decision threshold is 60% (60 parties), then you will need to send 40 public keys in the afkVoters array.
At the same time, in TBLS, the identifier of the entire group of signers is a 48-byte root key and in order for the network to understand that the initially set threshold has been reached (it doesnβt matter whether 60 participants, 63, 87, or all 100 agree with the decision, the main thing is more than initialy defined threshold) you need to provide only 1 signature. By verifying it using the master key, the network will allow the group to complete the transaction.
Use case
There are 6 friends who want to share some cryptocurrency when they go to the festival. At the same time, there was an agreement that the costs agree with the majority. That is, 4 out of 6 friends must agree to a certain purchase or other type of expenditure. For this, the friends agreed that each of them would replenish the joint wallet with 500 units of KLY. Well, let's help them generate such a wallet and everything else for honest money management.
Step 1 - generation
So, consider the signature of the first function generateTBLS() It has the following parameters:
threshold - threshold. In our case, it will be equal to 4
myPubId - choose some initial numeric ID for yourself
pubKeysArr - an array of other identifiers. Our ID must also be included in this array
Let's generate
import {crypto} from'web1337';let threshold =4; // 4/6let myPubId =1; // our IDlet pubKeysArr = [1,2,3,4,5,6]; // array of identifiers of all memberslet {verificationVector,secretShares,id} =crypto.tbls.generateTBLS(threshold,myPubId,pubKeysArr);console.log('Use with VV => ',verificationVector);console.log('Array of secret shares to share among friends => ',secretShares);console.log('Your id => ',id);
Output:
Use with VV => [
'a76d8d35fe2862f06023b84c0ddb51b5d1ef7f51a3a75e30cc44dc16ef394df663064e394b600ef4a01f5a56211e12f1',
'a4ec5ea273162fa638a705c05f2856773a9ffc4b05748a2a2460a1056fa79c3fe1970c964dd6cc05e8c4b9d632562b5a',
'a45dcde6d64b0b8fbe832c37261122917c773153cd2fedde38453269a7cf1e10cd1c364b29e87f888a0531f9680ac58f',
'ad63014f0a527a4f64fa191e976b07b228daa30a5af9687a7e47a9625e2d8eedd6e7a3a6f53b651f0a45fe174e1657d9'
]
Array of secret shares to share among friends => [
'1bf733f46fc9cc7b23602bda959cb0c4984c3ca7681301e01dd6e0fae70ba9f0',
'1d3fe21eee5127e6b071a80a18182afe867956f9ee7560ed518e5ae43b341ac4',
'117e89f528f2cb2ba094a303b8cd6623f416aa968d176b29d8da0436e08e786c',
'4dd9a6b1fbf4fc4350d1f8f96d32d3d9513f7823245bc8cd4c163ce0ff476705',
'3291b6b687fd89b561d1b01543fcf3e220a28b9f0c3cd3f1b66103309b2d57a1',
'1be39b80136feb48d2fabc68ad3f885e4043499a2b5191c7f9eb1a446f30ac79'
]
Your id => 1a4585773ce2ccd7a585c331d60a60d1e3b7d28cbb2ede3bc55445342f12f54b
Cool, now let's figure out what we have:
verificationVector is a verification vector that we have to send to all other 5 friends
secretShares are something that we have to send to friends(1 share for 1 friend). That is, the first share(secretShares[0]) goes to the friend with ID=1 (this is you), the second share (secretShares[1]) goes to the second friend - the one with ID=2, and so on. There are 6 of them here, so it is clear that everyone has a share
id is our ID that we will now use for further generations
Step 2 - friends do the same
A similar procedure is performed locally by yourself and 5 of your friends. Each of them will receive its ID, each will receive an array of 6 shares and a verification vector.
An important point is to agree a set of identifiers with your friends
I mean that the other 6 friends must also use the same ID array. And your ID will be the same for all friends. That is:
For a friend with ID=1 - takes share 1 for himself
For a friend with ID=2 - takes layer 2 for himself
And so on
Step 3 - get the root public key
At this stage, friends will receive 48-bytes hex encoded address in the KLY network to which they can send funds for shared use. For this purpose, they exchange verification vectors. When you receive 5 verification vectors from 5 other friends, then add your sixth one and call the deriveGroupPubTBLS() function. But before we break it down, let's create some imaginary dataset with the data of the other 5 friends. So, let it look like this:
/*------------------------------- FRIEND 1 -------------------------------Verification vector[ "a7e972de2362e725831efdebe080842f9ee275915a718dea43e561fa0d1af41b3192f849e1128d69f62018b9e7a9387f" "0003e06c68ba56e45db0ee64a06a6935554e0b7f4849da26223cf831cdfd341bf9fe628590eb436197145206eb8f2eb0" "53ad69e15e782a60fe63ee07d9e768dff002dfc54fa6fd6e4ea4531fc00d2700472fb244c9fa740ec354e417e8bd241c" "21b090515bf15d9ec6c4f4dd4df5f49a64f21e9b9c268b91b09bd77adcf2d517303fe3cf3bdd710ab783ae413476f7cc"]Array of shares[ "79b359142147dd33383e32ac2476577d7760245a644fdad8730b22fad5726b0d" it's your share "2ba86e244fe8ad6ea665598257e1a8700b433a2e5bd967116fcf982b9db0df05" send to friend 2 "af5f947ef9db70f50a8a5a5ee07170e78974c641b52942681a229605ff860e1f" send to friend 3 "0f0389cb5fdc97c14d3c494ada022bafb78988efb891258b9c487b9475febd0a" send to friend 4 "c8472e66991a8a1121a5f89f3ae5c1200455f77da838b965f8b9ef5af0701e07" send to friend 5 "565a252bc870bdcf046fb76a25c45c56cab9d4a5624e794319dd13dbc7e9781f" send to friend 6]ID = 4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785451a------------------------------- FRIEND 2 -------------------------------Verification vector[ "6f4c90be986832a71aa5b8d25007d27adc3aa267acdca189a42b9a17efc8dd17bcde25c173d18eeba5bae067e52cc5ba1" "775449cde76ce6333c53317e6b6a1eb47ee87af2bc56548bb38fea5da266dd0704ae043c288f9fb792b870128738ad736" "dd5a9d1f3236dd7e091dcb4272fb3cec624c22a0e59de283ce345603850e180e263806875158263b2bd46f0b7af4d7859" "8176bdd4610dd21cdb6bfb9b526a9e3ee2804c57ac9b9094235a4c1947c2f20aa1282cc8dd5e2ec09183c677920106024"]Array of shares[ 173fc58cb61188a8fad233a689baec3db34657c3bb8536b21cbad70db463130b send to friend 1 834ffe5b7794a5c8666210a98beaba4a48d344dd2e691ce4edb2196f6b2da317 it's your share a8e50fdc4d6f1f20047b7297ff54ac2d807cbfb6cd12e8f499e6eaf7b5feb010 send to friend 3 50b2c925a3463136414715d0f99c594c1aa2d7e5857d7881f62dcdc7676c191a send to friend 4 d7f329f64448ddd56350a2a3a45d944679a2c4fc76ecb3770d760592b08c8b0a send to friend 5 2ddedf940ea38c9809735793cec9ded6d0d6e573181611c0f3efa604b6b92e1c send to friend 6]ID=dbc1b4c900ffe48d575b5da5c638040125f65db0fe3e24494b76ea986457d906------------------------------- FRIEND 3 -------------------------------Verification vector[ "586797df712ba4dcb15e78a36e6ef4a3f9ba1b05ce3a6a9001f0cdfefbd8f8080a33a3182a9204657594ebc6749656166f1" "62b9b08eadbbb20ef840923c89ac53b73aa31fa3e493097f49496693a795131b46dba854f76bfaf369beb77a7a80e2fe665" "2577181e0384bc99ceb066acf69323e236160796df37f6e688d3274e4e026a03997460021b39da01a8a1465566e08f6a455" "b2a2ace162f22b200c7aa807083bae80e69214dcdaa9708c66f81d1e8d4a0c18c3b459214292bd683c9b80809ea3e7e9528"]Array of shares[ 82858da32c368bc8dea20ab9646d87f84eb478e51a45a55394710c96c71a080f send to friend 1 6a12a6abfe939015aca70e67c96e9768ad9af0e6541c62e82b51ca32176c8816 send to friend 2 b607ae0d7be4bbbad607967c40841e67f8b992e15a44fc3d0dbc5a14a16f9b0e it's your share 73d57dfb5cd773a19a34052184d1f0b2576bc127ee1d92ae596c51bf3a6e2c24 send to friend 4 d9dc10623e261047a0ac924595c356f5d9b192ab28f29276bf5c21206c143902 send to friend 5 952e03949438a001aafb2b1e864635c25b229047fc85b3178dd1d049ecbdcd04 send to friend 6]ID=084fed08b978af4d7d196a7446a86b58009e636b611db16211b65a9aadff2905------------------------------- FRIEND 4 -------------------------------Verification vector[ "7a4a81ba14f4b32b3c7f061f718cc15b0ca3ab76196a7e9e62f70dcc0add10092906a237d27b034f541731df41fee38d2f4b5d" "6edfa6a70925257e952f161d941092bf30cd70d1f27a6cba53affbe9de7a450dfc02b5c500fbeb9ca2443df0a941269ad65c8b" "492a5db1fdf4f133e4d8e92c0637ae13a8da6f19bc93da4ed6b0736d8bc602063a229846a43e18b8ba39de1cdba274a11fcda3" "8396e4d78a12580388c919b8a201036d48a1470c9684eb653ea89f458927730bc32e8f91763dfce581ff60125664cd6e1a20ed"]Array of shares[ 89b3400f482b4bed1e1eba002df97c8a7933c435fdd990d043fd527255010406 send to friend 1 36ae6a22edc96b63ae6bf5ca78445f62117d2aeb0606876b5b0cd321c5338b0a send to friend 2 2170ec403427f94086f4e4712aef6e0b719f58160d8acdd27e26eaaa95676e1a send to friend 3 88e7e3aea7506953618a4f6c3b09e52fa7e1f881f16c70b66ef67c2ba80c5c0e it's your share 3569f445bbc8274318a0a3e761c016610bcb8b2cb414b49a76979181f9a3480f send to friend 5 b7a2bc301f42f0aa7acff13015b5c28ddd13d8b3fee5f3f81978463bba5efb16 send to friend 6]ID=e52d9c508c502347344d8c07ad91cbd6068afc75ff6292f062a09ca381c89e11
We call the public key generation function of our group. In this case, we equate the concept of public key/network address. In any case, the address can be obtained from the public key. So, we have:
and be sure that everything is OK? No, because you need to check the validity of the shares first to omit situation when maulicious actors(your "friends") can control this wallet without you. This is a VSS(Verifiable Secret Sharing) element - we need to make sure that each friend sent us a valid share. For this, there is a verifyShareTBLS() function in the module. Let's consider its parameters
hexMyId - it's our ID from step 1
hexSomeSignerSecretKeyContribution - it's share that we're going to verify(share from friend X).
hexSomeSignerVerificationVector - it's verification vector by friend X
Ok, let's verify. From the friend 1 point orf view:
/*Verification vector[ "a7e972de2362e725831efdebe080842f9ee275915a718dea43e561fa0d1af41b3192f849e1128d69f62018b9e7a9387f8b8611488a72480305991d480dad0e11"
"0003e06c68ba56e45db0ee64a06a6935554e0b7f4849da26223cf831cdfd341bf9fe628590eb436197145206eb8f2eb0baef673eff23f63eaa6fe74e59da7c05"
"53ad69e15e782a60fe63ee07d9e768dff002dfc54fa6fd6e4ea4531fc00d2700472fb244c9fa740ec354e417e8bd241c875caf29c4abad251a042d7becca4d15"
"21b090515bf15d9ec6c4f4dd4df5f49a64f21e9b9c268b91b09bd77adcf2d517303fe3cf3bdd710ab783ae413476f7ccd050c1be02524a42484243b47767b71f"
]Shares[ "79b359142147dd33383e32ac2476577d7760245a644fdad8730b22fad5726b0d" your share "2ba86e244fe8ad6ea665598257e1a8700b433a2e5bd967116fcf982b9db0df05" send to friend 2 "af5f947ef9db70f50a8a5a5ee07170e78974c641b52942681a229605ff860e1f" send to friend 3 "0f0389cb5fdc97c14d3c494ada022bafb78988efb891258b9c487b9475febd0a" send to friend 4 "c8472e66991a8a1121a5f89f3ae5c1200455f77da838b965f8b9ef5af0701e07" send to friend 5 "565a252bc870bdcf046fb76a25c45c56cab9d4a5624e794319dd13dbc7e9781f" send to friend 6]ID = 4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785451a*/
Let's say we send the share to friend 4. So friend 4 will have the following:
/*Verification vector[ "7a4a81ba14f4b32b3c7f061f718cc15b0ca3ab76196a7e9e62f70dcc0add10092906a237d27b034f541731df41fee38d2f4b5d8998678b7d06cad2532fbecc13"
"6edfa6a70925257e952f161d941092bf30cd70d1f27a6cba53affbe9de7a450dfc02b5c500fbeb9ca2443df0a941269ad65c8bede560f033ae802d6499281a9e"
"492a5db1fdf4f133e4d8e92c0637ae13a8da6f19bc93da4ed6b0736d8bc602063a229846a43e18b8ba39de1cdba274a11fcda3cf482e3ca908cdf3c3f7ffdb04"
"8396e4d78a12580388c919b8a201036d48a1470c9684eb653ea89f458927730bc32e8f91763dfce581ff60125664cd6e1a20ed684677a6d8dccbb6b23c3a0182"
]Array of shares[ 89b3400f482b4bed1e1eba002df97c8a7933c435fdd990d043fd527255010406 send to friend 1 36ae6a22edc96b63ae6bf5ca78445f62117d2aeb0606876b5b0cd321c5338b0a send to friend 2 2170ec403427f94086f4e4712aef6e0b719f58160d8acdd27e26eaaa95676e1a send to friend 3 88e7e3aea7506953618a4f6c3b09e52fa7e1f881f16c70b66ef67c2ba80c5c0e your share 3569f445bbc8274318a0a3e761c016610bcb8b2cb414b49a76979181f9a3480f send to friend 5 b7a2bc301f42f0aa7acff13015b5c28ddd13d8b3fee5f3f81978463bba5efb16 send to friend 6]ID=e52d9c508c502347344d8c07ad91cbd6068afc75ff6292f062a09ca381c89e11++++++++++++++++++++++++++++++++++++++++++++++++ Received share and verification vecotr from friend 1 ++++++++++++++++++++++++++++++++++++++++++++++++
SHARE_FROM_FRIEND_1 = 0f0389cb5fdc97c14d3c494ada022bafb78988efb891258b9c487b9475febd0aVERIFICATION_VECTOR_OF_FRIEND_1 = [ "a7e972de2362e725831efdebe080842f9ee275915a718dea43e561fa0d1af41b3192f849e1128d69f62018b9e7a9387f8b8611488a72480305991d480dad0e11"
"0003e06c68ba56e45db0ee64a06a6935554e0b7f4849da26223cf831cdfd341bf9fe628590eb436197145206eb8f2eb0baef673eff23f63eaa6fe74e59da7c05"
"53ad69e15e782a60fe63ee07d9e768dff002dfc54fa6fd6e4ea4531fc00d2700472fb244c9fa740ec354e417e8bd241c875caf29c4abad251a042d7becca4d15"
"21b090515bf15d9ec6c4f4dd4df5f49a64f21e9b9c268b91b09bd77adcf2d517303fe3cf3bdd710ab783ae413476f7ccd050c1be02524a42484243b47767b71f"
]*/
And note, there will only be this public key in the blockchain - without any additional settings or conditions. The key size will be similar even if there are 20 or 100 signatory participants
Step 5 - generate partial signatures
Ok, let's move on to the moment when the friends finally decided to make a purchase. The worst possible scenario is when 4 out of 6 friends agree to the purchase and 2 of them do not. Nevertheless, 4 is a sufficient threshold and each of the 4 friends must generate a partial signature, in order to then combine them and send them to the blockchain as cryptographic proof that the threshold has been reached and the network can allow spending on this wallet. To do this, each of the 4 friends must generate a partial signature and share it with the other 3 friends.
It is worth noting that the threshold T indicates the minimum value of the signatories. In our example, we consider just such a case. However, funds can be spent even when 5 or all 6 agree with the decision
So, to generate a partial signature, we will use the signTBLS() function. Let's consider its parameters:
hexMyId - it's our ID from step 1
sharedPayload - it's array like this:
sharedPayload:[
{
verificationVector://Verification vector from signer_1 in hex format
secretKeyShare://Share that we get from signer_1 in hex format
},
{
verificationVector://Verification vector from signer_2 in hex format
secretKeyShare://Share that we get from signer_2 in hex format
},
...,
{
verificationVector://Verification vector from signer_N in hex format
secretKeyShare://Share that we get from signer_N in hex format
}
message - it's message that we need to sign(transaction hash)
Now, having 4 partial signatures, we can get a master signature. Later, with the message and master public key will be able to verify this signature and make sure it's valid and wished threshold was reached. It's time for the buildSignature() function. Traditionally, let's consider the parameters:
signaturesArray - array like
[ {sigShare:signedShareA,id:hexIdA}, {sigShare:signedShareB,id:hexIdB},... {sigShare:signedShareX,id:hexIdX} ]
// [+] sigShareN - partial signature by signer N in hex format
// [+] id - ID of this signer
Execute the function
let sigShareAndId1={sigShare:"fe789c95b112099b370d0dfdb7aae4fb80087aa2cea0334266de5792ee27d617",id:"4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785451a"};
let sigShareAndId2={sigShare:"3cafeb0275cea62faf29df46c3d7bb52e1a6d33ab89aa0ad53d5bf1f53a0e285",id:"dbc1b4c900ffe48d575b5da5c638040125f65db0fe3e24494b76ea986457d906"};
let sigShareAndId3={sigShare:"14a7a88ad49586e8c5a4e2c87b91b82f005fc595e60bd39b3a8d1cc3d20c9815",id:"084fed08b978af4d7d196a7446a86b58009e636b611db16211b65a9aadff2905"};
let sigShareAndId4={sigShare:"6b46897a312f2e9e8f515f359f2adeb50c5c9fb5f6317c535a9a351c3e5f6e8a",id:"e52d9c508c502347344d8c07ad91cbd6068afc75ff6292f062a09ca381c89e11"};
let masterSignature = crypto.tbls.buildSignature([sigShareAndId1,sigShareAndId2,sigShareAndId3,sigShareAndId4]); //46c1f011e7d7039bb77a638e60e7e1c3acbfb3124ec2b06b918f1fd5d4a0b39c
Step 7 - verification of group signature using the group public key
So, at the previous stage, the signature of the group was obtained. Even earlier, we received the public key of the group - this is our address in the KLY network:
And only one what the network needs to do to accept a transaction from friends is simply to make such a check:
let masterPub = '8aae5ae3b51a6f4bba62f64ab44b2135339831f662f8ef9e004bffb1458faa045f2c9a640acb466c5c35e2c9af757ac7fad74e3865b8527452619236822f9797';
let masterSig ='46c1f011e7d7039bb77a638e60e7e1c3acbfb3124ec2b06b918f1fd5d4a0b39c';let message ='WE BUY A TENT FOR 300$';let isOk =crypto.tbls.verifyTBLS(masterPub,masterSig,message); //true
We hope that such a step-by-step example where we describe generation and exchange of the necessary data will help developers in creating their products in the KLY ecosystem
Now, let's build the transactions
TBLS => Ed25519 transaction
import Web1337,{crypto} from'web1337';let web1337 =newWeb1337({ chainID:'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', workflowVersion:0, nodeURL:'http://localhost:7332'});// 3 friends, threshold is 2/3consttblsAccounts= { ALICE:{ verificationVector:["79309fde56bf1e0420408b79b9adb8b675b85eddb78b675d66b1931106a3d113f34d23257c912ee1800fcc31290e525bfbaf5d18a51eabc7daefc3ff8d183d17","67c2572d5b5e9be849917ba16a2152d70dff21094915ccf03969acbc0046870ece2fe2d9afbdd6dc5b65e2e528ee702a3343de6caf3b25f0f9c571fcfd55d084"],
shares:['f77ffec138a41033c3f278774685a53fa4f49687365d788c0efd671f29359703','f5b187d48cd56e9680985f5f0a6f7744bef11092a142bbbc0d5f0c4c92ed0a02','48f13b18936fabb681d7ed21bd0e747e9553b3777547795e9ad878734197631a'],
id:'4bf5122f344554c53bde2ebb8cd2b7e3d1600ad631c385a5d7cce23c7785451a' }, BOB:{ verificationVector:["0af3b5585e92422fd02d0370043e193f258896df63b4fcf37f5323c8d0545b00e67f1b3b728751ef2dabc3378959376b83edec5d0b788c367edb195cc9bca402","29480aacb9fd7c9fc02f2f201cf2958b1bac764f1b1d9b4ad0c4f24c981a891db271723d076eb06b0a5c6bddf758b3fc9ade4542628f583796fa55b5855bf194"],
shares:['1bfe78127fb2e4ee5eab8d0875aef9c49606535825fbb2619edb29ccd1a93508','ba706c61ab4be0b619b523021e79afddf21e124ecca08c1af4d057b3b6dd7213','a97319f37cdf2833a996334952eb73f8903260574d1ef549007a0d2de1ccb41c'],
id:'dbc1b4c900ffe48d575b5da5c638040125f65db0fe3e24494b76ea986457d906' }, CHARLIE:{ verificationVector:["0e4b8473bfe882f056d3ce4de2550b2f3415ec83b04fc9580656e74e308fa207730a126afe151feef1b505b3a00bc5939d6b55a622d47fdf3e71baabe614c89a","d6d8a177714216b4e4398fad40e17b6503fc7c06fc4b669e5010c4d5b0fe0c14e179ac57824d509f50dc233a00a5752de816dfb2c1aebaaafd8700310c9c4f08"],
shares:['4d941e9d6755581106df5189c54cffbc104709867f3c77078f3ac17c0880fc1e','cb00cad4e2c6d490d322ec0eb55ee7e381cd2e6a0e598eca12a1cf06a918791a','315dd8656357528f41e6140cf01b9f40cd01d1e2b4fafad40e706bc08aa45912'],
id:'084fed08b978af4d7d196a7446a86b58009e636b611db16211b65a9aadff2905' }, rootPub:'bedc88644f0deea4c0a77ba687712f494a1af7d8869f09768a0db42284f89d17b7b9225e0c87c2cb5511907dfd5eae3a53d789298721039e833770de29595880'
};const rootPubKey = crypto.tbls.deriveGroupPubTBLS([tblsAccounts.ALICE.verificationVector,tblsAccounts.BOB.verificationVector,tblsAccounts.CHARLIE.verificationVector]);
// ID of shard where you want to transfer KLY or call contractconstshardID='shard_0';// Default Ed25519constrecipient='6S4yLHorBUjSRjFpwxqPUXzwouZwR716CZ5uLmiy9Sze';constnonce=awaitweb1337.getAccount(shardID,rootPubKey).then(account=>account.nonce+1);constfee=1;constamountInKLY=13.37;consttxType="TX";constpayload= { to: recipient, amount: amountInKLY, shard:shardID};//_____________ GENERATE SIG_SHARES _____________constpartialSignatureOfFriend1=awaitweb1337.buildPartialSignatureWithTxData( shardID, txType,tblsAccounts.ALICE.id, [{secretKeyShare:tblsAccounts.ALICE.shares[0]},{secretKeyShare:tblsAccounts.BOB.shares[0]},{secretKeyShare:tblsAccounts.CHARLIE.shares[0]}],
nonce, fee, payload);constpartialSignatureOfFriend2=awaitweb1337.buildPartialSignatureWithTxData( shardID, txType,tblsAccounts.BOB.id, [{secretKeyShare:tblsAccounts.ALICE.shares[1]},{secretKeyShare:tblsAccounts.BOB.shares[1]},{secretKeyShare:tblsAccounts.CHARLIE.shares[1]}],
nonce, fee, payload);//_____________ BUILD TRANSACTION _______________constfinalTransaction=awaitweb1337.createThresholdTransaction( rootPubKey, txType, [partialSignatureOfFriend1,partialSignatureOfFriend2], nonce, fee, payload);console.log('============TBLS Transaction that can be deployed to network============\n');console.log(finalTransaction);
Output:
============TBLS Transaction that can be deployed to network============
{
v: 0,
creator: 'bedc88644f0deea4c0a77ba687712f494a1af7d8869f09768a0db42284f89d17b7b9225e0c87c2cb5511907dfd5eae3a53d789298721039e833770de29595880',
type: 'TX',
sigType: 'T',
nonce: 0,
fee: 1,
payload: {
to: '6S4yLHorBUjSRjFpwxqPUXzwouZwR716CZ5uLmiy9Sze',
amount: 13.37,
shard:"shard_0"
},
sig: 'bd602b821a12789cab6e191da09a813b6236fe3eb780a14c88d2a4d192b2221b'
}
TBLS => BLS(multisig address) transaction
The same for TBLs but remember about rev_t for new account
Tx structure should be like this:
============TBLS Transaction that can be deployed to network============
{
v: 0,
creator: 'bedc88644f0deea4c0a77ba687712f494a1af7d8869f09768a0db42284f89d17b7b9225e0c87c2cb5511907dfd5eae3a53d789298721039e833770de29595880',
type: 'TX',
sigType:'T',
nonce: 0,
fee: 1,
payload: {
to: '0x8f079049121d5e2ae885bdc6581df9fb68eab94a7aa3ae54bfe1d1ac35aceefbb202f656b0c1b56d64583630612a9970',
amount: 13.37,
shard:"shard_0",
rev_t: 2
},
sig: '3a985ce737b26c9217ca9e516c89cd83c0bb8be827cecf95449fee1f6d366081'
}