Skip to content

Instantly share code, notes, and snippets.

@ccoincash
Created December 9, 2020 09:13
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/0046bdd0c1f858ae91bd9fea6b62f6de to your computer and use it in GitHub Desktop.
Save ccoincash/0046bdd0c1f858ae91bd9fea6b62f6de to your computer and use it in GitHub Desktop.
deploy tokenP2SH contract
const {
bsv,
buildContractClass,
getPreimage,
toHex,
num2bin,
SigHashPreimage,
signTx,
PubKey,
Sig,
Bytes,
Ripemd160,
} = require('scryptlib');
const {
DataLen,
loadDesc,
sendTx,
showError,
} = require('../helper');
const {
privateKey,
privateKey2,
} = require('../privateKey');
const utxo1 = 'b3edf3d30cd1357c9bc24153d000e77330b12ba00df572288f1b34cfbf7b5d20';
const outIndex1 = 1;
const utxo2 = 'e32b5c7a1eab97ee9046d51567710c403b8a0b7c0cba1b933b4a0dd2f2e774e6';
const outIndex2 = 1
const utxo3 = '2de614eb75befa0a0f89c31cd771a5d55ceac0b0e0ed93551906ae0b44ff227b'
const outIndex3 = 0
let tokenContract = null
let tokenSellContract = null
let senderAmount = 100000
let sellBsvAmount = 10000
let Token = null
const address1 = toHex(bsv.crypto.Hash.sha256ripemd160(privateKey.publicKey.toBuffer()))
const address2 = toHex(bsv.crypto.Hash.sha256ripemd160(privateKey2.publicKey.toBuffer()))
function buildTx(lockingScript, inputAmount, outAmount1, outAmount2, utxo, outIndex) {
const tx = new bsv.Transaction()
tx.addInput(new bsv.Transaction.Input.PublicKeyHash({
output: new bsv.Transaction.Output({
script: bsv.Script.buildPublicKeyHashOut(privateKey.toAddress()),
satoshis: inputAmount
}),
prevTxId: utxo,
outputIndex: outIndex,
script: bsv.Script.empty()
}))
tx.addOutput(new bsv.Transaction.Output({
script: lockingScript,
satoshis: outAmount1,
}))
tx.addOutput(new bsv.Transaction.Output({
script: bsv.Script.buildPublicKeyHashOut(privateKey.toAddress()),
satoshis: outAmount2,
}))
let sigtype = bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID
let hashData = bsv.crypto.Hash.sha256ripemd160(privateKey.publicKey.toBuffer())
let sig = tx.inputs[0].getSignatures(tx, privateKey, 0, sigtype, hashData)
tx.inputs[0].addSignature(tx, sig[0])
return tx
}
function createTokenTx() {
Token = buildContractClass(loadDesc('tokenP2SH_desc.json'))
tokenContract = new Token()
// init token
tokenContract.setDataPart(address1 + num2bin(senderAmount, 8))
console.log(address1, num2bin(senderAmount, 8))
let inputAmount = 699000
let outAmount1 = 100000
let fee = 5000
let outAmount2 = inputAmount - outAmount1 - fee
const lockingScript = tokenContract.lockingScript
const tx = buildTx(lockingScript, inputAmount, outAmount1, outAmount2, utxo1, outIndex1)
//console.log('createTokenTx:', tx.id, tx.serialize())
return tx
}
function createScriptTx() {
const SellContract = buildContractClass(loadDesc('sellContract_desc.json'))
// swap token for satoshi
tokenSellContract = new SellContract(new Ripemd160(address1), sellBsvAmount)
//console.log('tokenSell args:', address1, sellBsvAmount)
let inputAmount = 710000
let outAmount1 = 5000
let fee = 5000
let outAmount2 = 710000 - outAmount1 - fee
const lockingScript = tokenSellContract.lockingScript
const tx = buildTx(lockingScript, inputAmount, outAmount1, outAmount2, utxo2, outIndex2)
//console.log('createScriptTx:', tx.id, tx.serialize())
return tx
}
function createTokenTransferTx(tokenTx, scriptHash) {
const tx = new bsv.Transaction()
let inputAmount = tokenTx.outputs[0].satoshis
let fee = 4000
let outAmount1 = (inputAmount - fee) / 2
let outAmount2 = inputAmount - fee - outAmount1
let tokenAmount1 = 1000
let tokenAmount2 = senderAmount - tokenAmount1
let prevLockingScript = tokenTx.outputs[0].script
tx.addInput(new bsv.Transaction.Input({
output: new bsv.Transaction.Output({
script: prevLockingScript,
satoshis: inputAmount
}),
prevTxId: tokenTx.id,
outputIndex: 0,
script: bsv.Script.empty()
}))
tokenContract = new Token()
tokenContract.setDataPart(scriptHash + num2bin(tokenAmount1, 8))
const lockingScript = tokenContract.lockingScript
tx.addOutput(new bsv.Transaction.Output({
script: lockingScript,
satoshis: outAmount1,
}))
tokenContract = new Token()
tokenContract.setDataPart(address1 + num2bin(tokenAmount2, 8))
const lockingScript2 = tokenContract.lockingScript
tx.addOutput(new bsv.Transaction.Output({
script: lockingScript2,
satoshis: outAmount2,
}))
//console.log("tokenContract: 1", scriptHash, num2bin(tokenAmount1, 8), lockingScript.toHex())
//console.log("tokenContract: ", address1, num2bin(tokenAmount2, 8), lockingScript2.toHex())
let sigtype = bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID
const preimage = getPreimage(tx, prevLockingScript.toASM(), inputAmount, inputIndex=0, sighashType=sigtype)
let sig = signTx(tx, privateKey, prevLockingScript.toASM(), inputAmount, inputIndex=0, sighashType=sigtype)
const unlockingScript = tokenContract.split(
new SigHashPreimage(toHex(preimage)),
new PubKey(privateKey.publicKey),
new Sig(toHex(sig)),
new Ripemd160(scriptHash),
tokenAmount1,
outAmount1,
new Ripemd160(address1),
tokenAmount2,
outAmount2
).toScript()
//console.log('createTokenTransferTx unlock args:', toHex(preimage), new PubKey(privateKey.publicKey), toHex(sig), scriptHash, tokenAmount1, outAmount1, address1, tokenAmount2, outAmount2)
tx.inputs[0].setScript(unlockingScript)
//console.log('createTokenTransferTx tx:', tx.id, tx.serialize())
return tx
}
function createUnlockScriptHashTx(transferTx, scriptTx) {
const tx = new bsv.Transaction()
let inputAmount1 = scriptTx.outputs[0].satoshis
let inputAmount2 = transferTx.outputs[0].satoshis
let inputAmount3 = 2000000
let fee = 20000
let outAmount1 = sellBsvAmount
let outAmount2 = inputAmount2
let outAmount3 = inputAmount1 + inputAmount2 + inputAmount3 - fee - outAmount1 - outAmount2
let tokenAmount = 1000
let prevLockingScript1 = scriptTx.outputs[0].script
let prevLockingScript2 = transferTx.outputs[0].script
// scriptTx input
tx.addInput(new bsv.Transaction.Input({
output: new bsv.Transaction.Output({
script: prevLockingScript1,
satoshis: inputAmount1
}),
prevTxId: scriptTx.id,
outputIndex: 0,
script: bsv.Script.empty()
}))
// tokenTx input
tx.addInput(new bsv.Transaction.Input({
output: new bsv.Transaction.Output({
script: prevLockingScript2,
satoshis: inputAmount2
}),
prevTxId: transferTx.id,
outputIndex: 0,
script: bsv.Script.empty()
}))
// bsv input
tx.addInput(new bsv.Transaction.Input.PublicKeyHash({
output: new bsv.Transaction.Output({
script: bsv.Script.buildPublicKeyHashOut(privateKey2.toAddress()),
satoshis: inputAmount3
}),
prevTxId: utxo3,
outputIndex: outIndex3,
script: bsv.Script.empty()
}))
// bsv output
tx.addOutput(new bsv.Transaction.Output({
script: bsv.Script.buildPublicKeyHashOut(privateKey.toAddress()),
satoshis: outAmount1,
}))
// token output
tokenContract.setDataPart(address2 + num2bin(tokenAmount, 8))
const lockingScript = tokenContract.lockingScript
//console.log('setDatPart', address2, tokenAmount, outAmount2, lockingScript.toHex())
tx.addOutput(new bsv.Transaction.Output({
script: lockingScript,
satoshis: outAmount2,
}))
// bsv charge
tx.addOutput(new bsv.Transaction.Output({
script: bsv.Script.buildPublicKeyHashOut(privateKey2.toAddress()),
satoshis: outAmount3,
}))
// unlock script 1
let sigtype = bsv.crypto.Signature.SIGHASH_SINGLE | bsv.crypto.Signature.SIGHASH_FORKID
const preimage1 = getPreimage(tx, prevLockingScript1.toASM(), inputAmount1, inputIndex=0, sighashType=sigtype)
const unlockingScript1 = tokenSellContract.unlock(new SigHashPreimage(toHex(preimage1))).toScript()
tx.inputs[0].setScript(unlockingScript1)
//console.log('createUnlockScriptHashTx tokenSell unlock:', toHex(preimage1))
// token contract unlock
const preimage2 = getPreimage(tx, prevLockingScript2.toASM(), inputAmount2, inputIndex=1, sighashType=sigtype)
let arr1 = [...Buffer.from(scriptTx.id, 'hex')].reverse()
let arr2 = [...Buffer.from(transferTx.id, 'hex')].reverse()
let arr3 = [...Buffer.from(utxo3, 'hex')].reverse()
let prevouts = Buffer.concat([
Buffer.from(arr1),
Buffer.from(num2bin(0, 4), 'hex'),
Buffer.from(arr2),
Buffer.from(num2bin(0, 4), 'hex'),
Buffer.from(arr3),
Buffer.from(num2bin(0, 4), 'hex'),
])
prevouts = new Bytes(prevouts.toString('hex'))
const unlockingScript2 = tokenContract.unlockFromScriptHash(
new SigHashPreimage(toHex(preimage2)),
prevouts,
new Bytes(toHex(scriptTx.serialize())),
0,
new Ripemd160(address2)
).toScript()
tx.inputs[1].setScript(unlockingScript2)
//console.log('createUnlockScriptHashTx tokenSell unlock:', toHex(preimage2), prevouts, 0, address2)
let sigtype2 = bsv.crypto.Signature.SIGHASH_ALL | bsv.crypto.Signature.SIGHASH_FORKID
let hashData = bsv.crypto.Hash.sha256ripemd160(privateKey2.publicKey.toBuffer())
let sig = tx.inputs[2].getSignatures(tx, privateKey2, 2, sigtype2, hashData)
tx.inputs[2].addSignature(tx, sig[0])
console.log("createUnlockScriptHashTx:", tx.id, tx.serialize())
return tx
}
(async() => {
try {
let tokenTx = createTokenTx()
let txid = await sendTx(tokenTx)
console.log('tokenTx id:', txid)
let scriptTx = createScriptTx()
txid = await sendTx(scriptTx)
console.log('scriptTx id:', txid)
let scriptCode = scriptTx.outputs[0].script.toHex()
let scriptHash = toHex(bsv.crypto.Hash.sha256ripemd160(Buffer.from(scriptCode, 'hex')))
let transferTx = createTokenTransferTx(tokenTx, scriptHash)
txid = await sendTx(transferTx)
console.log('transferTx id:', txid)
let unlockTokenSHTx = createUnlockScriptHashTx(transferTx, scriptTx)
txid = await sendTx(unlockTokenSHTx)
console.log('unlockTokenSHTx id:', txid)
} catch (error) {
console.log('Failed on testnet')
showError(error)
}
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment