57 lines
2.5 KiB
Text
57 lines
2.5 KiB
Text
|
|
pragma cashscript ^0.13.0;
|
||
|
|
|
||
|
|
// Subscription — a prepaid balance the host can draw from once per period,
|
||
|
|
// and the buyer can take back at any time.
|
||
|
|
// (Argus/src/lib/plans.js SUBSCRIPTION_ROADMAP; ROADMAP-MAINNET.md §9 step 4.)
|
||
|
|
//
|
||
|
|
// STATUS: chipnet draft. NOT REVIEWED.
|
||
|
|
//
|
||
|
|
// The buyer funds this script. Three things then hold, and the buyer can check
|
||
|
|
// each from the script alone:
|
||
|
|
//
|
||
|
|
// · the balance stays theirs — cancel() needs only their signature, no
|
||
|
|
// notice, no cooperation, and returns whatever is left;
|
||
|
|
// · the host cannot take more than one period's price per period — pull()
|
||
|
|
// pays exactly the host's lock at least `priceSats`, sends the rest back to
|
||
|
|
// this same script, and can only run on an output that is `periodBlocks`
|
||
|
|
// old, which the re-created output is not;
|
||
|
|
// · nobody else gains anything — pull() needs no signature, so the host does
|
||
|
|
// not have to be online with a key, but its only possible beneficiary is
|
||
|
|
// the host's lock.
|
||
|
|
//
|
||
|
|
// A pull spends this input ALONE. With two inputs, one "price to the host"
|
||
|
|
// output and one "rest back to the script" output could satisfy both, and the
|
||
|
|
// host would collect two balances for one payment. One input means the fee
|
||
|
|
// comes out of the balance too, bounded by `maxFeeSats`.
|
||
|
|
//
|
||
|
|
// The first period is not special-cased: the balance is drawn one period
|
||
|
|
// after it is funded. A host that wants payment up front takes the first
|
||
|
|
// period in the funding transaction itself.
|
||
|
|
contract Subscription(bytes20 buyerPkh, bytes hostLock, int priceSats, int periodBlocks, int maxFeeSats) {
|
||
|
|
// One period's payment to the host.
|
||
|
|
function pull() {
|
||
|
|
require(this.age >= periodBlocks);
|
||
|
|
require(tx.inputs.length == 1);
|
||
|
|
|
||
|
|
int balance = tx.inputs[0].value;
|
||
|
|
require(tx.outputs[0].lockingBytecode == hostLock);
|
||
|
|
require(tx.outputs[0].value >= priceSats);
|
||
|
|
require(tx.outputs[0].tokenCategory == 0x);
|
||
|
|
|
||
|
|
// Everything else stays in the subscription, less a bounded fee. When
|
||
|
|
// what would remain is too small to be an output, it is the fee.
|
||
|
|
int rest = balance - priceSats - maxFeeSats;
|
||
|
|
if (rest >= 546) {
|
||
|
|
require(tx.outputs[1].lockingBytecode == tx.inputs[0].lockingBytecode);
|
||
|
|
require(tx.outputs[1].value >= rest);
|
||
|
|
require(tx.outputs[1].tokenCategory == 0x);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// The buyer ends it and takes the balance. No conditions on where it goes.
|
||
|
|
function cancel(pubkey pk, sig s) {
|
||
|
|
require(hash160(pk) == buyerPkh);
|
||
|
|
require(checkSig(s, pk));
|
||
|
|
}
|
||
|
|
}
|