Closed lingyiliu016 closed 6 years ago
Have you looked at the multi sig contract?
I found some clues in Eosjs's ReadMe, but there are no examples.
Can you give me some suggestion about this? You don't have to give a complete example, just give the key point. Help me please.
@chris-allnutt I know how to complete a transaction in command line, but I don't know how to write a program by eosjs. Can you give me some suggestion?
Multi sig has 3 parts.
It's in the main repo under contracts eosio.msig
@chris-allnutt Are you referring to the code(C++) of eos?
Yes. You would have to look at the c++ contract, we don't provide any type of helper methods for this.
@chris-allnutt I want to know how to develop by eosjs. I know the theory of muti signature asynchronous . But I don't know how to call interface of cleos multisig by eosjs.
@chris-allnutt Can I understand that eosjs calls musisig just like calling the action of a normal contract?
for example:
cleos multisig propose boy.acnt '[{"actor":"girl.acnt","permission":"active"},{"actor":"boy.acnt","permission":"active"}]' '[{"actor":"girl.acnt","permission":"active"},{"actor":"boy.acnt","permission":"active"}]' genius.acnt borrow '{"tokenId":"1","borrower":"girl.acnt","lender":"boy.acnt"}' girl.acnt -p girl.acnt
multisig is contract ,propose is an action of contract, boy.acnt '[{"actor":"girl.acnt","permission":"active"},{"actor":"boy.acnt","permission":"active"}]' '[{"actor":"girl.acnt","permission":"active"},{"actor":"boy.acnt","permission":"active"}]' genius.acnt borrow '{"tokenId":"1","borrower":"girl.acnt","lender":"boy.acnt"}' girl.acnt -p girl.acnt
is parameter of propose?
It Maybe wrong!
Here is the code.
It means that propose has no parameter. so what is boy.acnt '[{"actor":"girl.acnt","permission":"active"},{"actor":"boy.acnt","permission":"active"}]' '[{"actor":"girl.acnt","permission":"active"},{"actor":"boy.acnt","permission":"active"}]' genius.acnt borrow '{"tokenId":"1","borrower":"girl.acnt","lender":"boy.acnt"}' girl.acnt -p girl.acnt
?
Cleos has options like: --print-request
.. cleos push action
has a --json and --dont-broadcast switch but since your using multisig I think you'll have to just live with --print-request
..
Turn that option on and you'll see everything cleos is doing for you and then you'll just need to put the transaction into eosjs..
I did what you said! The following is the details.
Firstly, I typed cleos --print-request multisig propose boy.acnt '[{"actor":"girl.acnt","permission":"active"},{"actor":"boy.acnt","permission":"active"}]' '[{"actor":"girl.acnt","permission":"active"},{"actor":"boy.acnt","permission":"active"}]' genius.acnt borrow '{"tokenId":"1","borrower":"girl.acnt","lender":"boy.acnt"}' girl.acnt -p girl.acnt
on the commend line terminal.( with --print-request)
Secondly I got the information as bellow.
Thirdly ,I read the eosio.msig.cpp file. Here is part of the content.
According to my understanding, calling msig propose is just calling a action of contract, So I just need to call the pose like calling a normal action. According to the above picture frame content, the action is propose, the parameter is proposer,proposal_name,requested and trx. is it right?just like the following picture(javascript)
I want to confirm whether my javascript content is right? give me an answer! Lastly I want to know the parameter of trx . As my understanding, the parameter of trx is the /v1/wallet/sign_transaction's parameters , is right? just as
so the right parameter of trx is
so the right program is
Is all right? To me, I need to calculate the parameter of trx.
As my understanding, the content of trx is /v1/wallet/sign_transaction, when I run javascript program , it means /v1/chain/push_transaction. is it right? @jcalfee So I just need to calculate ref_block_num、ref_block_prefix、actions.data. Your suggestion is important to me, thank you very much!
Turn off eosjs broadcast: false
then go to send a transaction as usual and you'll receive a transaction back that you can use in your trx proposal. You can turn off sign: false
too, after all it is a proposed transaction so I don't think you'll be signing it up-front. You may not need /v1/wallet/sign_transaction
at all unless you actually want a server to sign something. Also, to make it easy, try to use forceActionDataHex: false
so you can see the "data" as json instead of hex.
The source for parameters is the ABI. Look at the propose ABI action:
"actions": [{
"name": "propose",
"type": "propose",
"ricardian_contract": ""
},{
So that leads to the "propose" type (or struct): https://github.com/EOSIO/eos/blob/v1.1.3/contracts/eosio.msig/eosio.msig.abi#L56-L63
Also, this prints usage and example data in the console.log:
eos.contract('eosio.msig').then(msig => msig.propose())
You can run that command in the console here: https://jcalfee.github.io/eos.html
@jcalfee Your suggestion gave me great help, thank you very much. I did what you said. Here are some specific details.
This is the feedback of commandeos.contract('eosio.msig').then(msig => msig.propose())
at nodejs
I followed the prompts to write propose program.
when I write js program, I have some confusion. give me some suggestion How to understand "context_free_actions" and "actions" in "trx" ? What's the difference between "context_free_actions" and "actions"? Should I calculate "transaction_extensions"."data" or just null is ok?
When I run the program, error occurred! Details as follow!
"RangeError: Illegal offset: 0 <= 0 (+1) <= 0 action.data transaction.context_free_actions propose.trx action.data transaction.actions", I don't know what cause this error? how to solve it?
How to understand "context_free_actions" and "actions" in "trx" ? What's the difference between "context_free_actions" and "actions"? Should I calculate "transaction_extensions"."data" or just null is ok?
context_free_actions and context_free_actions can be removed or left as empty arrays..
Do you means that "context_free_actions" can be empty arrays and "transaction_extensions" can be empty arrays. Just as follow:
"trx": {
"expiration": "2018-08-09T10:02:39",
"ref_block_num": 45743,
"ref_block_prefix": 2268482204,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [
{
"account": "eosio.msig",
"name": "propose",
"authorization": [
{
"actor": "girl.acnt",
"permission": "active"
}
],
"data": "01000000000000000400000000000000289a01000000000004454f53000000000000c8131910af630000007922033c3d18e68891e8a681e4b9b0e4bda0e982a3e58faae7b2bee781b5"
}
],
"transaction_extensions": []
}
Is my understanding right?
I deployed a contract with the account market.acnt
,which contains trade
action . trade
is executed by multiple asynchronous signature.
Here are "proposer":"boy.acnt","proposal_name":"girl.acnt".
the parameters of trade is
'{
"id":"1",
"tokenId":"4",
"bidPrice":"10.5000 EOS",
"seller":"girl.acnt",
"buyer":"boy.acnt",
"memo":"I want to buy the bicycle"
}'
Here is the shell command cleos multisig propose girl.acnt '[{"actor":"girl.acnt","permission":"active"},{"actor":"boy.acnt","permission":"active"}]' '[{"actor":"girl.acnt","permission":"active"},{"actor":"boy.acnt","permission":"active"}]' market.acnt trade '{"id":"1","tokenId":"4","bidPrice":"10.5000 EOS","seller":"girl.acnt","buyer":"boy.acnt","memo":"I want to buy the bicycle"}' boy.acnt 100 -p boy.acnt
I compute the data(bin) by v1/chain/abi_json_to_bin, here is the command:
curl http://127.0.0.1:8888/v1/chain/abi_json_to_bin -X POST -d '{"code":"market.acnt", "action":"trade", "args":{"id": 1,"tokenId": 4,"bidPrice": "10.5000 EOS","seller": "girl.acnt","buyer": "boy.acnt","memo": "I want to buy the bicycle"}}'
and get the data: "01000000000000000400000000000000289a01000000000004454f53000000000000c8131910af630000007922033c3d19492077616e7420746f20627579207468652062696379636c65"
According to the definition of multisig propose abi and your suggestion, I write the program as follow:
eos.contract('eosio.msig').then(account => {
account.propose({
"proposer":"boy.acnt",
"proposal_name":"girl.acnt",
"requested":[
{"actor":"girl.acnt","permission":"active"},
{"actor":"boy.acnt","permission":"active"}
],
"trx": {
"expiration": "2018-08-11T15:28:57",
"ref_block_num": 0,
"ref_block_prefix": 0,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [
{
"account": "market.acnt",
"name": "trade",
"authorization": [
{
"actor": "girl.acnt",
"permission": "active"
},{
"actor": "boy.acnt",
"permission": "active"
}
],
"data": "01000000000000000400000000000000289a01000000000004454f53000000000000c8131910af630000007922033c3d19492077616e7420746f20627579207468652062696379636c65"
}
],
"transaction_extensions": []
}})
})
when I run the program by node.js, I got the error. The error is TypeError: Cannot read property 'abi' of undefined action.data transaction.actions propose.trx action.data transaction.actions
. I think the format of propose is right, but node prompts that it cannot be readed by 'abi',why? I cannot understand.
Here is the detail. give me some suggestion,please!
I considered eosio.multisig as an ordinary contract and call propose as calling an ordinary action, so at shell termial, I typed cleos push action eosio.msig propose propose_parameter1.json -p boy.acnt
, it runs successfully
I can also review the table data.
This is the content of propose_parameter1.json
{
"proposer":"boy.acnt",
"proposal_name":"girl.acnt",
"requested":[
{"actor":"girl.acnt","permission":"active"},
{"actor":"boy.acnt","permission":"active"}
],
"trx": {
"expiration": "2018-08-11T15:28:57",
"ref_block_num": 0,
"ref_block_prefix": 0,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [
{
"account": "market.acnt",
"name": "trade",
"authorization": [
{"actor": "girl.acnt","permission": "active"},
{"actor": "boy.acnt","permission": "active"}
],
"data": "01000000000000000400000000000000289a01000000000004454f53000000000000c8131910af630000007922033c3d19492077616e7420746f20627579207468652062696379636c65"
}
],
"transaction_extensions": []
}
}
here is eosjs function
eos.contract('eosio.msig').then(account => {
account.propose({
"proposer":"boy.acnt",
"proposal_name":"girl.acnt",
"requested":[
{"actor":"girl.acnt","permission":"active"},
{"actor":"boy.acnt","permission":"active"}
],
"trx": {
"expiration": "2018-08-11T15:28:57",
"ref_block_num": 0,
"ref_block_prefix": 0,
"max_net_usage_words": 0,
"max_cpu_usage_ms": 0,
"delay_sec": 0,
"context_free_actions": [],
"actions": [
{
"account": "market.acnt",
"name": "trade",
"authorization": [
{"actor": "girl.acnt","permission": "active"},
{"actor": "boy.acnt","permission": "active"}
],
"data": "01000000000000000400000000000000289a01000000000004454f53000000000000c8131910af630000007922033c3d19492077616e7420746f20627579207468652062696379636c65"
}
],
"transaction_extensions": []
}},options)
})
@jcalfee,one is executed successfully and another in eosjs runs failed! I think complicated parameters in propose cause this error! So maybe this is eosjs mechanism that cannot deal with complicated parameters . I hope you can give me the solution is eosjs,give me a example (call propose ) that can run successfully!
I was able to get a proposed transaction accepted on the Jungle net.
One "bug fix" was needed below (see comment). A default transaction header needed to be added. Fortunately there is a work-around below.
You should be able to open the web page: https://jcalfee.github.io/eos.html then open the web console and paste the following:
(async function() {
// `forceActionDataHex = false` is better for reading transactions but still fails with `get_required_keys`
createEos(Object.assign({}, {forceActionDataHex: true}, chain.jungle.costaricaeos))
function addKey(seed) {
const key = ecc.PrivateKey.fromSeed(seed)
console.log(seed, ecc.privateToPublic(key))
config.keyProvider.push(key)
}
addKey('testajungle1')
addKey('testajungle2')
const transfer = await eos.transfer('testajungle1', 'testajungle2', '1.0000 JUNGLE', '', {broadcast: false, sign: false})
transfer.transaction.transaction.max_net_usage_words = 0 // bug fix
console.log(transfer.transaction.transaction)
const msig = await eos.contract('eosio.msig')
const randomName = String(Math.round(Math.random() * 100000)).replace(/[0,6-9]/g, '')
const propose = await msig.propose('testajungle2', 'jungle.' + randomName, [{actor: 'testajungle1', permission: 'active'}], transfer.transaction.transaction)
console.info(propose)
})()
@jcalfee when I modify net_usage_words to max_net_usage_words ,almost transaction occurs error!
Error: Required varuint32 transaction_header.net_usage_words transaction.
when I modified max_net_usage_words to net_usage_words , it's ok!
So I think that I didn't need to modify net_usage_words to max_net_usage_words in eosjs-api/lib/exported-helpers.js
When I propose a multi signature action with transfer, it's ok!
eos.contract('eosio.msig').then( msig =>{
eos.transfer('boy.acnt', 'girl.acnt', '1.0000 EOS', '', {broadcast: false, sign: false}).then( transfer =>{
transfer.transaction.transaction.max_net_usage_words = 0;
transfer.transaction.transaction.expiration = new Date(Date.parse(new Date()) + 1000 * 60 * 3);
console.log(transfer.transaction.transaction);
msig.propose('boy.acnt','girl.acnt',[{"actor":"boy.acnt","permission":"active"}], transfer.transaction.transaction);
});
});
or
eos.contract('eosio.msig').then( msig =>{
eos.contract('eosio.token').then(token =>{
token.transfer('boy.acnt', 'girl.acnt', '1.0000 EOS', '', {broadcast: false, sign: false}).then( transfer =>{
transfer.transaction.transaction.max_net_usage_words = 0;
transfer.transaction.transaction.expiration = new Date(Date.parse(new Date()) + 1000 * 60 * 3);
console.log(transfer.transaction.transaction);
msig.propose('boy.acnt','girl.acnt',[{"actor":"boy.acnt","permission":"active"}], transfer.transaction.transaction);
});
});
});
But when I propose a multi signature with my own action, it failed!
eos.contract('eosio.msig').then( msig => {
eos.contract('market.acnt').then(market => {
market.trade1('4','4','10.5000 EOS','girl.acnt','boy.acnt','hello, selling bicycle',{authorization:'girl.acnt@active'}).then( trade =>{
trade.transaction.transaction.max_net_usage_words = 0;
trade.transaction.transaction.expiration = new Date(Date.parse(new Date()) + 1000 * 60 * 10);
console.log(trade.transaction.transaction);
msig.propose('boy.acnt','girl.acnt',[{"actor":"boy.acnt","permission":"active"},{"actor":"girl.acnt","permission":"active"}], trade.transaction.transaction);
});
});
});
The following is the details.
Here is my config.
config = {
chainId:'313da49a1f6c194fffe8a38122c8952f46f14e5ca5e1b037510004da1bfe1832',
keyProvider:[
'5KQwrPbwdL6PhXujxW37FSSQZ1JiwsScqQzDeyXtP79zkvFD3',
'5K463ynhZoCDDa4RDcr63cUwWLTnKqmdcKTHBjqoKfv4u5V7p',
'5KcHE3HF4zAecKWFxBiizG3KBPpkBxbbMDAnPeHQZecy69bZy'
],
httpEndpoint:'http://127.0.0.1:8888',
expireInSeconds:60,
broadcast:true,
verbose:false,
sign:true,
forceActionDataHex: true,
logger:{},
network:{api:{}},
abiCache:{}
}
Why it resports config.abiCache.abi is not a function
with my own action(trade1) of contract, but everything is ok with transfer of eosio.token?
@jcalfee I'm very confused! Why my action in multi signature failed! but transfer is ok! they are almost similar! give me some suggestion, too.
@jcalfee I think config cause the problem. it's part of the struct.js
it's the cause of why transfer of eosio.token can be executed successfully, but trade1 of market.acnt is executed unsuccessfully So I need to configure the config.abiCache.abi rightly! but I don't know how to configure it.
@jcalfee Hope you can give me a example. Thank you very much!
@jcalfee I solved this problem. when I have no idea , I find abiCache
in issue, Fortunately, I found the solution at https://github.com/EOSIO/eosjs/issues/260. It saids eosjs solve the issue that abiCache doesn't work in version 16.00. So I npm install eosjs
again, the program run successfully!
Thank you very much! have a good day!
I think you were deleting the abiCache by having too many config options. You should remove these from your config. Some are internal and logger is not custom so you don't need it:
logger:{},
network:{api:{}},
abiCache:{}
@jcalfee multisig propose cannot add authorization Here is my eosjs program
eos.contract('eosio.msig').then( msig => {
eos.contract('market.acnt').then(market => {
market.trade1('7','4','10.5000 EOS','boy.acnt','girl.acnt','hello, selling ',{broadcast: false, sign: false}).then( trade =>{
trade.transaction.transaction.max_net_usage_words = 0;
trade.transaction.transaction.expiration = new Date(Date.parse(new Date()) + 1000 * 60 * 10);
console.log(trade.transaction.transaction);
msig.propose('girl.acnt','boy.acnt',[{"actor":"boy.acnt","permission":"active"},{"actor":"girl.acnt","permission":"active"}], trade.transaction.transaction);
});
});
});
here is the result.
But when I call my own action with propose, authorization is null, I'm very confused! Here is my program.
eos.contract('eosio.msig').then( msig => {
eos.contract('market.acnt').then(market => {
market.trade1('7','4','10.5000 EOS','boy.acnt','girl.acnt','hello, selling ',{broadcast: false, sign: false}).then( trade =>{
trade.transaction.transaction.max_net_usage_words = 0;
trade.transaction.transaction.expiration = new Date(Date.parse(new Date()) + 1000 * 60 * 10);
console.log(trade.transaction.transaction);
msig.propose('girl.acnt','boy.acnt',[{"actor":"boy.acnt","permission":"active"},{"actor":"girl.acnt","permission":"active"}], trade.transaction.transaction);
});
});
});
Here is the result.
@jcalfee give me some solution.
Add it in the market.trade
in the options with sign, and broadcast:
market.trade1('7','4','10.5000 EOS','boy.acnt','girl.acnt','hello, selling ',
{broadcast: false, sign: false, authorization: {actor: account, permission: 'active'}}).then( trade =>{
approve a proposal:
eos.contract('eosio.msig').then(function (contract) {
contract.approve(proposer, proposalName, {
"actor": accountName,
"permission": "active"
}, {"authorization": accountName + "@active"}).then(function () {
console.log('success');
});
});
When I run this piece of code.
const Eos = require('eosjs');
var eosOnline = Eos({
httpEndpoint: "http://jungle.iryo.network:8888",
//httpEndpoint: "http://jungle.cryptolions.io:38888",
keyProvider: 'key',
broadcast: false,
sign: true,
//verbose: true,
//debug: true,
});
eosOnline.contract('eosio.msig').then(msig => console.log(msig));
I get this error
(node:7216) UnhandledPromiseRejectionWarning: Error: [
"Missing checksum256$ in approve.fields.proposal_hash"
]
at module.exports (/home/rahil.shaikh/blockchain/eosmultisig/node_modules/eosjs/lib/structs.js:141:11)
at abi (/home/rahil.shaikh/blockchain/eosmultisig/node_modules/eosjs/lib/abi-cache.js:63:21)
at /home/rahil.shaikh/blockchain/eosmultisig/node_modules/eosjs/lib/abi-cache.js:46:14
at process._tickCallback (internal/process/next_tick.js:68:7)
(node:7216) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejectinga promise which was not handled with .catch(). (rejection id: 1)
(node:7216) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
@jcalfee can you help here?
When I run this piece of code.
const Eos = require('eosjs'); var eosOnline = Eos({ httpEndpoint: "http://jungle.iryo.network:8888", //httpEndpoint: "http://jungle.cryptolions.io:38888", keyProvider: 'key', broadcast: false, sign: true, //verbose: true, //debug: true, }); eosOnline.contract('eosio.msig').then(msig => console.log(msig));
I get this error
(node:7216) UnhandledPromiseRejectionWarning: Error: [ "Missing checksum256$ in approve.fields.proposal_hash" ] at module.exports (/home/rahil.shaikh/blockchain/eosmultisig/node_modules/eosjs/lib/structs.js:141:11) at abi (/home/rahil.shaikh/blockchain/eosmultisig/node_modules/eosjs/lib/abi-cache.js:63:21) at /home/rahil.shaikh/blockchain/eosmultisig/node_modules/eosjs/lib/abi-cache.js:46:14 at process._tickCallback (internal/process/next_tick.js:68:7) (node:7216) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejectinga promise which was not handled with .catch(). (rejection id: 1) (node:7216) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
@jcalfee can you help here?
I have this question too in BOS , please help us . @jcalfee
Not sure where this "$" in "checksum256$" is coming from. This may be related: https://github.com/jcalfee/eosjc/issues/4
$ is a binary extension, introduced in ABI 1.1
I was able to get a proposed transaction accepted on the Jungle net.
One "bug fix" was needed below (see comment). A default transaction header needed to be added. Fortunately there is a work-around below.
You should be able to open the web page: https://jcalfee.github.io/eos.html then open the web console and paste the following:
(async function() { // `forceActionDataHex = false` is better for reading transactions but still fails with `get_required_keys` createEos(Object.assign({}, {forceActionDataHex: true}, chain.jungle.costaricaeos)) function addKey(seed) { const key = ecc.PrivateKey.fromSeed(seed) console.log(seed, ecc.privateToPublic(key)) config.keyProvider.push(key) } addKey('testajungle1') addKey('testajungle2') const transfer = await eos.transfer('testajungle1', 'testajungle2', '1.0000 JUNGLE', '', {broadcast: false, sign: false}) transfer.transaction.transaction.max_net_usage_words = 0 // bug fix console.log(transfer.transaction.transaction) const msig = await eos.contract('eosio.msig') const randomName = String(Math.round(Math.random() * 100000)).replace(/[0,6-9]/g, '') const propose = await msig.propose('testajungle2', 'jungle.' + randomName, [{actor: 'testajungle1', permission: 'active'}], transfer.transaction.transaction) console.info(propose) })()
Would you be able to update this example to use eosjs v20.0.0 ? I am dying to figure this out.
I am also trying to do this using EOSJS V20. Not straight forward.
When making a trade on line, this trade often requires multiple signatures asynchronously. I read your eosjs example, but I didn't found any of multiple asynchronous signature example. I don't know how to write this program ,so give me a example about this topic ,please! Thank you very much! Let me describe scene of trade: Sellers sell goods on the market, when the buyer see the goods that he needs, he want to buy it. The market is similar to an online mall, Buyers and sellers can't see each other. Let me describe this scene in more detail. Tom want to sell his bicycle on an online mall, Kate want to buy this bicycle at web. but closIng this deal needs Tom's signature and Kate's signature. Firstly Kate initiated a request that need Tom's signature and Kate's signature, Kate then signed this deal. The website reminds Tom that this deal needs to be signed in 1 hour, Tom signed the deal 10 minutes later. Lastly Tom submitted this trade at web. so deal closed. Tom selled this bicycle and got 10 dollars, and Kate get the bicycle and payed 10 dollars. The above scenario has been implemented through the command line now. here is command: Firstly,
cleos multisig propose Tom '[{"actor":"Kate","permission":"active"},{"actor":"Tom","permission":"active"}]' '[{"actor":"Kate","permission":"active"},{"actor":"Tom","permission":"active"}]' contract_setter trade '{"bicycleId":"1","buyer":"Kate","seller":"Tom"}' Kate -p Kate
Secondly,cleos multisig approve Tom Kate '{"actor":"Kate","permission":"active"}' -p Kate
Thirdly,cleos multisig approve Tom Kate '{"actor":"Tom","permission":"active"}' -p Kate
Lastly,cleos multisig exec Tom Kate Tom