Tutorial · Regtest

Vaults on Regtest

Set up an owner node and a manager node on your private chain, fund a vault between them, watch the manager stake it, then debit, reclaim and remove it. Every command on this page was run on a fresh regtest chain, with the exact output shown.

About 25 minutes · Checked 2026-10-21

1What this page is, and is not

A vault is a coin with two keys on it: the owner can spend it, the manager can only stake it. The vault tutorials explain the idea and walk through every operation on testnet, where mistakes cost nothing but time: start with what is a vault, then create a vault, fund a vault, add a vault as manager, debit a vault by name, reclaim vault funds, remove a vault, decompose a vault, move a vault, vault errors, vault security and running a vault staking service.

This page does one thing those cannot: it puts the whole vault life cycle on a chain you control, where a block takes a second instead of a minute and the manager's stake lands while you watch. Use it to rehearse before testnet, to test software that creates or watches vaults, or to see what the manager's node really holds.

What you need before you start

A regtest node in ~/divi-regtest built as in start your first regtest node, and the second-node technique from two regtest nodes. Blocks are made with setgenerate on the C++ node; IronDivi cannot make regtest blocks, so it appears below only as a manager, where it works.

2Two nodes: owner and manager

Vaults need two wallets, so they need two nodes. The first is your usual regtest node, which will be the owner. The second is a copy on different ports, connected to the first, which will be the manager. The manager's node gets one extra line in its config, vault=1; without it the node refuses to take on a vault (shown in step 4).

mkdir -p ~/divi-manager
cat > ~/divi-manager/divi.conf <<'EOF'
regtest=1
server=1
listen=0
rpcbind=127.0.0.1
rpcallowip=127.0.0.1
port=51486
rpcport=51487
rpcuser=regtest
rpcpassword=a long random password, different from the owner's
staking=0
connect=127.0.0.1:51476
vault=1
EOF
divid -datadir=~/divi-manager -daemon

Give the owner 101 blocks so it has 100,000 spendable DIVI (why 101 and not 100 is in give yourself coins on regtest), and check that both nodes see the same height:

divi-cli -datadir=~/divi-regtest setgenerate 101
divi-cli -datadir=~/divi-regtest getblockcount
101
divi-cli -datadir=~/divi-manager getblockcount
101
divi-cli -datadir=~/divi-regtest getwalletinfo
… "spendable_balance" : 100000.00000000, "immature_balance" : 25996.00000000, "vaulted_balance" : 0.00000000 …

Now take one address from each wallet. The owner address will be able to spend the vault; the manager address will be able to stake it. Keep both in shell variables, every later command uses them.

OWNER=$(divi-cli -datadir=~/divi-regtest getnewaddress)
MANAGER=$(divi-cli -datadir=~/divi-manager getnewaddress)
echo "$OWNER:$MANAGER"
y72sb7ERu8HxXJUemf5Vms4CYZrvVZwsLn:yD9AQYbuEUEGXv2nbX1VyDCWot5S1Ta2a2

That owner:manager string is the vault's name. On regtest both addresses start with x or y, like testnet; a mainnet address starting with D is rejected here as "Invalid DIVI address".

3Fund a vault

The owner creates the vault by sending coins to the two-key script. The amount comes from the owner's spendable balance, and the manager is not involved yet.

divi-cli -datadir=~/divi-regtest fundvault "$OWNER:$MANAGER" 1000
{
    "txhash" : "40994dc4e5f81ddbf56e61c7eda12a4c97b0420d413071651ab4b5b7e3de49d7",
    "vault" : [ { "encoding" : "y72sb7ERu8HxXJUemf5Vms4CYZrvVZwsLn:yD9AQYbuEUEGXv2nbX1VyDCWot5S1Ta2a2" } ]
}
VAULT_TX=40994dc4e5f81ddbf56e61c7eda12a4c97b0420d413071651ab4b5b7e3de49d7
divi-cli -datadir=~/divi-regtest setgenerate 1
divi-cli -datadir=~/divi-regtest getwalletinfo
… "spendable_balance" : 98999.99997490, "vaulted_balance" : 1000.00000000 …

