diff --git a/src/main/java/org/qortal/controller/TradeBot.java b/src/main/java/org/qortal/controller/TradeBot.java index d054b27e..7ad551e5 100644 --- a/src/main/java/org/qortal/controller/TradeBot.java +++ b/src/main/java/org/qortal/controller/TradeBot.java @@ -39,6 +39,7 @@ import org.qortal.transaction.MessageTransaction; import org.qortal.transaction.Transaction.ValidationResult; import org.qortal.transform.TransformationException; import org.qortal.transform.transaction.DeployAtTransactionTransformer; +import org.qortal.utils.Amounts; import org.qortal.utils.NTP; public class TradeBot { @@ -837,9 +838,15 @@ public class TradeBot { // Not finished yet return; - // If AT's balance is zero, then it's auto-refunded so we're done + // If AT's balance should be zero AccountBalanceData atBalanceData = repository.getAccountRepository().getBalance(tradeBotData.getAtAddress(), Asset.QORT); - if (atBalanceData == null || atBalanceData.getBalance() == 0L) { + if (atBalanceData != null && atBalanceData.getBalance() > 0L) { + LOGGER.debug(() -> String.format("AT %s should have zero balance, not %s", tradeBotData.getAtAddress(), Amounts.prettyAmount(atBalanceData.getBalance()))); + return; + } + + // We check variable in AT that is set when trade successfully completes + if (!crossChainTradeData.hasRedeemed) { tradeBotData.setState(TradeBotData.State.BOB_REFUNDED); repository.getCrossChainRepository().save(tradeBotData); repository.saveChanges(); diff --git a/src/main/java/org/qortal/crosschain/BTCACCT.java b/src/main/java/org/qortal/crosschain/BTCACCT.java index da7ed7a1..ab64ae09 100644 --- a/src/main/java/org/qortal/crosschain/BTCACCT.java +++ b/src/main/java/org/qortal/crosschain/BTCACCT.java @@ -92,7 +92,7 @@ public class BTCACCT { public static final int SECRET_LENGTH = 32; public static final int MIN_LOCKTIME = 1500000000; - public static final byte[] CODE_BYTES_HASH = HashCode.fromString("58542b1d204d7034280fb85e8053c056353fcc9c3870c062a19b2fc17f764092").asBytes(); // SHA256 of AT code bytes + public static final byte[] CODE_BYTES_HASH = HashCode.fromString("f62e1447e8361703c261c8e8e1973713d29b713716582f491431cb7f6ee99e80").asBytes(); // SHA256 of AT code bytes public static class OfferMessageData { public byte[] recipientBitcoinPKH; @@ -201,6 +201,8 @@ public class BTCACCT { final int addrMode = addrCounter++; + final int addrRedeemFlag = addrCounter++; + // Data segment ByteBuffer dataByteBuffer = ByteBuffer.allocate(addrCounter * MachineState.VALUE_SIZE); @@ -500,6 +502,9 @@ public class BTCACCT { codeByteBuffer.put(OpCode.EXT_FUN_DAT.compile(FunctionCode.SET_B_IND, addrQortalRecipientPointer)); // Pay AT's balance to recipient codeByteBuffer.put(OpCode.EXT_FUN_DAT.compile(FunctionCode.PAY_TO_ADDRESS_IN_B, addrQortAmount)); + // Set redeem flag + codeByteBuffer.put(OpCode.INC_DAT.compile(addrRedeemFlag)); + // Fall-through to refunding any remaining balance back to AT creator /* Refund balance back to AT creator */ @@ -686,6 +691,8 @@ public class BTCACCT { long mode = dataByteBuffer.getLong(); + long redeemFlag = dataByteBuffer.getLong(); + if (mode != 0) { tradeData.mode = CrossChainTradeData.Mode.TRADE; tradeData.refundTimeout = refundTimeout; @@ -695,6 +702,7 @@ public class BTCACCT { tradeData.recipientBitcoinPKH = recipientBitcoinPKH; tradeData.lockTimeA = lockTimeA; tradeData.lockTimeB = lockTimeB; + tradeData.hasRedeemed = redeemFlag != 0; } else { tradeData.mode = CrossChainTradeData.Mode.OFFER; } diff --git a/src/main/java/org/qortal/data/crosschain/CrossChainTradeData.java b/src/main/java/org/qortal/data/crosschain/CrossChainTradeData.java index 1ad50218..68a6124e 100644 --- a/src/main/java/org/qortal/data/crosschain/CrossChainTradeData.java +++ b/src/main/java/org/qortal/data/crosschain/CrossChainTradeData.java @@ -79,6 +79,9 @@ public class CrossChainTradeData { @Schema(description = "Trade partner's Bitcoin public-key-hash (PKH)") public byte[] recipientBitcoinPKH; + @Schema(description = "Whether AT has paid out to trade partner") + public Boolean hasRedeemed; + // Constructors // Necessary for JAXB