Understanding ARCC, a contract chain system

0 99
Avatar for kiok46
Written by
2 years ago

ARCC stands for Allowable Revocable Contract Chain, it provides a way to mimic the pull/revoke mechanism. An ARCC(I pronounce it as, arck/ärk) system lets the payer take back the money while still allowing the payee to withdraw some funds from the contract based on restrictions of time and amount. More details here.

Whitepaper and Contract

The Whitepaper and Contract for ARCC could be found here. (Contract is still being tested.)

Note: This requires prior knowledge of Bitcoin Scripting Language and I assume that you have gone through either the contract or whitepaper. :)

Want to skip and try out the demo?

How does it work?

Let's try to understand by taking an example:

  • There are two parties:

    • Payer: This party is willing to pay the Payee in return for a service.

    • Payee: This party gets paid for the service he provides.

  • They open an application that supports ARCC and lets them create a contract.

  • The Payer and Payee agree that Payee will be allowed to fetch a maximum of 3000 satoshis from the contract every 2 blocks(epoch = 2) ~20 mins.

  • The payee puts a condition that he must get an initial payment beforehand in order to start providing the service, to which Payer happily agrees.

  • They create an ARCC Agreement Contract and both agree to fill in these details, they both provide their public keys, epoch(2 blocks), the max amount the payee can fetch per epoch. The rest of the parameters will automatically be calculated by their application.

    • Payer PubKey: 039e1ba72275d96bb9bdb3b73d5e6367ac950af1f422c0ab66ae0527e56dae8a57

    • Payee PubKey: 03b44d334e7524ea3e1c081866b7cd44fe6891a20b13d2590ac3651aabb58d23a0

    • epoch: 2(4 bytes)

    • maxAmountPerEpoch: 3000(4 bytes)

    • remainingTime: 2(4 bytes)

    • remainingAmount: 3000(4 bytes)

    • validFrom: 698860(4 bytes, transaction-level locktime i.e current block height)

The application provides an address for the contract bitcoincash:prtym5z4xjcjjdu362l0zf8x67yavemuav5pahgxas which Payer must fund. The Payer decides to add 6000 satoshis to the contract.

Now that the contract has been funded, the Payee wants to withdraw some partial amount from the contract, he decides to withdraw 1000 satoshis.

The payee types 1000 satoshis and presses the spend/withdraw button on the application and immediately receives the amount.

How does it actually work?

In order to do so, the application needs to derive the next contract state and its address. For that to happen, it must calculate the remaining spendable amount after the transaction and the time(block height) since the validFrom parameter of the spending contract.

The application creates a new contract with updated values, in this case, the remaining amount spendable must be 2000. Since no blocks have passed yet, the validFrom and remainingTime parameters remain the same.

Note: These conditions are enforced by the contract itself, the application only needs to calculate in order to continue deriving the next state and let the Payee withdraw from future states. (See demo for more clarity).

Next State Constructor:

  • Payer PubKey: 039e1ba72275d96bb9bdb3b73d5e6367ac950af1f422c0ab66ae0527e56dae8a57

  • Payee PubKey: 03b44d334e7524ea3e1c081866b7cd44fe6891a20b13d2590ac3651aabb58d23a0

  • epoch: 2(4 bytes)

  • maxAmountPerEpoch: 3000(4 bytes)

  • remainingTime: 2(4 bytes)

  • remainingAmount: 2000(4 bytes)

  • validFrom: 698860(4 bytes, transaction-level locktime i.e current block height)

By adding new values to the constructor, the application is able to derive a new address: bitcoincash:pq4tczau4xv429swf8jejwmln5an3ldagq0ewt2x53

The contract executes and two outputs are produced:

  • 1000 satoshis to Payee

  • 3884 satoshis to the next state's address. (1116 paid as miner fee)

The Payee has the permission to spend up to 3000 satoshis per epoch. This means that after every 2 blocks the payee can spend 3000 satoshis once again.

Understanding a successful transaction using meep debugger:

Transaction id: 57cb04ec4ac76d7a18e4ece8b03b546457dff13b7514256ed3cbeeeefc58735e