Keep the transaction hash: the manager needs it in the next step. Look at the transaction itself to see what a vault is on the chain. One output is ordinary change back to the owner. The other has type vault and carries both addresses:

divi-cli -datadir=~/divi-regtest getrawtransaction $VAULT_TX 1
… "vout" : [
      { "value" : 249.99997490, "scriptPubKey" : { "type" : "pubkeyhash", "addresses" : [ "yL1j…" ] } },
      { "value" : 1000.00000000, "scriptPubKey" : { "type" : "vault",
            "addresses" : [ "y72sb7ERu8HxXJUemf5Vms4CYZrvVZwsLn", "yD9AQYbuEUEGXv2nbX1VyDCWot5S1Ta2a2" ] } } ] …

In the owner's listtransactions the funding shows as category move to the address "Staking Vault", not as a send: the money has not left the owner's wallet, it has changed form. The fee was 0.0000251 DIVI, which is why the spendable balance is 98,999.9999749 rather than 99,000.

4The manager adds the vault

The manager's wallet does not know about the vault until it is told. First, see what happens on a node started without vault=1 (start the manager once with that line commented out if you want to reproduce this):

divi-cli -datadir=~/divi-manager addvault "$OWNER:$MANAGER" $VAULT_TX
error: {"code":-32600,"message":"AddingVaultScript: Unable to sync TX!"}

With vault=1 in the config, the same command succeeds, and the vault appears in the manager's staking balance but not in its spendable balance:

divi-cli -datadir=~/divi-manager addvault "$OWNER:$MANAGER" $VAULT_TX
{ "succeeded" : true }
divi-cli -datadir=~/divi-manager getbalance
0.00000000
divi-cli -datadir=~/divi-manager getstakingstatus
… "mintablecoins" : false, "enoughcoins" : true, "staking_balance" : 1000.00000000 …
divi-cli -datadir=~/divi-manager sendtoaddress $OWNER 10
error: {"code":-6,"message":"Insufficient funds: 1000000000(total requested) is greater than 0(total available)"}

That last error is the point of a vault: the manager holds 1,000 DIVI for staking and can spend none of it. mintablecoins is still false because the vault coin has only one confirmation; a coin must be 20 blocks deep before it can stake, the same maturity rule as a reward.

manager's spendable balance
0
manager's staking balance
1,000
confirmations before the vault can stake
21

5The manager stakes with it

On testnet you would now wait, possibly for days, for the manager to win a stake. On regtest you can make the stake happen. setgenerate on the manager's node makes a staked block from whatever that wallet can stake, and the only coin it can stake is the vault. Before the vault matures the manager cannot make a block at all:

divi-cli -datadir=~/divi-manager setgenerate 1
error: {"code":-25,"message":"failed to generate a valid block"}
divi-cli -datadir=~/divi-regtest setgenerate 20
divi-cli -datadir=~/divi-manager getstakingstatus
… "mintablecoins" : true …
divi-cli -datadir=~/divi-manager setgenerate 1
[ "481670a10aaadf52d4b4b51604dcc1905c0763b9e1860680e91f3171a12c2ff7" ]

Open that block and its second transaction, the coinstake. Its input is the vault output you funded, and its output is a new vault output for 1,996 DIVI: the 1,000 that went in plus the 996 reward, still locked to the same two keys.

divi-cli -datadir=~/divi-regtest getrawtransaction <second txid in that block> 1
… "vin" : [ { "txid" : "40994dc4…", "vout" : 1 } ],
    "vout" : [ { "value" : 0.00000000, "scriptPubKey" : { "type" : "nonstandard" } },
               { "value" : 1996.00000000, "scriptPubKey" : { "type" : "vault",
                 "addresses" : [ "y72sb7ERu8HxXJUemf5Vms4CYZrvVZwsLn", "yD9AQYbuEUEGXv2nbX1VyDCWot5S1Ta2a2" ] } } ] …

Right after the block both wallets look alarming for a moment: the owner's vaulted_balance reads 0 and the manager's staking_balance reads 0. The old vault coin is spent and the new one is an immature reward. Make 20 more blocks on the owner node and both come back, larger:

