Skip to content

Instantly share code, notes, and snippets.

@ccoincash
Created December 9, 2020 09:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ccoincash/fafb5e7097a04fb4dbb9bcd79273d8f6 to your computer and use it in GitHub Desktop.
Save ccoincash/fafb5e7097a04fb4dbb9bcd79273d8f6 to your computer and use it in GitHub Desktop.
a token contract support pay to contract
import "util.scrypt";
import "backtrace.scrypt";
/**
* A token protocol based on UTXO model
*/
contract Token {
public function split(
SigHashPreimage txPreimage,
PubKey senderPubKey,
Sig senderSig,
Ripemd160 receiver0,
int tokenAmount0,
int satoshiAmount0,
Ripemd160 receiver1,
int tokenAmount1,
int satoshiAmount1
) {
require(tokenAmount0 > 0);
// 1 to 1 transfer when tokenAmount1 is 0
require(tokenAmount1 >= 0);
// this ensures the preimage is for the current tx
require(Tx.checkPreimage(txPreimage));
// read previous locking script
// locking script = codePart + OP_RETURN + senderAddress + balance
bytes lockingScript = Util.scriptCode(txPreimage);
int scriptLen = len(lockingScript);
int dataStart = scriptLen - Util.PubKeyHashLen - 8;
Ripemd160 senderAddress = Ripemd160(lockingScript[dataStart: dataStart + Util.PubKeyHashLen]);
// authorize
require(hash160(senderPubKey) == senderAddress);
require(checkSig(senderSig, senderPubKey));
int senderBalance = Util.fromLEUnsigned(lockingScript[dataStart + Util.PubKeyHashLen: dataStart + Util.PubKeyHashLen + 8]);
// split
require(senderBalance == tokenAmount0 + tokenAmount1);
// persist contract code part, including op_return itself
bytes codePart = lockingScript[: dataStart];
// setting first balance as 0 is just a convention, not a requirement
bytes outputScript0 = codePart + receiver0 + num2bin(tokenAmount0, 8);
bytes output0 = Util.buildOutput(outputScript0, satoshiAmount0);
bytes outputScript1 = codePart + receiver1 + num2bin(tokenAmount1, 8);
bytes output1 = (tokenAmount1 > 0) ? Util.buildOutput(outputScript1, satoshiAmount1) : b'';
Sha256 hashOutputs = hash256(output0 + output1);
require(hashOutputs == Util.hashOutputs(txPreimage));
}
public function unlockFromScriptHash(
SigHashPreimage txPreimage,
bytes prevouts,
bytes prevScriptTx,
int prevScriptOutIndex,
Ripemd160 receiver
) {
SigHashType sigHashType = SigHash.SINGLE | SigHash.FORKID;
require(Util.checkPreimageSigHashType(txPreimage, sigHashType));
// check prevouts
require(hash256(prevouts) == Util.hashPrevouts(txPreimage));
// verify the prevScriptTx
// the script input index is 0
int outpointLen = 36;
bytes prevScriptTxId = prevouts[:32];
require(hash256(prevScriptTx) == prevScriptTxId);
// check the script
bytes lockingScript = Util.scriptCode(txPreimage);
int scriptLen = len(lockingScript);
int dataStart = scriptLen - Util.PubKeyHashLen - 8;
Ripemd160 scriptHash = Ripemd160(lockingScript[dataStart: dataStart + Util.PubKeyHashLen]);
bytes prevScriptCode = Backtrace.readOutputScript(prevScriptTx, prevScriptOutIndex);
require(hash160(prevScriptCode) == scriptHash);
// check the output
bytes codePart = lockingScript[: dataStart];
int tokenAmount = unpack(lockingScript[dataStart + Util.PubKeyHashLen: dataStart + Util.PubKeyHashLen + 8]);
int satoshiAmount = Util.value(txPreimage);
// setting first balance as 0 is just a convention, not a requirement
bytes outputScript = codePart + receiver + num2bin(tokenAmount, 8);
bytes output = Util.buildOutput(outputScript, satoshiAmount);
Sha256 hashOutputs = hash256(output);
require(hashOutputs == Util.hashOutputs(txPreimage));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment