Skip to content

Instantly share code, notes, and snippets.

@saltyskip
Last active May 11, 2021 04:20
Show Gist options
  • Save saltyskip/c305a91a6bfca767b177ca81d93824ff to your computer and use it in GitHub Desktop.
Save saltyskip/c305a91a6bfca767b177ca81d93824ff to your computer and use it in GitHub Desktop.
let wif = ""
let pubkeyCompressed = "028013a81902a823dec80b54b5e1591b8d2fa359e9024934dae604aaa3be7dc020"
let pubkeyUncompressed = "048013a81902a823dec80b54b5e1591b8d2fa359e9024934dae604aaa3be7dc0202c487e634ab286179f6fefd9689e30465b6bbf658408928ddb01a419a81bf168"
let addressCompressed = "1KM68pTTgD172nJqykCUPpMA7hT7aGnn7w"
let addressUncompressed = "1KRhiKNai3ke3hZgSPZ5TpJoSJvs1aZfWo" //funds are here
var allAvailableUtxos = [
InputUtxo(
txid: "fd1ea8178228e825d4106df0acb61a4fb14a8f04f30cd7c1f39c665c9427bf13"
satoshis: 10098,
vout: 0,
x: 0,
y: 0
),
InputUtxo(
txid: "6ae3f1d245521b0ea7627231d27d613d58c237d6bf97a1471341a3532e31906c"
satoshis: 16874,
vout: 0,
x: 0,
y: 0
)
]
func lockScriptForAddress(wif: String) -> Data {
let isCompressed = wif.starts(with: "K") || wif.starts(with: "L")
let privKey = PrivateKey(wif: wif)!
let publicKey = privKey.getPublicKeySecp256k1(compressed: isCompressed)
let hashedMainnet = [0x00] + Hash.sha256RIPEMD(data: publicKey.data)
let doubleSha = Hash.sha256SHA256(data: Data(hashedMainnet))
let doubleShaChecked = hashedMainnet + doubleSha[0..<4]
let address = Base58.encodeNoCheck(data: Data(doubleShaChecked))
let scriptp2pkh = BitcoinScript.buildPayToPublicKeyHash(hash: Hash.ripemd(data: publicKey.data))
let scriptAddr = BitcoinScript.lockScriptForAddress(address: address, coin: .bitcoin)
debugPrint(scriptp2pkh.data.hex)
debugPrint(scriptAddr.data.hex)
return scriptAddr
}
func createTx() throws {
let masterKey = PrivateKey(wif: wif)!
let utxos: [TW_Bitcoin_Proto_UnspentTransaction] = allAvailableUTXOs.map { utxo in
BitcoinUnspentTransaction.with {
$0.outPoint.hash = utxo.hash
$0.outPoint.index = UInt32(utxo.vout)
$0.outPoint.sequence = UINT32_MAX
$0.amount = NSDecimalNumber(decimal: utxo.satoshis).int64Value
$0.script = lockScriptForAddress(wif: wif)
}
}
var keys: [Data] = []
for _ in utxos {
keys.append(masterKey.data)
}
var hashType = BitcoinSigHashType.all.rawValue
if chainAssetProtocol.toChain() == .bitcoinCash {
hashType = BitcoinSigHashType.all.rawValue | BitcoinSigHashType.fork.rawValue
}
let input = BitcoinSigningInput.with {
$0.hashType = hashType
$0.byteFee = satsPerByteFee
$0.toAddress = destination
$0.coinType = chainAssetProtocol.toChain().toTrustCoin().rawValue
$0.utxo = utxos
$0.privateKey = keys
$0.useMaxAmount = true
}
let output: BitcoinSigningOutput = AnySigner.sign(input: input, coin: chainAssetProtocol.toChain().toTrustCoin())
guard output.error == .ok else {
throw SendTxError(output.error) //throws missing input here
}
}
extension CoinType {
var keyPrefix: UInt8 {
switch self {
case .bitcoin:
return 0x80
case .litecoin:
return 0xb0
case .dash:
return 0xcc
case .zcoin:
return 0xd2
default:
fatalError("no private prefix: \(self)")
}
}
}
extension PrivateKey {
/// Creates a `PrivateKey` from a Bitcoin WIF (wallet import format) string.
static let prefixSet = Set<UInt8>([CoinType.bitcoin, .litecoin, .dash, .zcoin].map {$0.keyPrefix})
public convenience init?(wif: String) {
guard let decoded = Base58.decode(string: wif) else {
return nil
}
guard PrivateKey.prefixSet.contains(decoded[0]) else {
return nil
}
if decoded.count == 34 && decoded.last != 0x01 {
return nil
}
self.init(data: Data(decoded[1 ..< 33]))
}
public func wif(for coin: CoinType = .bitcoin) -> String {
let result = Data(bytes: [coin.keyPrefix]) + data
let check = Hash.sha256SHA256(data: result)[0..<4]
return Base58.encodeNoCheck(data: result + check)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment