Created
December 9, 2020 09:13
-
-
Save ccoincash/0046bdd0c1f858ae91bd9fea6b62f6de to your computer and use it in GitHub Desktop.
deploy tokenP2SH contract
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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