ScriptSig (Unlocking script):

  • amount: e803 (1000, amount that payee is spending)

  • amountToNextState: 2c0f(3884, amount going to the next state)

  • payeeSig:eb8a17ffff5b33e96a6ae7bce8286c8d48ba3c1d511ed393e1c9ae5726d9deb204dc9cc2eb9051726bc816f7902c961130870d9396011237ff8519cfdf01eb1141

  • preimage: 0200....000

    • version (4-bytes): 02000000

    • hashPrevouts (32 bytes): fdcdf2965805bf9ec240b192293c37d5ae9f4cc901b46567016bf4c8af484d35

    • hashSequence (32 bytes): 18606b350cd8bf565266bc352f0caddcf01e8fa789dd8a15386327cf8cabe198

    • outpoint (32 bytes + 4 bytes ): ddedd3fe22c9d4427152a05f7ffa61254911a136d92f8c8e2803d11739726ae7 + 00000000fd3b01

    • scriptCode:04eca90a0004b80b0000040200000004b80b000004020000002103b44d334e7524ea3e1c081866b7cd44fe6891a20b13d2590ac3651aabb58d23a021039e1ba72275d96bb9bdb3b73d5e6367ac950af1f422c0ab66ae0527e56dae8a575779009c63587a7cad6d6d6d755167577a519d5779016b7f77820134947f5c7f7701207f547f755b7a55796e7c828c7f755e7aa87bbbad567a815b7902220252798ba569567a815279815a7a81947600a269527952795379009e6354795e79947b757c5a79815379557997947600a063537955799f635c79815f7994537a757c6b7c6c6877766876009f6354797890947b757c6875687800567a8ba56954557a7e547e7b54807e547e7c54807e547a5f7f777e597a5880041976a9147e567aa97e0288ac7e587a58800317a9147e7ba97e01877e7eaa537a886d6d755168

    • Input's amount being spent (8 bytes) : 7017000000000000(6000)

    • nSequence (4 bytes): feffffff(4294967294)

    • hashOutputs (32 bytes): 00b0ff635eb645691dd2c8335369266fe907f345a84d2aeded8d4c75149f06ea

    • nLocktime (4 bytes): eca90a00(698860)

    • Sighash type (4 bytes): 41000000(41)

  • Different executable section's id: 1 represents a spend transaction from payee while 0 means that the payer wants to make a revoke-type transaction and transfer all the amount from the contract.

  • scriptCode: 04eca90a0004b80b0000040200000004b80b000004020000002103b44d334e7524ea3e1c081866b7cd44fe6891a20b13d2590ac3651aabb58d23a021039e1ba72275d96bb9bdb3b73d5e6367ac950af1f422c0ab66ae0527e56dae8a575779009c63587a7cad6d6d6d755167577a519d5779016b7f77820134947f5c7f7701207f547f755b7a55796e7c828c7f755e7aa87bbbad567a815b7902220252798ba569567a815279815a7a81947600a269527952795379009e6354795e79947b757c5a79815379557997947600a063537955799f635c79815f7994537a757c6b7c6c6877766876009f6354797890947b757c6875687800567a8ba56954557a7e547e7b54807e547e7c54807e547a5f7f777e597a5880041976a9147e567aa97e0288ac7e587a58800317a9147e7ba97e01877e7eaa537a886d6d755168

The script code in the preimage will later be used with the redeem script to enforce the next contract state and other necessary calculations like remaining time and amount.

ScriptPubKey:

OP_HASH160 d64dd05534b1293791d2bef124e6d789d6677ceb OP_EQUAL

RedeemScript:

  • validFrom: eca90a00(698860)

  • remainingAmount: b80b0000(3000)

  • remainingTime: 02000000(2)

  • maxAmountPerEpoch: b80b0000(3000)

  • epoch: 02000000(2)

  • payeePk: 03b44d334e7524ea3e1c081866b7cd44fe6891a20b13d2590ac3651aabb58d23a0

  • PayerPk:039e1ba72275d96bb9bdb3b73d5e6367ac950af1f422c0ab66ae0527e56dae8a57

