-1

I have a webhook that sends a header, which needs to be verified. Below are some details:

Problem :

The Java method always returns false. The provided header and body are correct and should result as TRUE.

As per docs from the provider :

Signature = Base64(RSA512(WEBHOOK_PRIVATE_KEY, SHA512(eventBody)))

Public Key :

-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0+6wd9OJQpK60ZI7qnZG
jjQ0wNFUHfRv85Tdyek8+ahlg1Ph8uhwl4N6DZw5LwLXhNjzAbQ8LGPxt36RUZl5
YlxTru0jZNKx5lslR+H4i936A4pKBjgiMmSkVwXD9HcfKHTp70GQ812+J0Fvti/v
4nrrUpc011Wo4F6omt1QcYsi4GTI5OsEbeKQ24BtUd6Z1Nm/EP7PfPxeb4CP8KOH
clM8K7OwBUfWrip8Ptljjz9BNOZUF94iyjJ/BIzGJjyCntho64ehpUYP8UJykLVd
CGcu7sVYWnknf1ZGLuqqZQt4qt7cUUhFGielssZP9N9x7wzaAIFcT3yQ+ELDu1SZ
dE4lZsf2uMyfj58V8GDOLLE233+LRsRbJ083x+e2mW5BdAGtGgQBusFfnmv5Bxqd
HgS55hsna5725/44tvxll261TgQvjGrTxwe7e5Ia3d2Syc+e89mXQaI/+cZnylNP
SwCCvx8mOM847T0XkVRX3ZrwXtHIA25uKsPJzUtksDnAowB91j7RJkjXxJcz3Vh1
4k182UFOTPRW9jzdWNSyWQGl/vpe9oQ4c2Ly15+/toBo4YXJeDdDnZ5c/O+KKadc
IMPBpnPrH/0O97uMPuED+nI6ISGOTMLZo35xJ96gPBwyG5s2QxIkKPXIrhgcgUnk
tSM7QYNhlftT4/yVvYnk0YcCAwEAAQ==
-----END PUBLIC KEY-----

Header :

YNYVgWsx3PdoEGq2nUFGLmE6tE2y0LCc/eWPSY+rAqK+8fcxrPN0SPGbTdAXQ9+v62T5akWaVRWKXc1YBWlZxhVTCa/Ou7FfjVPG6JIQNX3Lks3ZhW0k29bVKf7Qvjp7z8HM9s1D8ZC28HvpX15a4by7DpNKkQ6cLWMDtBvqY02FSO+L4Vq54GZoTrplYkqCYcI4/oWchYzMZMq4omIOuam2DXm5BLlZ7HCR/nhUyp5duJpYnWJCKEwOTh3zLm842r5Fa9humq9WKkkT+AgFxe95bG4F3p8XhsciXiaNgx8diKLF0aBklqJ6yA70vjIP92BHuEnvIl37RiSFiIvkYWvLpMc1LoPxWZvncaLUjlYSVT3zd/gCDPEn1Mu8wUogGt9npkc/eKMdrKefcjEIMrJoO0HMMREZcOpc72F0+RM4QCkMaQMmK4zq9cBF0E2bNaEabNDSWXIfx9fa2VuyGYa5GLmAPUQPYRv50n92IGFewxj9vFAWhca+uthvsqz3FekyHK+c9G1Wh9OScR2TQp9Lbe4LqlX4FGapQitmfDvKRJhjAVm0n5355+k1dRse4fGeXqd2EfledWUJ3egpmW1NlmWBr8d4PsruKYZnphEMn9F5F3Vyu2sCpBSvqmcMANXzyZP7u3lGsUpH4V2lM6nCeBiRcbfwyrFsJ6Q5dso=

RequestBody:

{"type":"TRANSACTION_STATUS_UPDATED","tenantId":"f4df1e73-ec68-53c5-aa92-1a2bc45900ef","timestamp":1671288284087,"data":{"id":"b96f37dd-0fe9-4aa0-853b-f7d39c2ddc52","createdAt":1671286112004,"lastUpdated":1671286112019,"assetId":"BTC_TEST","source":{"id":"","type":"UNKNOWN","name":"External","subType":""},"destination":{"id":"26","type":"VAULT_ACCOUNT","name":"55b49ae0-0f34-4b3c-8cf6-0094254261c2","subType":""},"amount":1.0E-5,"networkFee":1.41E-6,"netAmount":1.0E-5,"sourceAddress":"tb1qluc5wgms8kpu0tydu00590qryfan3969jvmc8e","destinationAddress":"tb1qyhfnsfe2dy8az3040yvx087qdfsw6yxk8pc7yj","destinationAddressDescription":"","destinationTag":"","status":"CONFIRMING","txHash":"15873dc631db22a1bd13c6adecf7fb63f8fbbecce36eb38d12df65573e83dfa9","subStatus":"PENDING_BLOCKCHAIN_CONFIRMATIONS","signedBy":[],"createdBy":"","rejectedBy":"","amountUSD":0.17,"addressType":"","note":"","exchangeTxId":"","requestedAmount":1.0E-5,"feeCurrency":"BTC_TEST","operation":"TRANSFER","customerRefId":null,"numOfConfirmations":2,"amountInfo":{"amount":"0.00001","requestedAmount":"0.00001","netAmount":"0.00001","amountUSD":"0.17"},"feeInfo":{"networkFee":"0.00000141"},"destinations":[],"externalTxId":null,"blockInfo":{"blockHeight":"2411637","blockHash":"00000000d45b7ebf40921cbc70fb6791985a0b256241757a28bf762be07478e8"},"signedMessages":[],"index":1}}

Java method that's called when webhook event is received :

public boolean matches(WebhookEvent body, String header){

        try {
            File publicKeyFile = new File("publicKey.pub");

            byte[] bytes = PemUtils.parsePEMFile(publicKeyFile);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
            PublicKey publicKey = kf.generatePublic(spec);

            ObjectMapper objectMapper = new ObjectMapper();
            String message = objectMapper.writeValueAsString(body);

            Signature verifier = Signature.getInstance("SHA512withRSA");
            verifier.initVerify(publicKey);
            verifier.update(message.getBytes());

            boolean isVerified = verifier.verify(Base64.getDecoder().decode(header));
            System.out.println("Verified: " + isVerified);

            return isVerified;
        } catch (Exception e){
            log.error("Error while verifying signature : " + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }

PemFile parser :

    static byte[] parsePEMFile(File pemFile) throws IOException {
        if (!pemFile.isFile() || !pemFile.exists()) {
            throw new FileNotFoundException(String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath()));
        }
        PemReader reader = new PemReader(new FileReader(pemFile));
        PemObject pemObject = reader.readPemObject();
        byte[] content = pemObject.getContent();
        reader.close();
        return content;
    }

Request POJO

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class WebhookEvent {

    @JsonProperty(value = "type")
    private FireblocksEventType eventType;

    @JsonProperty(value = "tenantId")
    private String tenantId;

    @JsonProperty(value = "timestamp")
    private long timestamp;

    @JsonProperty(value = "data")
    private TransactionDetailObject eventData;
}

TransactionDetailObject :

@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class TransactionDetailObject {

    private String id;
    private String assetId;
    private TransferPeerPathResponse source;
    private TransferPeerPathResponse destination;
    private BigDecimal requestedAmount;
    private AmountInfo amountInfo;
    private FeeInfo feeinfo;
    private BigDecimal amount;
    private BigDecimal netAmount;
    private BigDecimal amountUSD;
    private BigDecimal serviceFee;
    private Boolean treatAsGrossAmount;
    private BigDecimal networkFee;
    private Long createdAt;
    private Long lastUpdated;
    private TransactionStatus status;
    private String txHash;
    private Long index;
    private TransactionSubStatus subStatus;
    private String sourceAddress;
    private String destinationAddress;
    private String destinationAddressDescription;
    private String destinationTag;
    private List<String> signedBy;
    private String createdBy;
    private String rejectedBy;
    private String addressType;
    private String note;
    private String exchangeTxId;
    private String feeCurrency;
    private TransactionOperation operation;
    private AmlScreeningResult amlScreeningResult;
    private String customerRefId;
    private Long numOfConfirmations;
    private List<NetworkRecord>networkRecords;
    private String replacedTxHash;
    private String externalTxId;
    private List<DestinationResponse>destinations;
    private BlockInfo blockInfo;
    private RewardsInfo rewardsInfo;
    private AuthorizationInfo authorizationInfo;
    private List<SignedMessage>signedMessages;
    private Object extraParameters;
}
  • The definition of `WebhookEvent` (incl. class hierarchy, if any) for the mapping to a string is missing. – Topaco Dec 20 '22 at 16:54
  • I am sorry, I didn't get your query. WebhookEvent is a POJO, received from a third-party. – Gladiator9120 Dec 21 '22 at 04:36
  • 1
    Yes, and you should share this class (with all the classes it uses). That actually should be obvious, after all the string used in the verification comes from here. – Topaco Dec 21 '22 at 07:01
  • @Topaco It's a huge object class with multiple objects included. The RequestBody is included as String of that Class itself. – Gladiator9120 Dec 21 '22 at 07:09
  • @Topaco but I think, unknowingly you may have pointed me in the right direction. There are certain statuses where I am using ENUM class, while the docs of the provider uses it as String. Does that matter ? – Gladiator9120 Dec 21 '22 at 07:09
  • 1
    The verification fails because your mapping object-> string uses the *scientific notation*. The fix depends on the data type of the relevant parameters in the POJO, which is not known until you post the classes. – Topaco Dec 21 '22 at 07:14
  • @Topaco updated my question with object. – Gladiator9120 Dec 21 '22 at 07:18
  • 1
    If the content of `RequestBody` is used as string for `message` and the 4 fields written with scientific notation are written plain, verification is successful. If the posted POJOs and the unchanged value of `RequestBody` are used to generate `message`, there are differences in the number and order of the data elements and in part of the decimal numbers (number of decimal places). All this is the cause of the failed verification. – Topaco Dec 21 '22 at 10:53
  • @Topaco Is it possible for you to give a solution as answer, which I can change in my code to make it working ? – Gladiator9120 Dec 21 '22 at 11:36
  • @Topaco, I also tried to make my webhook POST method to take Map as provider's requestBody. Then directly convert it to String, without mapping to POJO, and then message.getBytes() of the String to verify the signature, it still fails. All I am doing is just converting whatever I receive as notification from third-party, convert to string > convert to byte[] and pass to Signature instance to verify. – Gladiator9120 Dec 21 '22 at 12:45
  • Please have a look at my answer. – Topaco Dec 21 '22 at 17:23

1 Answers1

1

As mentioned in the comments, verification of the posted signature with the posted key is successful if the following message is used:

String message = "{\"type\":\"TRANSACTION_STATUS_UPDATED\",\"tenantId\":\"f4df1e73-ec68-53c5-aa92-1a2bc45900ef\",\"timestamp\":1671288284087,\"data\":{\"id\":\"b96f37dd-0fe9-4aa0-853b-f7d39c2ddc52\",\"createdAt\":1671286112004,\"lastUpdated\":1671286112019,\"assetId\":\"BTC_TEST\",\"source\":{\"id\":\"\",\"type\":\"UNKNOWN\",\"name\":\"External\",\"subType\":\"\"},\"destination\":{\"id\":\"26\",\"type\":\"VAULT_ACCOUNT\",\"name\":\"55b49ae0-0f34-4b3c-8cf6-0094254261c2\",\"subType\":\"\"},\"amount\":0.00001,\"networkFee\":0.00000141,\"netAmount\":0.00001,\"sourceAddress\":\"tb1qluc5wgms8kpu0tydu00590qryfan3969jvmc8e\",\"destinationAddress\":\"tb1qyhfnsfe2dy8az3040yvx087qdfsw6yxk8pc7yj\",\"destinationAddressDescription\":\"\",\"destinationTag\":\"\",\"status\":\"CONFIRMING\",\"txHash\":\"15873dc631db22a1bd13c6adecf7fb63f8fbbecce36eb38d12df65573e83dfa9\",\"subStatus\":\"PENDING_BLOCKCHAIN_CONFIRMATIONS\",\"signedBy\":[],\"createdBy\":\"\",\"rejectedBy\":\"\",\"amountUSD\":0.17,\"addressType\":\"\",\"note\":\"\",\"exchangeTxId\":\"\",\"requestedAmount\":0.00001,\"feeCurrency\":\"BTC_TEST\",\"operation\":\"TRANSFER\",\"customerRefId\":null,\"numOfConfirmations\":2,\"amountInfo\":{\"amount\":\"0.00001\",\"requestedAmount\":\"0.00001\",\"netAmount\":\"0.00001\",\"amountUSD\":\"0.17\"},\"feeInfo\":{\"networkFee\":\"0.00000141\"},\"destinations\":[],\"externalTxId\":null,\"blockInfo\":{\"blockHeight\":\"2411637\",\"blockHash\":\"00000000d45b7ebf40921cbc70fb6791985a0b256241757a28bf762be07478e8\"},\"signedMessages\":[],\"index\":1}}";

In order for verification to succeed, the exact same message must be used as for signing (i.e. the same formatting and order).
However, on my machine, when filling the WebhookEvent object with RequestBody, the posted code generates a different message when using the posted POJOs:

String message = "{\"type\":\"TRANSACTION_STATUS_UPDATED\",\"tenantId\":\"f4df1e73-ec68-53c5-aa92-1a2bc45900ef\",\"timestamp\":1671288284087,\"data\":{\"id\":\"b96f37dd-0fe9-4aa0-853b-f7d39c2ddc52\",\"assetId\":\"BTC_TEST\",\"source\":{\"id\":\"\",\"type\":\"UNKNOWN\",\"name\":\"External\",\"subType\":\"\"},\"destination\":{\"id\":\"26\",\"type\":\"VAULT_ACCOUNT\",\"name\":\"55b49ae0-0f34-4b3c-8cf6-0094254261c2\",\"subType\":\"\"},\"requestedAmount\":0.000010,\"amountInfo\":{\"amount\":\"0.00001\",\"requestedAmount\":\"0.00001\",\"netAmount\":\"0.00001\",\"amountUSD\":\"0.17\"},\"feeinfo\":null,\"amount\":0.000010,\"netAmount\":0.000010,\"amountUSD\":0.17,\"serviceFee\":null,\"treatAsGrossAmount\":null,\"networkFee\":0.00000141,\"createdAt\":1671286112004,\"lastUpdated\":1671286112019,\"status\":\"CONFIRMING\",\"txHash\":\"15873dc631db22a1bd13c6adecf7fb63f8fbbecce36eb38d12df65573e83dfa9\",\"index\":1,\"subStatus\":\"PENDING_BLOCKCHAIN_CONFIRMATIONS\",\"sourceAddress\":\"tb1qluc5wgms8kpu0tydu00590qryfan3969jvmc8e\",\"destinationAddress\":\"tb1qyhfnsfe2dy8az3040yvx087qdfsw6yxk8pc7yj\",\"destinationAddressDescription\":\"\",\"destinationTag\":\"\",\"signedBy\":[],\"createdBy\":\"\",\"rejectedBy\":\"\",\"addressType\":\"\",\"note\":\"\",\"exchangeTxId\":\"\",\"feeCurrency\":\"BTC_TEST\",\"operation\":\"TRANSFER\",\"amlScreeningResult\":null,\"customerRefId\":null,\"numOfConfirmations\":2,\"networkRecords\":null,\"replacedTxHash\":null,\"externalTxId\":null,\"destinations\":[],\"blockInfo\":{\"blockHeight\":\"2411637\",\"blockHash\":\"00000000d45b7ebf40921cbc70fb6791985a0b256241757a28bf762be07478e8\"},\"rewardsInfo\":null,\"authorizationInfo\":null,\"signedMessages\":[],\"extraParameters\":null}}";

RequestBody differs from the correct message only in that scientific notation is used instead of the plain format for BigDecimal.
If RequestBody reliably matches the correct message apart from the BigDecimal format, a correction of the BigDecimal format might be enough for successful verification, e.g. with:

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.math.BigDecimal;
...
private static String fixDecimalNumberFormat(String json) throws Exception {
    ObjectMapper objectMapper = new ObjectMapper();
    JsonNode jsonNode = objectMapper.readTree(json);
    ObjectNode objectNode = (ObjectNode)jsonNode.get("data");
    objectNode.put("createdAt", new BigDecimal(objectNode.get("createdAt").toString()));
    objectNode.put("amount", new BigDecimal(objectNode.get("amount").toString()));
    objectNode.put("networkFee", new BigDecimal(objectNode.get("networkFee").toString()));
    objectNode.put("netAmount", new BigDecimal(objectNode.get("netAmount").toString()));
    objectNode.put("amountUSD", new BigDecimal(objectNode.get("amountUSD").toString()));
    objectNode.put("requestedAmount", new BigDecimal(objectNode.get("requestedAmount").toString()));
    return jsonNode.toString();
}

Otherwise, the rules for formatting and order must be agreed with the signing side.


Test:

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
...
public static void main(String[] args) throws Exception {
    
    // Import key and signature 
    byte[] derKey = Base64.getDecoder().decode("MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0+6wd9OJQpK60ZI7qnZGjjQ0wNFUHfRv85Tdyek8+ahlg1Ph8uhwl4N6DZw5LwLXhNjzAbQ8LGPxt36RUZl5YlxTru0jZNKx5lslR+H4i936A4pKBjgiMmSkVwXD9HcfKHTp70GQ812+J0Fvti/v4nrrUpc011Wo4F6omt1QcYsi4GTI5OsEbeKQ24BtUd6Z1Nm/EP7PfPxeb4CP8KOHclM8K7OwBUfWrip8Ptljjz9BNOZUF94iyjJ/BIzGJjyCntho64ehpUYP8UJykLVdCGcu7sVYWnknf1ZGLuqqZQt4qt7cUUhFGielssZP9N9x7wzaAIFcT3yQ+ELDu1SZdE4lZsf2uMyfj58V8GDOLLE233+LRsRbJ083x+e2mW5BdAGtGgQBusFfnmv5BxqdHgS55hsna5725/44tvxll261TgQvjGrTxwe7e5Ia3d2Syc+e89mXQaI/+cZnylNPSwCCvx8mOM847T0XkVRX3ZrwXtHIA25uKsPJzUtksDnAowB91j7RJkjXxJcz3Vh14k182UFOTPRW9jzdWNSyWQGl/vpe9oQ4c2Ly15+/toBo4YXJeDdDnZ5c/O+KKadcIMPBpnPrH/0O97uMPuED+nI6ISGOTMLZo35xJ96gPBwyG5s2QxIkKPXIrhgcgUnktSM7QYNhlftT4/yVvYnk0YcCAwEAAQ==");
    KeyFactory kf = KeyFactory.getInstance("RSA");
    X509EncodedKeySpec spec = new X509EncodedKeySpec(derKey);
    PublicKey publicKey = kf.generatePublic(spec);
    String header = "YNYVgWsx3PdoEGq2nUFGLmE6tE2y0LCc/eWPSY+rAqK+8fcxrPN0SPGbTdAXQ9+v62T5akWaVRWKXc1YBWlZxhVTCa/Ou7FfjVPG6JIQNX3Lks3ZhW0k29bVKf7Qvjp7z8HM9s1D8ZC28HvpX15a4by7DpNKkQ6cLWMDtBvqY02FSO+L4Vq54GZoTrplYkqCYcI4/oWchYzMZMq4omIOuam2DXm5BLlZ7HCR/nhUyp5duJpYnWJCKEwOTh3zLm842r5Fa9humq9WKkkT+AgFxe95bG4F3p8XhsciXiaNgx8diKLF0aBklqJ6yA70vjIP92BHuEnvIl37RiSFiIvkYWvLpMc1LoPxWZvncaLUjlYSVT3zd/gCDPEn1Mu8wUogGt9npkc/eKMdrKefcjEIMrJoO0HMMREZcOpc72F0+RM4QCkMaQMmK4zq9cBF0E2bNaEabNDSWXIfx9fa2VuyGYa5GLmAPUQPYRv50n92IGFewxj9vFAWhca+uthvsqz3FekyHK+c9G1Wh9OScR2TQp9Lbe4LqlX4FGapQitmfDvKRJhjAVm0n5355+k1dRse4fGeXqd2EfledWUJ3egpmW1NlmWBr8d4PsruKYZnphEMn9F5F3Vyu2sCpBSvqmcMANXzyZP7u3lGsUpH4V2lM6nCeBiRcbfwyrFsJ6Q5dso=";

    // Fix BigDecimal format, message from RequestBody
    String message = "{\"type\":\"TRANSACTION_STATUS_UPDATED\",\"tenantId\":\"f4df1e73-ec68-53c5-aa92-1a2bc45900ef\",\"timestamp\":1671288284087,\"data\":{\"id\":\"b96f37dd-0fe9-4aa0-853b-f7d39c2ddc52\",\"createdAt\":1671286112004,\"lastUpdated\":1671286112019,\"assetId\":\"BTC_TEST\",\"source\":{\"id\":\"\",\"type\":\"UNKNOWN\",\"name\":\"External\",\"subType\":\"\"},\"destination\":{\"id\":\"26\",\"type\":\"VAULT_ACCOUNT\",\"name\":\"55b49ae0-0f34-4b3c-8cf6-0094254261c2\",\"subType\":\"\"},\"amount\":1.0E-5,\"networkFee\":1.41E-6,\"netAmount\":1.0E-5,\"sourceAddress\":\"tb1qluc5wgms8kpu0tydu00590qryfan3969jvmc8e\",\"destinationAddress\":\"tb1qyhfnsfe2dy8az3040yvx087qdfsw6yxk8pc7yj\",\"destinationAddressDescription\":\"\",\"destinationTag\":\"\",\"status\":\"CONFIRMING\",\"txHash\":\"15873dc631db22a1bd13c6adecf7fb63f8fbbecce36eb38d12df65573e83dfa9\",\"subStatus\":\"PENDING_BLOCKCHAIN_CONFIRMATIONS\",\"signedBy\":[],\"createdBy\":\"\",\"rejectedBy\":\"\",\"amountUSD\":0.17,\"addressType\":\"\",\"note\":\"\",\"exchangeTxId\":\"\",\"requestedAmount\":1.0E-5,\"feeCurrency\":\"BTC_TEST\",\"operation\":\"TRANSFER\",\"customerRefId\":null,\"numOfConfirmations\":2,\"amountInfo\":{\"amount\":\"0.00001\",\"requestedAmount\":\"0.00001\",\"netAmount\":\"0.00001\",\"amountUSD\":\"0.17\"},\"feeInfo\":{\"networkFee\":\"0.00000141\"},\"destinations\":[],\"externalTxId\":null,\"blockInfo\":{\"blockHeight\":\"2411637\",\"blockHash\":\"00000000d45b7ebf40921cbc70fb6791985a0b256241757a28bf762be07478e8\"},\"signedMessages\":[],\"index\":1}}";
    message = fixDecimalNumberFormat(message);
    
    // Verify signature
    Signature verifier = Signature.getInstance("SHA512withRSA");
    verifier.initVerify(publicKey);
    verifier.update(message.getBytes());
    boolean isVerified = verifier.verify(Base64.getDecoder().decode(header));

    System.out.println(message);
    System.out.println(isVerified);
}

performs a successful verification of the fixed data from RequestBody:

{"type":"TRANSACTION_STATUS_UPDATED","tenantId":"f4df1e73-ec68-53c5-aa92-1a2bc45900ef","timestamp":1671288284087,"data":{"id":"b96f37dd-0fe9-4aa0-853b-f7d39c2ddc52","createdAt":1671286112004,"lastUpdated":1671286112019,"assetId":"BTC_TEST","source":{"id":"","type":"UNKNOWN","name":"External","subType":""},"destination":{"id":"26","type":"VAULT_ACCOUNT","name":"55b49ae0-0f34-4b3c-8cf6-0094254261c2","subType":""},"amount":0.00001,"networkFee":0.00000141,"netAmount":0.00001,"sourceAddress":"tb1qluc5wgms8kpu0tydu00590qryfan3969jvmc8e","destinationAddress":"tb1qyhfnsfe2dy8az3040yvx087qdfsw6yxk8pc7yj","destinationAddressDescription":"","destinationTag":"","status":"CONFIRMING","txHash":"15873dc631db22a1bd13c6adecf7fb63f8fbbecce36eb38d12df65573e83dfa9","subStatus":"PENDING_BLOCKCHAIN_CONFIRMATIONS","signedBy":[],"createdBy":"","rejectedBy":"","amountUSD":0.17,"addressType":"","note":"","exchangeTxId":"","requestedAmount":0.00001,"feeCurrency":"BTC_TEST","operation":"TRANSFER","customerRefId":null,"numOfConfirmations":2,"amountInfo":{"amount":"0.00001","requestedAmount":"0.00001","netAmount":"0.00001","amountUSD":"0.17"},"feeInfo":{"networkFee":"0.00000141"},"destinations":[],"externalTxId":null,"blockInfo":{"blockHeight":"2411637","blockHash":"00000000d45b7ebf40921cbc70fb6791985a0b256241757a28bf762be07478e8"},"signedMessages":[],"index":1}}
true
Topaco
  • 40,594
  • 4
  • 35
  • 62