我原来在scrypt上做过一个类似想法的原型,供参考。
这个最好配合Layer 1的token方案,不然就要想另外的办法让合约可以验证token的真伪。
生成的测试网交易:
<a href='https://test.whatsonchain.com/tx/30cc3d743d9e76a314dd7f70aaefabd6bdd976754cd5f9bb8f6c546cb7633f7b'>https://test.whatsonchain.com/tx/30cc3d743d9e76a314dd7f70aaefabd6bdd976754cd5f9bb8f6c546cb7633f7b</a>
contract文件:
contract Sell {
bytes bsvReceiveScript;
int sellAmount;
int getAmount;
constructor(bytes bsvReceiveScript,int sellAmount, int getAmount) {
this.bsvReceiveScript = bsvReceiveScript;
this.sellAmount = sellAmount;
this.getAmount = getAmount;
}
public function match(bytes sighashPreimage, bytes receiverScriptPubkey, int coinAmount, int bsvAmount, bytes additionalOutputs) {
Tx tx = new Tx();
require(tx.validate(sighashPreimage));
require(coinAmount>0);
require(bsvAmount>0);
int len = length(sighashPreimage);
bytes hashOutputs = sighashPreimage[len - 40 : len - 8];
// scriptCode is just scriptPubKey if there is no CODESEPARATOR in the latter
bytes scriptCode = this.readVarint(sighashPreimage[104:]);
int scriptLen = length(scriptCode);
// last byte contains the state, i.e., counter
int amount = unpack(scriptCode[scriptLen - 4 :]);
require(coinAmount<=amount);
// increment counter
bytes scriptCode_ = scriptCode[: scriptLen - 4] ++ num2bin(amount - coinAmount, 4);
//todo verify price where
require(this.getAmount * coinAmount <= this.sellAmount * bsvAmount);
// output: amount + scriptlen + script
Sha256 hashOutputs_ = hash256(
num2bin(1000, 8) ++ this.writeVarint(
b"6a"++b"0453454e44"++this.writeVarint(num2bin(amount - coinAmount, 4))
++this.writeVarint(num2bin(coinAmount, 4))
)
++num2bin(1000, 8) ++ this.writeVarint(scriptCode_)
++num2bin(1000, 8) ++ this.writeVarint(receiverScriptPubkey)
++num2bin(bsvAmount, 8) ++ this.writeVarint(this.bsvReceiveScript)
++additionalOutputs
);
// ensure output is expected: amount is same with specified
// also output script is the same with scriptCode except counter incremented
require(hashOutputs == hashOutputs_);
}
function readVarint(bytes b) returns (bytes) {
int len = 0;
bytes ret = b"";
bytes header = b[0:1];
if (header == b"fd") {
len = this.fromLEUnsigned(b[1:3]);
ret = b[3:3+len];
} else if (header == b"fe") {
len = this.fromLEUnsigned(b[1:5]);
ret = b[5:5+len];
} else if (header == b"ff") {
len = this.fromLEUnsigned(b[1:9]);
ret = b[9:9+len];
} else {
len = this.fromLEUnsigned(b[0:1]);
ret = b[1:1+len];
}
return ret;
}
function writeVarint(bytes b) returns (bytes) {
int n = length(b);
bytes header = b"";
if (n < 0xfd) {
header = this.toLEUnsigned(n, 1);
} else if (n < 0x10000) {
header = b"fd" ++ this.toLEUnsigned(n, 2);
} else if (n < 0x100000000) {
header = b"fe" ++ this.toLEUnsigned(n, 4);
} else if (n < 0x10000000000000000) {
header = b"ff" ++ this.toLEUnsigned(n, 8);
}
return header ++ b;
}
// convert signed integer `n` to unsigned integer of `len` bytes, in little endian
function toLEUnsigned(int n, int len) returns (bytes) {
// one extra byte to accommodate possible negative sign byte
bytes m = num2bin(n, len + 1);
// remove sign byte
return m[0 : length(m) - 1];
}
function fromLEUnsigned(bytes b) returns (int) {
// append positive sign byte. This does not hurt even when sign bit is already positive
return unpack(b ++ b"00");
}
}
我原来在scrypt上做过一个类似想法的原型,供参考。
这个最好配合Layer 1的token方案,不然就要想另外的办法让合约可以验证token的真伪。
生成的测试网交易:
<a href='https://test.whatsonchain.com/tx/30cc3d743d9e76a314dd7f70aaefabd6bdd976754cd5f9bb8f6c546cb7633f7b'>https://test.whatsonchain.com/tx/30cc3d743d9e76a314dd7f70aaefabd6bdd976754cd5f9bb8f6c546cb7633f7b</a>
contract文件:
contract Sell {
bytes bsvReceiveScript;
int sellAmount;
int getAmount;
constructor(bytes bsvReceiveScript,int sellAmount, int getAmount) {
this.bsvReceiveScript = bsvReceiveScript;
this.sellAmount = sellAmount;
this.getAmount = getAmount;
}
public function match(bytes sighashPreimage, bytes receiverScriptPubkey, int coinAmount, int bsvAmount, bytes additionalOutputs) {
Tx tx = new Tx();
require(tx.validate(sighashPreimage));
require(coinAmount>0);
require(bsvAmount>0);
int len = length(sighashPreimage);
bytes hashOutputs = sighashPreimage[len - 40 : len - 8];
// scriptCode is just scriptPubKey if there is no CODESEPARATOR in the latter
bytes scriptCode = this.readVarint(sighashPreimage[104:]);
int scriptLen = length(scriptCode);
// last byte contains the state, i.e., counter
int amount = unpack(scriptCode[scriptLen - 4 :]);
require(coinAmount<=amount);
// increment counter
bytes scriptCode_ = scriptCode[: scriptLen - 4] ++ num2bin(amount - coinAmount, 4);
//todo verify price where
require(this.getAmount * coinAmount <= this.sellAmount * bsvAmount);
// output: amount + scriptlen + script
Sha256 hashOutputs_ = hash256(
num2bin(1000, 8) ++ this.writeVarint(
b"6a"++b"0453454e44"++this.writeVarint(num2bin(amount - coinAmount, 4))
++this.writeVarint(num2bin(coinAmount, 4))
)
++num2bin(1000, 8) ++ this.writeVarint(scriptCode_)
++num2bin(1000, 8) ++ this.writeVarint(receiverScriptPubkey)
++num2bin(bsvAmount, 8) ++ this.writeVarint(this.bsvReceiveScript)
++additionalOutputs
);
// ensure output is expected: amount is same with specified
// also output script is the same with scriptCode except counter incremented
require(hashOutputs == hashOutputs_);
}
function readVarint(bytes b) returns (bytes) {
int len = 0;
bytes ret = b"";
bytes header = b[0:1];
if (header == b"fd") {
len = this.fromLEUnsigned(b[1:3]);
ret = b[3:3+len];
} else if (header == b"fe") {
len = this.fromLEUnsigned(b[1:5]);
ret = b[5:5+len];
} else if (header == b"ff") {
len = this.fromLEUnsigned(b[1:9]);
ret = b[9:9+len];
} else {
len = this.fromLEUnsigned(b[0:1]);
ret = b[1:1+len];
}
return ret;
}
function writeVarint(bytes b) returns (bytes) {
int n = length(b);
bytes header = b"";
if (n < 0xfd) {
header = this.toLEUnsigned(n, 1);
} else if (n < 0x10000) {
header = b"fd" ++ this.toLEUnsigned(n, 2);
} else if (n < 0x100000000) {
header = b"fe" ++ this.toLEUnsigned(n, 4);
} else if (n < 0x10000000000000000) {
header = b"ff" ++ this.toLEUnsigned(n, 8);
}
return header ++ b;
}
// convert signed integer `n` to unsigned integer of `len` bytes, in little endian
function toLEUnsigned(int n, int len) returns (bytes) {
// one extra byte to accommodate possible negative sign byte
bytes m = num2bin(n, len + 1);
// remove sign byte
return m[0 : length(m) - 1];
}
function fromLEUnsigned(bytes b) returns (int) {
// append positive sign byte. This does not hurt even when sign bit is already positive
return unpack(b ++ b"00");
}
}