这里我们介绍一个定期支付合约,允许用户定期存入款项,并且收款者可以定期收取款项。
合约实现
合约代码如下:
contract Recurring {
Ripemd160 userPubKeyHash; //Address of the owner of the coin
int merchantPayment; //How much the merchant can take from the contract
Ripemd160 merchantPubKeyHash; //Address of the merchant
int frequenceOfPayment; //Merchant can take money each "frequenceOfPayment" seconds
// User can deposit more money in his recurring contract
public function deposit_user(SigHashPreimage preImage, int depositAmount, int changeAmount) {
require(Tx.checkPreimage(preImage));
require(depositAmount > 0);
int contractTotalAmount = SigHash.value(preImage) + depositAmount;
bytes output = Utils.buildOutput(SigHash.scriptCode(preImage), contractTotalAmount);
bytes change_output = changeAmount <= 546 ? b'' : Utils.buildOutput(Utils.buildPublicKeyHashScript(this.userPubKeyHash), changeAmount);
require(hash256(output + change_output) == SigHash.hashOutputs(preImage));
}
// User wants to withdraw its money. Standard P2PKH transaction
public function withdraw_user(Sig sig, PubKey pubKey) {
require(hash160(pubKey) == this.userPubKeyHash);
require(checkSig(sig, pubKey));
}
// Merchant wants its money
public function withdraw_merchant(SigHashPreimage preImage, int newAmount) {
require(Tx.checkPreimage(preImage));
//Output for the merchant
bytes outputMerchant = Utils.buildOutput(Utils.buildPublicKeyHashScript(this.merchantPubKeyHash), this.merchantPayment);
//Output that'll be the next instance of the contract
//Check nlocktime
bytes scriptCode = SigHash.scriptCode(preImage);
int scriptLen = len(scriptCode);
bytes codePart = this.getCodePart(scriptCode, scriptLen);
int newMatureTime = this.getPrevMatureTime(scriptCode, scriptLen) + this.frequenceOfPayment;
bytes newScript = codePart + pack(newMatureTime);
require(SigHash.nLocktime(preImage) == newMatureTime);
//Build the output
bytes outputContract = Utils.buildOutput(newScript, newAmount);
require(hash256(outputContract + outputMerchant) == SigHash.hashOutputs(preImage));
}
function getPrevMatureTime(bytes lockingScript, int scriptLen) : int {
return unpack(lockingScript[scriptLen - 4 :]);
}
function getCodePart(bytes lockingScript, int scriptLen) : bytes {
return lockingScript[0 : scriptLen - 4];
}
}
该合约有3个公共函数:
- 第一个允许用户存入更多的钱;
- 第二个允许用户随时选择退出。 请注意,如果用户需要在停止重复付款之前提供取消通知给商家,可以基于此合约进行些小的修改而实现;
- 最后一个允许商家定期从合约中提取一定数量的钱。 它包含一个nLockTimeVerify 部分,以防止商家立即提取它。另请注意,nLockTimeVerify 仅适用于商家,用户仍可以存入更多资金或选择退出。
应用场景
此合约除了对于订阅付款非常有用以外,其设计思路也可以用于实现很多支付帐户的功能,例如:每天有支出限额;或者如果手机被盗会紧急关闭;有取款密码;支付时需要满足特殊条件等应用场景。