7 OP_PICK(Push the section execution id to the top of the stack)0 OP_NUMEQUAL OP_IF(True if the Payer made the revoke transaction) 8 OP_ROLL OP_SWAP OP_CHECKSIGVERIFY OP_2DROP OP_2DROP OP_2DROP OP_DROP 1 OP_ELSE(True if the Payee makes the transaction) 7 OP_ROLL 1 OP_NUMEQUALVERIFY 7 OP_PICK(Fetch the preimage and push it to the top of the stack) 6b(107) OP_SPLIT OP_NIP OP_SIZE(6f01, 367) 34 OP_SUB OP_SPLIT 12 OP_SPLIT OP_NIP 20 OP_SPLIT 4 OP_SPLIT OP_DROP 11 OP_ROLL 5 OP_PICK OP_2DUP OP_SWAP OP_SIZE OP_1SUB OP_SPLIT OP_DROP 14 OP_ROLL OP_SHA256 OP_ROT OP_CHECKDATASIGVERIFY OP_CHECKSIGVERIFY(Make sure that the preimage provided in scriptSig is exactly the same as the one used to perform check sig (See here) 6 OP_ROLL OP_BIN2NUM 11 OP_PICK 2202 2 OP_PICK OP_1ADD OP_WITHIN(Checks the amount's range that Payee is trying to spend) OP_VERIFY 6 OP_ROLL OP_BIN2NUM 2 OP_PICK OP_BIN2NUM 10 OP_ROLL OP_BIN2NUM OP_SUB OP_DUP 0 OP_GREATERTHANOREQUAL OP_VERIFY(Verifies that the passed time is greater than equal to 0 by fetching the validFrom from constructor and locktime) 2 OP_PICK 2 OP_PICK 3 OP_PICK 0 OP_NUMNOTEQUAL OP_IF 4 OP_PICK 14 OP_PICK OP_SUB OP_ROT OP_DROP OP_SWAP 10 OP_PICK OP_BIN2NUM 3 OP_PICK 5 OP_PICK OP_MOD OP_SUB OP_DUP 0 OP_GREATERTHAN OP_IF 3 OP_PICK 5 OP_PICK OP_LESSTHAN OP_IF 12 OP_PICK OP_BIN2NUM 15 OP_PICK OP_SUB 3 OP_ROLL OP_DROP OP_SWAP OP_TOALTSTACK OP_SWAP OP_FROMALTSTACK OP_ENDIF OP_NIP OP_DUP OP_ENDIF OP_DUP 0 OP_LESSTHAN OP_IF 4 OP_PICK OP_OVER OP_ABS OP_SUB OP_ROT OP_DROP OP_SWAP OP_ENDIF OP_DROP OP_ENDIF OP_OVER 0 6 OP_ROLL OP_1ADD OP_WITHIN(Enforces that the new remaining amount is within the allowed range.) OP_VERIFY 4 5 OP_ROLL (Process to create the new script code starts)OP_CAT 4 OP_CAT OP_ROT 4 OP_NUM2BIN OP_CAT 4 OP_CAT OP_SWAP 4 OP_NUM2BIN OP_CAT 4 OP_ROLL 15 OP_SPLIT OP_NIP OP_CAT 9 OP_ROLL 8 OP_NUM2BIN 1976a914 OP_CAT 6 OP_ROLL OP_HASH160 OP_CAT 88ac OP_CAT 8 OP_ROLL 8 OP_NUM2BIN 17a914 OP_CAT OP_ROT OP_HASH160 OP_CAT 87 OP_CAT OP_CAT OP_HASH256 3 OP_ROLL OP_EQUALVERIFY OP_2DROP OP_2DROP OP_DROP 1 OP_ENDIF 

Notice the top item of the stack. In the process of inspecting the unlocking script and at the time of executing the contract in the redeem script, the script ended up creating a new script code with values that we expected: 04 + eca90a00(698860) + 04 + d0070000(2000) + 04 + 04 + 020000000 + ....

The only difference from the previous state's scriptCode is the value of the remaining amount which changed from b80b0000(3000) to d0070000(2000).

Feedback?

I still have a lot to learn and it's possible that there might be some improvements that can be made.

Thanks for reading, I hope it was worth your time!
Cheers!

4
$ 5.10
$ 5.00 from @bitcoincashautist
$ 0.10 from @tula_s
Avatar for kiok46
Written by
2 years ago

Comments