-
Notifications
You must be signed in to change notification settings - Fork 85
Wallet API Guide
https://docs.rs/grin_wallet_api/2.0.0/grin_wallet_api/
RECENT CHANGES:
- (30 Jun 2019) Obsoleted since Grin Wallet v2.0.0
- (7 Feb 2019) Creation for Grin v1.0.x
- General Information
- Wallet Sending via API
- Wallet Query via API
- How to Collaborate Send/Receive and Query/Cancel/Post
- Some Special Use Cases
This doc is for the Grin wallet API practical usage guide, not the wallet API doc. For detailed wallet APIs reference, please read doc Wallet Owner API and Wallet Foreign API.
By default, the wallet configuration file ~/.grin/main/grin-wallet.toml
will be automatically generated on the 1st run of grin-wallet
. Floonet configuration is stored in a separate directory (~/.grin/floo
).
Note: On all following introductions, I will only write main
for mainnet. If you're runing Floonet, please remember to replace main
as floo
.
Some default configuration need to be modified according to your practical requirements:
#Floonet - For the long term Floonet test network
chain_type = "Mainnet"
Please double check the chain_type
here is configured as Mainnet
.
Floonet
is only for the test network.
#host IP for wallet listener, change to "0.0.0.0" to receive grins
api_listen_interface = "0.0.0.0"
And remember to double check the listening interface after you start wallet listening:
netstat -tlna | grep 3415
For example, my output is:
tcp 0 0 127.0.0.1:3415 0.0.0.0:* LISTEN
that means my wallet's listening on localhost only.
Note: For send-only wallet, it's OK to keep api_listen_interface = "127.0.0.1"
as the default configuration for it.
On the 1st time running of grin, a random API secret will be generated into ~/.grin/main/.api_secret
file. You can use your own secret but please make sure using some kinds of password generator to ensure this secret has enough complexity.
#path of the secret token used by the API to authenticate the calls
#comment it to disable basic auth
#api_secret_path = "/home/garyyu/.grin/main/.api_secret"
#location of the node api secret for basic auth on the Grin API
#node_api_secret_path = "/home/garyyu/.grin/main/.api_secret"
#where the wallet should find a running node
check_node_api_http_addr = "http://127.0.0.1:3413"
These are my configurations, and yours should be different on the home directory name.
As you see, I disabled the wallet API secret, this disable is ONLY for the following demos (for simple) and this API secret is strongly suggested on the production environment. Same for the node API secret. (node
means a Grin server)
Regarding the check_node_api_http_addr
, in my case I have a Grin server running on same server, so I can use "http://127.0.0.1:3413"
. If you're using an external Grin server, you can modify this to point to your Grin server. 3413
is the default node API port.
For the wallet which is listening on external network interface, it's a MUST to enable the https, unless you know exactly what you're doing by HTTP!
To enable https, we only need to configure the following TLS certificate files:
#path of TLS certificate file, self-signed certificates are not supported
tls_certificate_file = "/etc/letsencrypt/live/demo.grin.icu/fullchain.pem"
#private key for the TLS certificate
tls_certificate_key = "/etc/letsencrypt/live/demo.grin.icu/privkey.pem"
Please replace these files with your own TLS certificate files.
If you want to use letsencrypt
like me, you can refer to the Wallet TLS Setup Guide.
BTW, we will do some enhancement on this in the future, refer to #2523 for the detail.
By default, grin wallet will create wallet data folder in ~/.grin/main/wallet_data
. And you can modify this folder as you want, to put wallet_data
into any location.
#where to find wallet files (seed, data, etc)
data_file_dir = "/home/garyyu/.grin/main/wallet_data"
In this wallet_data
, you will find 3 types of files:
- wallet database files: lmdb database.
- wallet.seed: the encrypted wallet seed file.
- saved_txs: the folder to save those raw transaction data, in file format, with the
Shared Transaction Id
(i.e. an UUID) as the file name. Note: only those sending transactions have the correspondingsaved_txs
file, and the purpose of this saved raw transaction data is forreposting
, in case any failure of previouspost_tx
.
Here is an example in this `wallet_data` folder: (Click to expand)
$ tree ~/.grin/main/wallet_data/
/home/garyyu/.grin/main/wallet_data/
├── db
│ └── lmdb
│ ├── data.mdb
│ └── lock.mdb
├── saved_txs
│ ├── 205d9cde-af28-44ff-b425-3be4a7e939dd.grintx
│ ├── 4caee644-f8d1-4f5c-b3af-f11de5a41586.grintx
│ ├── 507aa335-246d-4d6c-84bb-2516fb8e44ac.grintx
│ ├── 78efaa87-f7c2-4fde-a14b-68338f9c32fd.grintx
│ ├── 8ba033b6-3e05-4cad-81ec-937f3056b1e8.grintx
│ ├── 8d2fc370-b442-41a5-b889-715a1dae9cf2.grintx
│ ├── 8e298bd0-2bd5-4184-a810-3d0a9f6086b8.grintx
│ ├── a063be0e-7523-4a1c-a993-ae3592c10191.grintx
│ ├── b55a062a-32b4-45d1-b4d9-f921f922555a.grintx
│ └── edea1387-a797-4a50-92b5-4cdadfae6052.grintx
└── wallet.seed
I suggest to enable both stdout and file log, as follows. And stdout_log_level = "Info"
, the "Info" level is better than "Warning" level for stdout, because with this you will get some immediate useful feedbacks when using some grin wallet command.
#whether to log to stdout
log_to_stdout = true
#log level for stdout: Error, Warning, Info, Debug, Trace
stdout_log_level = "Info"
#whether to log to a file
log_to_file = true
#log level for file: Error, Warning, Info, Debug, Trace
file_log_level = "Debug"
Before we can call the following wallet API, we need run a grin wallet listening on owner api:
$ grin-wallet owner_api
Note: please run this grin-wallet owner_api
command from a designed folder and which folder will also be used to store some possible temporary files (when using file
method).
Construct a JSON format parameters.
For example:
{
"amount": 110000000,
"minimum_confirmations": 10,
"method": "http",
"dest": "https://demo.grin.icu:3415",
"max_outputs": 500,
"num_change_outputs": 1,
"selection_strategy_is_use_all": true
}
For the detailed parameter description, please refer to issue_send_tx API doc.
Some additional notes on above parameters:
-
amount
is using Nano Grin as unit, i.e. 10^-9 Grin. For example, the amount110000000
here means0.11
Grin coins. - both https and https share the same
method
name:http
. -
"dest": "https://demo.grin.icu:3415"
here is using https. If you need use http, just modify the url ashttp://...
. - For a simple case, normally we have one change output for self and another output for payee, that's why in this example I set
"num_change_outputs": 1
. -
"selection_strategy_is_use_all": true
is the proposed setting (to make the chain has the minimum UTXO sets). But if you have multiple payments need to be done quickly, you can set it asfalse
. Because withtrue
, we will get all the balance locked until current transaction is confirmed on the chain (that's 10 blocks or about 10 minutes). With"selection_strategy_is_use_all": false
, only part of UTXOs (sum up to be able to pay the amount) will be used. -
"max_outputs"
here means the maximum UTXOs can be used for this transaction. And it's a soft limit, when this is not enough to cover the whole output amount, the wallet will include more outputs. The proposed value here is500
.
Call the issue_send_tx
API with above parameters.
Let's use curl
for a demo here on calling this API, if we save above JSON parameters into a file issue_send_tx-1.json
:
$ data=`cat issue_send_tx-1.json`; curl -0 -XPOST http://127.0.0.1:3420/v1/wallet/owner/issue_send_tx -d "$data" 2>/dev/null | jq
Note: In production environment with API secret, the above curl
would be curl -0 -XPOST -u grin:"$api_secret" http://...
, i.e. add -u grin:password
.
The output example: (Click to expand)
{
"num_participants": 2,
"id": "8ba033b6-3e05-4cad-81ec-937f3056b1e8",
"tx": {
"offset": [...],
"body": {
"inputs": [
{
"features": "Plain",
"commit": [...],
}
],
"outputs": [
{
"features": "Plain",
"commit": [...],
"proof": [...],
},
{
"features": "Plain",
"commit": [...],
"proof": [...],
}
],
"kernels": [
{
"features": "HeightLocked",
"fee": 8000000,
"lock_height": 18187,
"excess": [...],
"excess_sig": [...],
}
]
}
},
"amount": 110000000,
"fee": 8000000,
"height": 18187,
"lock_height": 18187,
"participant_data": [
{
"id": 0,
"public_blind_excess": [...],
"public_nonce": [...],
"part_sig": [...],
"message": null,
"message_sig": null
},
{
"id": 1,
"public_blind_excess": [...],
"public_nonce": [...],
"part_sig": [...],
"message": null,
"message_sig": null
}
]
}
Call the post_tx
API with above outputs from 2nd step. Refer to detailed info in Post Tx API Doc.
Suppose we save above JSON format output as a file post_tx_1.json
, then, let's still use curl
to simulate this API call:
$ data=`cat post_tx-1.json`; curl -0 -XPOST http://127.0.0.1:3420/v1/wallet/owner/post_tx?fluff -d "$data" 2>/dev/null
Note: In above usage demo, I use ?fluff
to bypass the Dandelion relay, but it's not proposed.
Then, in normal case, a wallet sending (payment) is done. We will discuss how to handle the exception cases in How to Collaborate Sending and Query.
For some use cases, the file
method is useful. For example, payment by email, or by file download/upload plus a finalize
step, in which case the user will login to the website and request a payout, and then download a raw transaction file, then execute a receive
on his/her local Grin wallet, and then upload the output file, and the website will call the finalize
once the uploading is completed, and call the last step post
. Payment by email is similar.
Construct a JSON format parameters.
For example:
{
"amount": 120000000,
"minimum_confirmations": 10,
"method": "file",
"dest": "file1.json",
"max_outputs": 500,
"num_change_outputs": 1,
"selection_strategy_is_use_all": true
}
Note: the generated file file1.json
will be in the same folder as you run the grin-wallet owner_api
.
This should be executed by the payment receiver! Remember that the Grin transaction is an interactive procedure.
Suppose the payee already downloaded the file file1.json
, and ask him/her to run following command on his local wallet:
$ grin-wallet receive -i file1.json
and this command will generate file file1.json.response
, in the same folder as file1.json
.
Then the payee need upload this file1.json.response
file to the payer.
Once the payer received above uploaded file file1.json.response
, call the finalize_tx
API with the file. For detailed info about this API, refer to finalize_tx API Doc.
Still use curl
to simulate this API call:
$ data=`cat file1.json.response`; curl -0 -XPOST http://127.0.0.1:3420/v1/wallet/owner/finalize_tx -d "$data" 2>/dev/null | jq
The output format is similar as the output of issue_send_tx
API output, so I will not paste here.
We need call the post_tx
API with the finalize_tx
API outputs from 3rd step. Refer to detailed info in Post Tx API Doc.
Suppose we save above JSON format output as a file post_tx_2.json
, then, let's still use curl
to simulate this API call:
$ data=`cat post_tx-2.json`; curl -0 -XPOST http://127.0.0.1:3420/v1/wallet/owner/post_tx?fluff -d "$data" 2>/dev/null
Same comments as before about the ?fluff
.
Then, in normal case, a wallet sending (payment) is done. We will discuss how to handle the exception cases in How to Collaborate Sending and Query.
Grin wallet support Keybase plugin method, using Keybase encrypted private communication channel as a safe transmitting tool. It's a better method that Http/s for those users whose grin wallet is under NAT and hard to open a port on router or firewall, and easy to use. And comparing to File
method, this Keybase
method is more efficient because it's a realtime processing.
To use Keybase plugin, both the sender and the receiver must have Keybase installed and running, and of course a Keybase account is needed and keep it login. Propose to use keybase status
command to double check the following status of keybase, before sender start making a payment with keybase method:
$ keybase status
The output should contains the following:
...
Logged in: yes
Device:
...
status: active
Service:
status: running
The steps of using this keybase
method to make a payment are almost same as HTTP/s method, the difference is:
- The receiver must have grin wallet listening on keybase plugin.
$ grin-wallet listen -m keybase
- The constructed JSON format parameters for the 1st step is a little bit different:
For example:
{
"amount": 150000000,
"minimum_confirmations": 10,
"method": "keybase",
"dest": "gringod",
"max_outputs": 1,
"num_change_outputs": 1,
"selection_strategy_is_use_all": false
}
Note:
"method": "keybase"
-
dest
here must fill the receiver's keybase account name, for examplegringod
here in above example.
then, for the 2nd step (call the issue_send_tx
API with above parameters) and the 3rd step (call post_tx
API to post the transaction to the chain) are same as HTTP/s method.
Important Notes for Keybase method:
- For saving the CPU load, the Keybase communication channel polling has a long interval (about 5 seconds) by default, and a long TTL (about 60 seconds), so it's not efficient if you need call a payment frequently especially in batch payment case.
- But these timers can be adapted for much better performance in this special use case, please contact us if need further suggestions on this.
We can use retrieve_txs
API for transactions query, normally this is the 1st step in a query, if we start from the Shared Transaction Id
(i.e. wallet transaction UUID). For detail info of this API, refers to retrieve_txs API doc.
Let's simulate this API call with curl
:
$ curl -0 -XGET http://127.0.0.1:3420/v1/wallet/owner/retrieve_txs?tx_id=e2195b2c-9fd5-442b-86ce-8c7693671484 2>/dev/null | jq
The output example for above command: (Click to expand)
[
false,
[
{
"parent_key_id": "0200000000000000000000000000000000",
"id": 0,
"tx_slate_id": "e2195b2c-9fd5-442b-86ce-8c7693671484",
"tx_type": "TxReceived",
"creation_ts": "2019-01-28T00:01:00.122919Z",
"confirmation_ts": null,
"confirmed": false,
"num_inputs": 0,
"num_outputs": 1,
"amount_credited": 1000000000,
"amount_debited": 0,
"fee": null,
"stored_tx": null
}
]
]
Note:
- The
tx_id
here is theShared Transaction Id
for wallet, it's a local generated random UUID, and this UUID is not stored in the blockchain (please don't mix it with Bitcoin/Ethereum TxId concept). - When using wallet API for payment, it's important to cache this UUID, so as to query the transaction status with this UUID, for example using it here.
- In this example, it's a
TxReceived
transaction, so some fields are invalid such asnum_inputs
,fee
, andstored_tx
. As you see, this transaction status is"confirmed": false
, that means it's pending on payer side to post it.
Let's take another example here for a TxSent
transaction:
$ curl -0 -XGET http://127.0.0.1:3420/v1/wallet/owner/retrieve_txs?tx_id=8e298bd0-2bd5-4184-a810-3d0a9f6086b8 2>/dev/null | jq
The output example for above command: (Click to expand)
[
false,
[
{
"parent_key_id": "0200000000000000000000000000000000",
"id": 1,
"tx_slate_id": "8e298bd0-2bd5-4184-a810-3d0a9f6086b8",
"tx_type": "TxSent",
"creation_ts": "2019-01-28T00:23:20.025622Z",
"confirmation_ts": "2019-01-28T00:28:23.305599Z",
"confirmed": true,
"num_inputs": 1,
"num_outputs": 1,
"amount_credited": 892000000,
"amount_debited": 1000000000,
"fee": 8000000,
"stored_tx": "8e298bd0-2bd5-4184-a810-3d0a9f6086b8.grintx"
}
]
]
Note:
- For
TxSent
type transactions, thestored_tx
contains the file name which stored the raw transaction data, the file location is in~/.grin/main/wallet_data/saved_txs
by default. -
fee
is the transaction fee of this transaction.0.008
Grin is a typical fee for a transaction with 1 input and 2 outputs (1 change plus 1 output for receiver). -
amount_debited
is the sum of all inputs amount. It's1.0
Grin in this example. -
amount_credited
is the your own change output amount. It's0.892
Grin in this example, andamount_debited - amount_credited - fee
is the paid amount in this transaction. -
"confirmed": true
here just means this transaction has been picked up in the chain, you still need check the output status to get the confirmation numbers, withretrieve_outputs
API. -
"id": 1
refers to thetx_log_entry
, which will be used forretrieve_outputs
API (next chapter).
We can use retrieve_outputs
API for outputs query, normally this is the 2nd step in a query, if we start from the Shared Transaction Id
(i.e. wallet transaction UUID). For detail info of this API, refers to retrieve_outputs API doc.
To simulate this API call with curl
:
$ curl -0 -XGET http://127.0.0.1:3420/v1/wallet/owner/retrieve_outputs?refresh\&show_spent\&tx_id=1 2>/dev/null | jq
In this example, we query the transaction with tx_log_entry = 1
, and with refresh
to refresh the transaction status from Grin server (node) with node API, and with show_spent
to show the Input(s)
of this transaction.
The output example for above command: (Click to expand)
[
true,
[
[
{
"root_key_id": "0200000000000000000000000000000000",
"key_id": "0300000000000000000000000000000000",
"n_child": 0,
"commit": "090ece191f5e29c1ab07cdf8f51a0e464d0d4bab3eeeeb01ffaf106f09e33ade98",
"mmr_index": null,
"value": 1000000000,
"status": "Spent",
"height": 17587,
"lock_height": 0,
"is_coinbase": false,
"tx_log_entry": 1
},
[...(33 bytes commit data)...]
],
[
{
"root_key_id": "0200000000000000000000000000000000",
"key_id": "0300000000000000000000000400000000",
"n_child": 4,
"commit": "0888738231e755c348b512e681b6147c6d4f37e8d7054d2ffc700d7ea38c945341",
"mmr_index": null,
"value": 892000000,
"status": "Unspent",
"height": 17609,
"lock_height": 0,
"is_coinbase": false,
"tx_log_entry": 1
},
[...(33 bytes commit data)...]
]
]
]
Note:
- In this example, the input commitment and output commitment can be found in the explorer.
- You can find this transaction in block 17609.
- In this example, the input is
1.0
Grin coin, and the output (it's the change output here) is0.892
Grin coin, where's another leg? :) the answer is theretrieve_outputs
wallet API is used to retrieve your own outputs! and the status (confirmed / unconfirmed) of another leg (or other outputs) is same as your own change output, because all outputs in one transaction share same transaction kernel, i.e. they're in same transaction. - Then, how to query the outputs you sent to receiver? the answer is:
retrieve_stored_tx
API, we will show the usage in next section. - Please note that, for your own outputs, there're two types: one is spent output, another is unspent output (i.e. UTXO). To avoid showing a long history, the
grin-wallet outputs
command will only show theLocked | Unspent | Unconfirmed
outputs by default. We can use-s
option to show also thespent
outputs, i.e.grin-wallet -s outputs
, to get same result as in this example. - For spent outputs, another note is: it will be bound to same
tx_log_entry
as the spent transaction. In this example, you can see thetx_log_entry=1
and it include both your spent output/s (i.e. Input/s) and your change output/s. - The first element
true
is the validated status. Withrefresh
parameter in this API call, thistrue
means the output status is validated on the chain, via node API. - The returned value looks like not in a pure JSON format, this could deserve an improvement in the future, will submit an issue on this (if not having). And the
[...(33 bytes commit data)...]
part is the duplication of"commit"
.
And regarding the output status, totally we have 4 status:
- Unconfirmed
- Unspent
- Locked
- Spent
With retrieve_txs
API, we can get something like "confirmed": true
for a transaction status. And with retrieve_outputs
API, we can get something like "status": "Unspent"
for an output status. But an important concept for blockchain transaction is the confirmations, that means how many consequent blocks have been mined after this transaction included in one block.
So, both above "confirmed": true
and "status": "Unspent"
just means the outputs have been included in the chain, and we still need query the confirmations
for this transaction / output, normally this is the 3rd step in a query, if we start from the Shared Transaction Id
(i.e. wallet transaction UUID).
To query the confirmations of an output, propose to use node API chain/outputs/byids
with the unspent output commitment, normally this "unspent output" is either the change output
in a sending transaction, or the received output in a receiving transaction. And please remember you can't query a spent output commitment on the chain, because of MimbleWimble cut-through feature.
For example:
Suppose we got an unspent output commitment with retrieve_outputs
API:
$ curl -0 -XGET http://127.0.0.1:3420/v1/wallet/owner/retrieve_outputs?refresh\&show_spent\&tx_id=9 2>/dev/null | jq
part of the outputs:
{
"root_key_id": "0200000000000000000000000000000000",
"key_id": "0300000000000000000000000e00000000",
"n_child": 14,
"commit": "08cef2eee0ee9b8ff79d3fabf63da57e520255c749553c2ac72b874c1e8d7a02cb",
"mmr_index": null,
"value": 174333334,
"status": "Unspent",
"height": 32344,
"lock_height": 0,
"is_coinbase": false,
"tx_log_entry": 9
},
Repeat step 1 until its status
becomes Unspent
, then we call node API chain/outputs/byids
with this commit
to query whether it's still on the chain:
$ curl -0 -XGET http://127.0.0.1:3413/v1/chain/outputs/byids?id=08b5c829f81cdf2a1f600517907607f22591ef96673b1145f6b5d0eda425cb4df8 2>/dev/null | jq
The output of above query:
[
{
"commit": "08b5c829f81cdf2a1f600517907607f22591ef96673b1145f6b5d0eda425cb4df8",
"height": 32344,
"mmr_index": 646506
}
]
Note: for the details of this node API, please refer to Node API Doc.
Repeat step 2 (in every minute for example) until the node height is high enough, i.e. node_height - output_height > minimum_confirmations
.
output_height
is 32344
in this example.
minimum_confirmations
can be your self configuration, at this moment, the proposed minimum confirmations value is 10
.
And we can query node_height
by node_height
API:
$ curl -0 -XGET http://127.0.0.1:3420/v1/wallet/owner/node_height 2>/dev/null | jq
At this moment (when writing this wiki), the output could be:
[
34191,
true
]
When node_height - output_height > minimum_confirmations
is true, the query loop can stop and the output status is finalized.
Note: for the details of this API, please refer to Node Height API Doc.
To get the same info as the grin-wallet info
command, we can use retrieve_summary_info
API.
$ curl -0 -XGET http://127.0.0.1:3420/v1/wallet/owner/retrieve_summary_info?refresh\&minimum_confirmations=10 2>/dev/null | jq
An example output:
[
true,
{
"last_confirmed_height": 32427,
"minimum_confirmations": 10,
"total": 118125000000,
"amount_awaiting_confirmation": 0,
"amount_immature": 0,
"amount_currently_spendable": 118125000000,
"amount_locked": 0
}
]
And compare it with the command grin-wallet info
:
$ grin-wallet info --min_conf=10
Password:
____ Wallet Summary Info - Account 'default' as of height 32427 ____
Total | 118.125000000
Awaiting Confirmation (< 10) | 0.000000000
Locked by previous transaction | 0.000000000
-------------------------------- | -------------
Currently Spendable | 118.125000000
In production environment, there're always some exception cases which sending/receiving can't finish. The possible reasons here but not limited:
- For Sending
- The receiver is not ready to receive, such as wallet is not listening, unreachable under NAT, etc.
- The transaction posting failed for some reasons, so the transaction status stays in
Unconfirmed
for ever.
- For Receiving
- The sender didn't finish the remaining steps (i.e.
finalize
andposting
) of a transaction, so the received output always shows asUnconfirmed
. - The sender double spent an output.
- The sender didn't finish the remaining steps (i.e.
On these exception cases, we need call cancel_tx
or post_tx
API, depending on the actual query status. For query steps, please refer to Transaction/Output Confirmation Query.
For an Unconfirmed
sending transaction, we can call cancel_tx
API to cancel it. Refer to Cancel Tx API Doc for detail.
An example to call this API:
$ curl -0 -XPOST http://127.0.0.1:3420/v1/wallet/owner/cancel_tx?id=2 2>/dev/null | jq
To avoid the racing exception, either you're sure this transaction can't finish, or waiting enough time before you cancel it.
For an Unconfirmed
sending transaction, if you make sure the previous posting doesn't work (for example you already waited 2 minutes but the transaction status is still Unconfirmed
), you can call repost
API to try re-posting it to the chain. The re-posting is a safe operation.
In case of this transaction is already included on the chain, the repost
API will get 500 Internal Server Error
, with an error message failed to validate tx
.
For detail of this repost
API, refer to Repost API Doc.
To simulate this API call here with curl
:
$ curl -0 -XPOST http://127.0.0.1:3420/v1/wallet/owner/repost?id=2 2>/dev/null
And you can use UUID instead of the entry id. Also, the fluff
parameter is feasible here.
This API is identical to the command grin-wallet repost
, refer to repost command usage.
For example, in mining pool use case, we could setup an automatic payout on a scheduled periodic time, and we need make hundred/thousand payments in one time. Surely there're also a lot of other similar batch payment use cases like this.
The batch payment (i.e. multiple receivers for one transaction) feature is planed in the future release. At this moment (for version 1.0.x), we only can pay one receiver for one transaction.
Because we need wait 10 confirmations (suppose we set minimum_confirmations=10
) for each transaction, the wallet balance will be locked for about 10 minutes after we did one transaction. That's quite inconvenient and inefficient for batch payment use case.
But we have a workaround solution here, before we release the real batch payment
feature.
The basic idea is to split our wallet balance before we do the batch payment.
For example, if we have total 2,004
spendable Grin coins in the wallet, and we need do a 1,000
receivers batch payments, and suppose every payment is less than 2
Grin coins, then we can do it at the following steps:
We can use issue_send_tx
API to generate 1,000
UTXOs for ourselves at one time.
Construct a JSON format parameters:
{
"amount": 2000000000,
"minimum_confirmations": 10,
"method": "file",
"dest": "split.1000.grin",
"max_outputs": 1000,
"num_change_outputs": 999,
"selection_strategy_is_use_all": true
}
Note:
- The
num_change_outputs
is the desired numbers minus one, since we have onereceiver
output on this transaction. -
selection_strategy_is_use_all
istrue
here, to ensure we use all the existing UTXOs for getting enough input balance. -
"method": "file"
is strongly suggested for this splitting, for safety. - Regarding the transaction fee of the splitting: in this example, the fee will be
output_len * 4 + kernel_len - input_len = 1000 * 4 + 1 - 1000 = 3001
Milli-Grin (i.e. about 3.0 Grin Coins). So the estimated fee rate is about0.15%
in this example. (Note: here we suppose the total inputs number is also1,000
, it's a reasonable assumption since we most likely got one change output for one transaction.) - Before calling
issue_send_tx
API to execute this splitting, remember to useretrieve_summary_info
API to retrieve theamount_currently_spendable
and make sure the total spendable amount is enough for this splitting, including the fee. - The
999
split change output will have the same amount for each. That means we will get999
UTXOs and each UTXO has an amount:(origin_total_spendable - fee - 2) / 999
, in this example, it's(2004 - 3.001 - 2) / 999 = 2.001
.
Then, for the remaining parts to finish this splitting transaction, we can follow the above guide: Wallet Sending via API (Method: File).
Remember to query the transaction / output status, and wait till 10 (for example) confirmations for this splitting transaction.
With the generated 1,000
UTXOs in step 1, we're ready to make 1,000
transactions to those 1,000
receivers. There's nothing special here compared to making a payment to one receiver, just follow those steps which has been introduced in Wallet Sending via API (and don't forget the Transaction/Output Confirmation Query and How to Collaborate Send/Receive and Query/Cancel/Post ), and make these payments one by one.
An important note is, please remember to set selection_strategy_is_use_all
as false
for these payments!
For example, the constructed JSON format parameters of a payment:
{
"amount": 2000000000,
"minimum_confirmations": 10,
"method": "http",
"dest": "https://{one-receiver's address and port}",
"max_outputs": 1,
"num_change_outputs": 1,
"selection_strategy_is_use_all": false
}
For wallet performance reason, depending on what kind of CPU your wallet's running, you could need sleep 1 or 2 seconds between each payment. Then, 1,000
payments could need 15 or 30 minutes to complete. If that can't reach your requirement, you can consider using multiple wallet instances for parallel calling, each wallet instance is a completely independent wallet with its own wallet_data
, configuration file, and port.
[To Be Completed]
Basics
- Getting Started
- User Documentation
- MimbleWimble
- FAQ
- Planned releases (Roadmap)
- Code of Conduct
Contributing
- Contributing Guide
- Code Structure
- Code coverage and metrics
- Code Reviews and Audits
- Adding repos to /mimblewimble
Development
Mining
Infrastructure
Exchange integrations
R&D
Grin Community
Grin Governance
Risk Management
Grin Internals
- Block Header Data Structure
- Detailed validation logic
- P2P Protocol
Misc