divi-cli -datadir=~/divi-manager listtransactions "*" 1
… "category" : "stake_reward", "amount" : 996.00000000 …
divi-cli -datadir=~/divi-regtest setgenerate 20
divi-cli -datadir=~/divi-regtest getwalletinfo
… "vaulted_balance" : 1996.00000000 …
divi-cli -datadir=~/divi-manager getstakingstatus
… "staking_balance" : 1996.00000000 …

The reward went into the vault, so it belongs to the owner, and the manager still cannot spend a satoshi of it. This is exactly what a vault staking service does for its customers, compressed into a few seconds; the service side is described in running a vault staking service.

Where did 996 come from?

A staked block after block 100 pays 1,250, of which 50 is set aside for the lottery, 16% plus 1% goes to the treasury and charity, and the staker keeps the rest, 996, because there are no masternodes on your chain to take the masternode share. The full split is in give yourself coins on regtest.

6An IronDivi manager

IronDivi can be the manager too, which matters if that is what your staking service will run. Start it as a third node connected to the owner (the same way as in two regtest nodes), fund a second vault to one of its addresses, and add it there:

irondivid --regtest --datadir ~/iron-regtest --rpcport 51485 \
    --connect 127.0.0.1:51476 --staking=false &
IRON=$(irondivi-cli --regtest --rpcport 51485 getnewaddress)
divi-cli -datadir=~/divi-regtest fundvault "$OWNER:$IRON" 500
{ "txhash" : "a24cc973e34663d5b8b75104a5d73062701b3d7dae3940dc4adc4e7aa26a8543", … }
divi-cli -datadir=~/divi-regtest setgenerate 1
irondivi-cli --regtest --rpcport 51485 addvault "$OWNER:$IRON" a24cc973e34663d5b8b75104a5d73062701b3d7dae3940dc4adc4e7aa26a8543
{ "message": "Vault y72sb7ER…:y6727was… added successfully", "result": "success" }
irondivi-cli --regtest --rpcport 51485 getbalance
500.0
irondivi-cli --regtest --rpcport 51485 getstakingstatus
… "enoughcoins": true, "staking_balance": 500.0 …
irondivi-cli --regtest --rpcport 51485 setgenerate 1
error code: -32603: setgenerate is not yet implemented - requires full mining subsystem

Two differences from the C++ manager are worth knowing. IronDivi needs no vault=1 switch, and its getbalance reports the vaulted 500 where the C++ node reports 0; the staking balance is the number to compare. And IronDivi cannot stake a block on regtest, so the stake in step 5 can only be shown with a C++ manager. Whether IronDivi stakes a vault on a real network is a testnet question, not a regtest one.

The owner now sees both vaults added together:

divi-cli -datadir=~/divi-regtest getwalletinfo
… "vaulted_balance" : 2496.00000000 …

7Debit, reclaim, remove

Three commands take money or control back. All three ran on the chain above, in this order, and the balances after each are shown so you can see what moved.

Debit by name pays someone out of one named vault and leaves the rest in that vault. The owner runs it; it does not need the manager at all.

DEST=$(divi-cli -datadir=~/divi-regtest getnewaddress)
divi-cli -datadir=~/divi-regtest debitvaultbyname "$OWNER:$MANAGER" $DEST 50
a101210a818cca28d16a0bef66b3fab6c643326ae6c871869bea7c585b75f046
divi-cli -datadir=~/divi-regtest setgenerate 1
divi-cli -datadir=~/divi-regtest getwalletinfo
… "vaulted_balance" : 2445.99997480 …
divi-cli -datadir=~/divi-manager getstakingstatus
… "staking_balance" : 1945.99997480 …

The transaction spent the 1,996 vault coin, paid 50 to the destination and put 1,945.9999748 back into a new output of type vault with the same two keys. The fee came out of the vault. The IronDivi vault's 500 was not touched.

Reclaim pulls money out of the vaults as a whole, to any address, without naming a vault:

