forked from Qortal/qortal
Reduce bitcoinj exposure to classes outside of org.qortal.crosschain package.
BTC.getBalance() now returns Long instead of Coin. BTC.FORMAT.format(Coin) changed to BTC.format(Coin or long). Added BTC.deriveP2shAddress(byte[] redeemScriptBytes).
This commit is contained in:
parent
04d691991a
commit
593b61ea4b
@ -498,17 +498,17 @@ public class CrossChainResource {
|
||||
|
||||
// Check P2SH is funded
|
||||
|
||||
Coin p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
Long p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
if (p2shBalance == null)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.ADDRESS_UNKNOWN);
|
||||
|
||||
CrossChainBitcoinP2SHStatus p2shStatus = new CrossChainBitcoinP2SHStatus();
|
||||
p2shStatus.bitcoinP2shAddress = p2shAddress.toString();
|
||||
p2shStatus.bitcoinP2shBalance = BigDecimal.valueOf(p2shBalance.value, 8);
|
||||
p2shStatus.bitcoinP2shBalance = BigDecimal.valueOf(p2shBalance, 8);
|
||||
|
||||
List<TransactionOutput> fundingOutputs = BTC.getInstance().getUnspentOutputs(p2shAddress.toString());
|
||||
|
||||
if (p2shBalance.value >= crossChainTradeData.expectedBitcoin && !fundingOutputs.isEmpty()) {
|
||||
if (p2shBalance >= crossChainTradeData.expectedBitcoin && !fundingOutputs.isEmpty()) {
|
||||
p2shStatus.canRedeem = now >= medianBlockTime * 1000L;
|
||||
p2shStatus.canRefund = now >= crossChainTradeData.lockTime * 1000L;
|
||||
}
|
||||
@ -591,7 +591,7 @@ public class CrossChainResource {
|
||||
|
||||
// Check P2SH is funded
|
||||
|
||||
Coin p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
Long p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
if (p2shBalance == null)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.ADDRESS_UNKNOWN);
|
||||
|
||||
@ -603,10 +603,10 @@ public class CrossChainResource {
|
||||
if (!canRefund)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BTC_TOO_SOON);
|
||||
|
||||
if (p2shBalance.value < crossChainTradeData.expectedBitcoin)
|
||||
if (p2shBalance < crossChainTradeData.expectedBitcoin)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BTC_BALANCE_ISSUE);
|
||||
|
||||
Coin refundAmount = p2shBalance.subtract(Coin.valueOf(refundRequest.bitcoinMinerFee.unscaledValue().longValue()));
|
||||
Coin refundAmount = Coin.valueOf(p2shBalance - refundRequest.bitcoinMinerFee.unscaledValue().longValue());
|
||||
|
||||
org.bitcoinj.core.Transaction refundTransaction = BTCACCT.buildRefundTransaction(refundAmount, refundKey, fundingOutputs, redeemScriptBytes, crossChainTradeData.lockTime);
|
||||
boolean wasBroadcast = BTC.getInstance().broadcastTransaction(refundTransaction);
|
||||
@ -692,11 +692,11 @@ public class CrossChainResource {
|
||||
long now = NTP.getTime();
|
||||
|
||||
// Check P2SH is funded
|
||||
Coin p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
Long p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
if (p2shBalance == null)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.ADDRESS_UNKNOWN);
|
||||
|
||||
if (p2shBalance.value < crossChainTradeData.expectedBitcoin)
|
||||
if (p2shBalance < crossChainTradeData.expectedBitcoin)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BTC_BALANCE_ISSUE);
|
||||
|
||||
List<TransactionOutput> fundingOutputs = BTC.getInstance().getUnspentOutputs(p2shAddress.toString());
|
||||
@ -707,7 +707,7 @@ public class CrossChainResource {
|
||||
if (!canRedeem)
|
||||
throw ApiExceptionFactory.INSTANCE.createException(request, ApiError.BTC_TOO_SOON);
|
||||
|
||||
Coin redeemAmount = p2shBalance.subtract(Coin.valueOf(redeemRequest.bitcoinMinerFee.unscaledValue().longValue()));
|
||||
Coin redeemAmount = Coin.valueOf(p2shBalance - redeemRequest.bitcoinMinerFee.unscaledValue().longValue());
|
||||
|
||||
org.bitcoinj.core.Transaction redeemTransaction = BTCACCT.buildRedeemTransaction(redeemAmount, redeemKey, fundingOutputs, redeemScriptBytes, redeemRequest.secret);
|
||||
boolean wasBroadcast = BTC.getInstance().broadcastTransaction(redeemTransaction);
|
||||
|
@ -8,6 +8,7 @@ import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bitcoinj.core.Address;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.bitcoinj.core.LegacyAddress;
|
||||
import org.bitcoinj.core.NetworkParameters;
|
||||
import org.bitcoinj.core.Transaction;
|
||||
import org.bitcoinj.core.TransactionOutput;
|
||||
@ -16,13 +17,13 @@ import org.bitcoinj.params.RegTestParams;
|
||||
import org.bitcoinj.params.TestNet3Params;
|
||||
import org.bitcoinj.script.ScriptBuilder;
|
||||
import org.bitcoinj.utils.MonetaryFormat;
|
||||
import org.qortal.crypto.Crypto;
|
||||
import org.qortal.settings.Settings;
|
||||
import org.qortal.utils.BitTwiddling;
|
||||
import org.qortal.utils.Pair;
|
||||
|
||||
public class BTC {
|
||||
|
||||
public static final MonetaryFormat FORMAT = new MonetaryFormat().minDecimals(8).postfixCode();
|
||||
public static final long NO_LOCKTIME_NO_RBF_SEQUENCE = 0xFFFFFFFFL;
|
||||
public static final long LOCKTIME_NO_RBF_SEQUENCE = NO_LOCKTIME_NO_RBF_SEQUENCE - 1;
|
||||
public static final int HASH160_LENGTH = 20;
|
||||
@ -30,6 +31,7 @@ public class BTC {
|
||||
protected static final Logger LOGGER = LogManager.getLogger(BTC.class);
|
||||
|
||||
private static final int TIMESTAMP_OFFSET = 4 + 32 + 32;
|
||||
private static final MonetaryFormat FORMAT = new MonetaryFormat().minDecimals(8).postfixCode();
|
||||
|
||||
public enum BitcoinNet {
|
||||
MAIN {
|
||||
@ -88,6 +90,20 @@ public class BTC {
|
||||
|
||||
// Actual useful methods for use by other classes
|
||||
|
||||
public static String format(Coin amount) {
|
||||
return BTC.FORMAT.format(amount).toString();
|
||||
}
|
||||
|
||||
public static String format(long amount) {
|
||||
return format(Coin.valueOf(amount));
|
||||
}
|
||||
|
||||
public String deriveP2shAddress(byte[] redeemScriptBytes) {
|
||||
byte[] redeemScriptHash = Crypto.hash160(redeemScriptBytes);
|
||||
Address p2shAddress = LegacyAddress.fromScriptHash(params, redeemScriptHash);
|
||||
return p2shAddress.toString();
|
||||
}
|
||||
|
||||
/** Returns median timestamp from latest 11 blocks, in seconds. */
|
||||
public Integer getMedianBlockTime() {
|
||||
Integer height = this.electrumX.getCurrentHeight();
|
||||
@ -107,12 +123,8 @@ public class BTC {
|
||||
return blockTimestamps.get(5);
|
||||
}
|
||||
|
||||
public Coin getBalance(String base58Address) {
|
||||
Long balance = this.electrumX.getBalance(addressToScript(base58Address));
|
||||
if (balance == null)
|
||||
return null;
|
||||
|
||||
return Coin.valueOf(balance);
|
||||
public Long getBalance(String base58Address) {
|
||||
return this.electrumX.getBalance(addressToScript(base58Address));
|
||||
}
|
||||
|
||||
public List<TransactionOutput> getUnspentOutputs(String base58Address) {
|
||||
|
@ -98,7 +98,7 @@ public class BuildP2SH {
|
||||
System.out.println(String.format("Bitcoin redeem amount: %s", bitcoinAmount.toPlainString()));
|
||||
|
||||
System.out.println(String.format("Redeem Bitcoin address: %s", redeemBitcoinAddress));
|
||||
System.out.println(String.format("Redeem miner's fee: %s", BTC.FORMAT.format(bitcoinFee)));
|
||||
System.out.println(String.format("Redeem miner's fee: %s", BTC.format(bitcoinFee)));
|
||||
|
||||
System.out.println(String.format("Redeem script lockTime: %s (%d)", LocalDateTime.ofInstant(Instant.ofEpochSecond(lockTime), ZoneOffset.UTC), lockTime));
|
||||
System.out.println(String.format("Hash of secret: %s", HashCode.fromBytes(secretHash)));
|
||||
@ -115,7 +115,7 @@ public class BuildP2SH {
|
||||
|
||||
// Fund P2SH
|
||||
System.out.println(String.format("\nYou need to fund %s with %s (includes redeem/refund fee of %s)",
|
||||
p2shAddress.toString(), BTC.FORMAT.format(bitcoinAmount), BTC.FORMAT.format(bitcoinFee)));
|
||||
p2shAddress.toString(), BTC.format(bitcoinAmount), BTC.format(bitcoinFee)));
|
||||
|
||||
System.out.println("Once this is done, responder should run Respond to check P2SH funding and create AT");
|
||||
} catch (DataException e) {
|
||||
|
@ -106,7 +106,7 @@ public class CheckP2SH {
|
||||
System.out.println(String.format("Bitcoin redeem amount: %s", bitcoinAmount.toPlainString()));
|
||||
|
||||
System.out.println(String.format("Redeem Bitcoin address: %s", refundBitcoinAddress));
|
||||
System.out.println(String.format("Redeem miner's fee: %s", BTC.FORMAT.format(bitcoinFee)));
|
||||
System.out.println(String.format("Redeem miner's fee: %s", BTC.format(bitcoinFee)));
|
||||
|
||||
System.out.println(String.format("Redeem script lockTime: %s (%d)", LocalDateTime.ofInstant(Instant.ofEpochSecond(lockTime), ZoneOffset.UTC), lockTime));
|
||||
System.out.println(String.format("Hash of secret: %s", HashCode.fromBytes(secretHash)));
|
||||
@ -135,12 +135,12 @@ public class CheckP2SH {
|
||||
System.out.println(String.format("Too soon (%s) to redeem based on median block time %s", LocalDateTime.ofInstant(Instant.ofEpochMilli(now), ZoneOffset.UTC), LocalDateTime.ofInstant(Instant.ofEpochSecond(medianBlockTime), ZoneOffset.UTC)));
|
||||
|
||||
// Check P2SH is funded
|
||||
Coin p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
Long p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
if (p2shBalance == null) {
|
||||
System.err.println(String.format("Unable to check P2SH address %s balance", p2shAddress));
|
||||
System.exit(2);
|
||||
}
|
||||
System.out.println(String.format("P2SH address %s balance: %s", p2shAddress, BTC.FORMAT.format(p2shBalance)));
|
||||
System.out.println(String.format("P2SH address %s balance: %s", p2shAddress, BTC.format(p2shBalance)));
|
||||
|
||||
// Grab all P2SH funding transactions (just in case there are more than one)
|
||||
List<TransactionOutput> fundingOutputs = BTC.getInstance().getUnspentOutputs(p2shAddress.toString());
|
||||
@ -152,7 +152,7 @@ public class CheckP2SH {
|
||||
System.out.println(String.format("Found %d output%s for P2SH", fundingOutputs.size(), (fundingOutputs.size() != 1 ? "s" : "")));
|
||||
|
||||
for (TransactionOutput fundingOutput : fundingOutputs)
|
||||
System.out.println(String.format("Output %s:%d amount %s", HashCode.fromBytes(fundingOutput.getParentTransactionHash().getBytes()), fundingOutput.getIndex(), BTC.FORMAT.format(fundingOutput.getValue())));
|
||||
System.out.println(String.format("Output %s:%d amount %s", HashCode.fromBytes(fundingOutput.getParentTransactionHash().getBytes()), fundingOutput.getIndex(), BTC.format(fundingOutput.getValue())));
|
||||
|
||||
if (fundingOutputs.isEmpty()) {
|
||||
System.err.println(String.format("Can't redeem spent/unfunded P2SH"));
|
||||
|
@ -107,7 +107,7 @@ public class Redeem {
|
||||
System.out.println("Confirm the following is correct based on the info you've given:");
|
||||
|
||||
System.out.println(String.format("Redeem PRIVATE key: %s", HashCode.fromBytes(redeemPrivateKey)));
|
||||
System.out.println(String.format("Redeem miner's fee: %s", BTC.FORMAT.format(bitcoinFee)));
|
||||
System.out.println(String.format("Redeem miner's fee: %s", BTC.format(bitcoinFee)));
|
||||
System.out.println(String.format("Redeem script lockTime: %s (%d)", LocalDateTime.ofInstant(Instant.ofEpochSecond(lockTime), ZoneOffset.UTC), lockTime));
|
||||
|
||||
// New/derived info
|
||||
@ -147,12 +147,12 @@ public class Redeem {
|
||||
}
|
||||
|
||||
// Check P2SH is funded
|
||||
Coin p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
Long p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
if (p2shBalance == null) {
|
||||
System.err.println(String.format("Unable to check P2SH address %s balance", p2shAddress));
|
||||
System.exit(2);
|
||||
}
|
||||
System.out.println(String.format("P2SH address %s balance: %s BTC", p2shAddress, p2shBalance.toPlainString()));
|
||||
System.out.println(String.format("P2SH address %s balance: %s", p2shAddress, BTC.format(p2shBalance)));
|
||||
|
||||
// Grab all P2SH funding transactions (just in case there are more than one)
|
||||
List<TransactionOutput> fundingOutputs = BTC.getInstance().getUnspentOutputs(p2shAddress.toString());
|
||||
@ -164,7 +164,7 @@ public class Redeem {
|
||||
System.out.println(String.format("Found %d output%s for P2SH", fundingOutputs.size(), (fundingOutputs.size() != 1 ? "s" : "")));
|
||||
|
||||
for (TransactionOutput fundingOutput : fundingOutputs)
|
||||
System.out.println(String.format("Output %s:%d amount %s", HashCode.fromBytes(fundingOutput.getParentTransactionHash().getBytes()), fundingOutput.getIndex(), BTC.FORMAT.format(fundingOutput.getValue())));
|
||||
System.out.println(String.format("Output %s:%d amount %s", HashCode.fromBytes(fundingOutput.getParentTransactionHash().getBytes()), fundingOutput.getIndex(), BTC.format(fundingOutput.getValue())));
|
||||
|
||||
if (fundingOutputs.isEmpty()) {
|
||||
System.err.println(String.format("Can't redeem spent/unfunded P2SH"));
|
||||
@ -179,8 +179,8 @@ public class Redeem {
|
||||
for (TransactionOutput fundingOutput : fundingOutputs)
|
||||
System.out.println(String.format("Using output %s:%d for redeem", HashCode.fromBytes(fundingOutput.getParentTransactionHash().getBytes()), fundingOutput.getIndex()));
|
||||
|
||||
Coin redeemAmount = p2shBalance.subtract(bitcoinFee);
|
||||
System.out.println(String.format("Spending %s of output, with %s as mining fee", BTC.FORMAT.format(redeemAmount), BTC.FORMAT.format(bitcoinFee)));
|
||||
Coin redeemAmount = Coin.valueOf(p2shBalance).subtract(bitcoinFee);
|
||||
System.out.println(String.format("Spending %s of output, with %s as mining fee", BTC.format(redeemAmount), BTC.format(bitcoinFee)));
|
||||
|
||||
Transaction redeemTransaction = BTCACCT.buildRedeemTransaction(redeemAmount, redeemKey, fundingOutputs, redeemScriptBytes, secret);
|
||||
|
||||
|
@ -110,7 +110,7 @@ public class Refund {
|
||||
System.out.println(String.format("Redeem Bitcoin address: %s", redeemBitcoinAddress));
|
||||
System.out.println(String.format("Redeem script lockTime: %s (%d)", LocalDateTime.ofInstant(Instant.ofEpochSecond(lockTime), ZoneOffset.UTC), lockTime));
|
||||
System.out.println(String.format("P2SH address: %s", p2shAddress));
|
||||
System.out.println(String.format("Refund miner's fee: %s", BTC.FORMAT.format(bitcoinFee)));
|
||||
System.out.println(String.format("Refund miner's fee: %s", BTC.format(bitcoinFee)));
|
||||
|
||||
// New/derived info
|
||||
|
||||
@ -151,12 +151,12 @@ public class Refund {
|
||||
}
|
||||
|
||||
// Check P2SH is funded
|
||||
Coin p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
Long p2shBalance = BTC.getInstance().getBalance(p2shAddress.toString());
|
||||
if (p2shBalance == null) {
|
||||
System.err.println(String.format("Unable to check P2SH address %s balance", p2shAddress));
|
||||
System.exit(2);
|
||||
}
|
||||
System.out.println(String.format("P2SH address %s balance: %s BTC", p2shAddress, p2shBalance.toPlainString()));
|
||||
System.out.println(String.format("P2SH address %s balance: %s", p2shAddress, BTC.format(p2shBalance)));
|
||||
|
||||
// Grab all P2SH funding transactions (just in case there are more than one)
|
||||
List<TransactionOutput> fundingOutputs = BTC.getInstance().getUnspentOutputs(p2shAddress.toString());
|
||||
@ -168,7 +168,7 @@ public class Refund {
|
||||
System.out.println(String.format("Found %d output%s for P2SH", fundingOutputs.size(), (fundingOutputs.size() != 1 ? "s" : "")));
|
||||
|
||||
for (TransactionOutput fundingOutput : fundingOutputs)
|
||||
System.out.println(String.format("Output %s:%d amount %s", HashCode.fromBytes(fundingOutput.getParentTransactionHash().getBytes()), fundingOutput.getIndex(), BTC.FORMAT.format(fundingOutput.getValue())));
|
||||
System.out.println(String.format("Output %s:%d amount %s", HashCode.fromBytes(fundingOutput.getParentTransactionHash().getBytes()), fundingOutput.getIndex(), BTC.format(fundingOutput.getValue())));
|
||||
|
||||
if (fundingOutputs.isEmpty()) {
|
||||
System.err.println(String.format("Can't refund spent/unfunded P2SH"));
|
||||
@ -183,8 +183,8 @@ public class Refund {
|
||||
for (TransactionOutput fundingOutput : fundingOutputs)
|
||||
System.out.println(String.format("Using output %s:%d for redeem", HashCode.fromBytes(fundingOutput.getParentTransactionHash().getBytes()), fundingOutput.getIndex()));
|
||||
|
||||
Coin refundAmount = p2shBalance.subtract(bitcoinFee);
|
||||
System.out.println(String.format("Spending %s of output, with %s as mining fee", BTC.FORMAT.format(refundAmount), BTC.FORMAT.format(bitcoinFee)));
|
||||
Coin refundAmount = Coin.valueOf(p2shBalance).subtract(bitcoinFee);
|
||||
System.out.println(String.format("Spending %s of output, with %s as mining fee", BTC.format(refundAmount), BTC.format(bitcoinFee)));
|
||||
|
||||
Transaction redeemTransaction = BTCACCT.buildRefundTransaction(refundAmount, refundKey, fundingOutputs, redeemScriptBytes, lockTime);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user