divi-cli -datadir=~/divi-regtest reclaimvaultfunds $DEST 300
8bee50dba846599fc6cafab27559e879eab4f3811eef9afd90b9cad6dabda10c
divi-cli -datadir=~/divi-regtest setgenerate 1
divi-cli -datadir=~/divi-regtest getwalletinfo
… "vaulted_balance" : 500.00000000 …
divi-cli -datadir=~/divi-manager getstakingstatus
… "staking_balance" : 0.00000000 …

Read the balances carefully: asking for 300 emptied the manager's vault, not just 300 of it. The reclaim spent the whole 1,945.9999748 coin, paid 300 to the destination, and sent the remaining 1,645.9999496 to an ordinary address in the owner's wallet, not back into the vault. If you want to take out a part and keep the rest staking, use debitvaultbyname with your own address as the destination. Reclaim is for taking the vault apart.

Remove is the manager's command. It takes the vault out of the manager's wallet so it stops staking it; the coins are unaffected and still belong to the owner. The manager can add the same vault back later with the same funding transaction.

divi-cli -datadir=~/divi-manager removevault "$OWNER:$MANAGER"
{ "removal_status" : true }
divi-cli -datadir=~/divi-manager addvault "$OWNER:$MANAGER" $VAULT_TX
{ "succeeded" : true }

On this chain the manager's staking balance stays 0 after adding it back, because the reclaim in the previous step already emptied that vault; add it back before reclaiming and the balance returns.

Shell variables and the funding hash

Every command above identifies the vault by the owner:manager string, and addvault also needs the funding transaction hash. Save both somewhere you can find them. On testnet or mainnet, losing the manager address of a funded vault means you cannot tell the manager which vault to add, though the owner can always reclaim.

8The errors you will see

Each of these was produced on purpose on the chain above. The wording is the node's own, so you can search for it.

You ranNode saidMeaning
addvault on a node without vault=1AddingVaultScript: Unable to sync TX!Add vault=1 to the manager's divi.conf and restart that node.
addvault with a manager address that is not in this walletAddingVaultScript: Does not have matching manager key!You are on the wrong node, or the manager address in the name is not one of yours.
debitvaultbyname on the manager's nodeVault owner key is unknown: ownership=0 address=y72s…Only the owner can debit. The manager has no spending key.
removevault on the owner's node{ "removal_status" : false }Remove is a manager action. The owner takes money out with reclaimvaultfunds instead.
sendtoaddress from the managerInsufficient funds: … is greater than 0(total available)Correct behaviour: the vault is not spendable by the manager.
setgenerate 1 on the manager before 20 blocksfailed to generate a valid blockThe vault coin is not mature yet. Make 20 blocks on the owner and try again.
reclaimvaultfunds for more than the vaulted totalInsufficient funds: 200000000000(total requested) is greater than 50000000000(total available)Amounts are in satoshis here; you asked for 2,000 with 500 vaulted.
reclaimvaultfunds for exactly the vaulted totalInsufficient funds to meet coin selection algorithm requirements.The fee must come out of the vault coins too. Reclaim slightly less than the total.

The testnet page vault errors covers the same messages in the wallet apps.

If something goes wrong

SymptomCauseFix
The manager node's getblockcount stays at 0It is not connected to the owner nodeCheck connect=127.0.0.1:51476 matches the owner's port, and that both configs say regtest=1.
vaulted_balance drops to 0 right after the manager made a blockThe staked vault coin is an immature reward for 20 blocksMake 20 blocks on the owner node; the balance returns, 996 larger.
staking_balance stays 0 after addvault succeededThe vault was already emptied by a reclaim, or the funding transaction is not in a block yetCheck the owner's vaulted_balance, and run setgenerate 1 on the owner if the funding is still in the mempool.
fundvault says Invalid DIVI addressOne of the two addresses is from another networkUse addresses made by getnewaddress on the regtest nodes themselves.
Both nodes refuse to start, "cannot obtain a lock"Both use the same data folder or the same portsGive the manager its own -datadir and its own port and rpcport.

Still stuck? Ask the Divi chatbot, or see all tutorials.