Skip to content

Commit

Permalink
[Cardano] Support utxo with legacy(byron) address (#3284)
Browse files Browse the repository at this point in the history
  • Loading branch information
Balashov152 authored Jul 7, 2023
1 parent 5b6581b commit 5dee361
Show file tree
Hide file tree
Showing 6 changed files with 196 additions and 31 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import org.junit.Assert.assertEquals
import org.junit.Test
import wallet.core.java.AnySigner
import wallet.core.jni.*
import wallet.core.jni.Cardano.getByronAddress
import wallet.core.jni.Cardano.getStakingAddress
import wallet.core.jni.Cardano.outputMinAdaAmount
import wallet.core.jni.CoinType.CARDANO
Expand Down Expand Up @@ -75,6 +76,60 @@ class TestCardanoSigning {
assertEquals(Numeric.toHexString(txid.toByteArray()), "0x9b5b15e133cd73ccaa85307d2986aebc846505118a2eb4e6111e6b4b67d1f389");
}

/// Successfully broadcasted:
/// https://cardanoscan.io/transaction/0203ce2c91f59f169a26e9ef91254639d2b7911afac9c7c0ae64539f88ba46a5
@Test
fun testSignTransferFromLegacy() {
val privateKey = PrivateKey("98f266d1aac660179bc2f456033941238ee6b2beb8ed0f9f34c9902816781f5a9903d1d395d6ab887b65ea5e344ef09b449507c21a75f0ce8c59d0ed1c6764eba7f484aa383806735c46fd769c679ee41f8952952036a6e2338ada940b8a91f4e890ca4eb6bec44bf751b5a843174534af64d6ad1f44e0613db78a7018781f5aa151d2997f52059466b715d8eefab30a78b874ae6ef4931fa58bb21ef8ce2423d46f19d0fbf75afb0b9a24e31d533f4fd74cee3b56e162568e8defe37123afc4".toHexByteArray())
var publicKey = privateKey.publicKeyEd25519Cardano
var byronAddress = wallet.core.jni.Cardano.getByronAddress(publicKey)

assertEquals(byronAddress, "Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8")

val message = Cardano.Transfer.newBuilder()
.setToAddress("addr1q90uh2eawrdc9vaemftgd50l28yrh9lqxtjjh4z6dnn0u7ggasexxdyyk9f05atygnjlccsjsggtc87hhqjna32fpv5qeq96ls")
.setChangeAddress("addr1qx55ymlqemndq8gluv40v58pu76a2tp4mzjnyx8n6zrp2vtzrs43a0057y0edkn8lh9su8vh5lnhs4npv6l9tuvncv8swc7t08")
.setAmount(3_000_000)
.build()
val input = Cardano.SigningInput.newBuilder()
.setTransferMessage(message)
.setTtl(190000000)

input.addPrivateKey(ByteString.copyFrom(privateKey.data()))

val outpoint1 = Cardano.OutPoint.newBuilder()
.setTxHash(ByteString.copyFrom(Numeric.hexStringToByteArray("8316e5007d61fb90652cabb41141972a38b5bc60954d602cf843476aa3f67f63")))
.setOutputIndex(0)
.build()
val utxo1 = Cardano.TxInput.newBuilder()
.setOutPoint(outpoint1)
.setAddress("Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8")
.setAmount(2_500_000)
.build()
input.addUtxos(utxo1)

val outpoint2 = Cardano.OutPoint.newBuilder()
.setTxHash(ByteString.copyFrom(Numeric.hexStringToByteArray("e29392c59c903fefb905730587d22cae8bda30bd8d9aeec3eca082ae77675946")))
.setOutputIndex(0)
.build()
val utxo2 = Cardano.TxInput.newBuilder()
.setOutPoint(outpoint2)
.setAddress("Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8")
.setAmount(1_700_000)
.build()
input.addUtxos(utxo2)

val output = AnySigner.sign(input.build(), CARDANO, Cardano.SigningOutput.parser())
assertEquals(output.error, SigningError.OK)

val encoded = output.encoded
assertEquals(Numeric.toHexString(encoded.toByteArray()),
"0x83a400828258208316e5007d61fb90652cabb41141972a38b5bc60954d602cf843476aa3f67f6300825820e29392c59c903fefb905730587d22cae8bda30bd8d9aeec3eca082ae77675946000182825839015fcbab3d70db82b3b9da5686d1ff51c83b97e032e52bd45a6ce6fe7908ec32633484b152fa756444e5fc62128210bc1fd7b8253ec5490b281a002dc6c082583901a9426fe0cee6d01d1fe32af650e1e7b5d52c35d8a53218f3d0861531621c2b1ebdf4f11f96da67fdcb0e1d97a7e778566166be55f193c30f1a000f9ec1021a0002b0bf031a0b532b80a20081825820d163c8c4f0be7c22cd3a1152abb013c855ea614b92201497a568c5d93ceeb41e58406a23ab9267867fbf021c1cb2232bc83d2cdd663d651d22d59b6cddbca5cb106d4db99da50672f69a2309ca8a329a3f9576438afe4538b013de4591a6dfcd4d090281845820d163c8c4f0be7c22cd3a1152abb013c855ea614b92201497a568c5d93ceeb41e58406a23ab9267867fbf021c1cb2232bc83d2cdd663d651d22d59b6cddbca5cb106d4db99da50672f69a2309ca8a329a3f9576438afe4538b013de4591a6dfcd4d095820a7f484aa383806735c46fd769c679ee41f8952952036a6e2338ada940b8a91f441a0f6");

val txid = output.txId
assertEquals(Numeric.toHexString(txid.toByteArray()), "0x0203ce2c91f59f169a26e9ef91254639d2b7911afac9c7c0ae64539f88ba46a5");
}

@Test
fun testSignTransferToken1() {
val toToken = Cardano.TokenAmount.newBuilder()
Expand Down
6 changes: 6 additions & 0 deletions include/TrustWalletCore/TWCardano.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,10 @@ TWString *_Nullable TWCardanoOutputMinAdaAmount(TWString *_Nonnull toAddress, TW
TW_EXPORT_STATIC_METHOD
TWString *_Nonnull TWCardanoGetStakingAddress(TWString *_Nonnull baseAddress) TW_VISIBILITY_DEFAULT;

/// Return the legacy(byron) address.
/// \param publicKey A valid public key with TWPublicKeyTypeED25519Cardano type.
/// \return the legacy(byron) address, as string, or empty string on error.
TW_EXPORT_STATIC_METHOD
TWString *_Nonnull TWCardanoGetByronAddress(struct TWPublicKey *_Nonnull publicKey);

TW_EXTERN_C_END
75 changes: 59 additions & 16 deletions src/Cardano/Signer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ Common::Proto::SigningError Signer::assembleSignatures(std::vector<std::pair<Dat
const auto address = AddressV3(publicKey);
privateKeys[address.string()] = privateKeyData;

const auto legacyAddress = AddressV2(publicKey);
privateKeys[legacyAddress.string()] = privateKeyData;

// Also add the derived staking private key (the 2nd half) and associated address; because staking keys also need signature
const auto stakingPrivKeyData = deriveStakingPrivateKey(privateKeyData);
if (!stakingPrivKeyData.empty()) {
Expand All @@ -131,7 +134,7 @@ Common::Proto::SigningError Signer::assembleSignatures(std::vector<std::pair<Dat
// collect every unique input UTXO address, preserving order
std::vector<std::string> addresses;
for (auto& u : plan.utxos) {
if (!AddressV3::isValid(u.address)) {
if (!AddressV3::isValidLegacy(u.address)) {
return Common::Proto::Error_invalid_address;
}
addresses.emplace_back(u.address);
Expand Down Expand Up @@ -174,31 +177,53 @@ Common::Proto::SigningError Signer::assembleSignatures(std::vector<std::pair<Dat
const auto privateKey = PrivateKey(privateKeyData);
const auto publicKey = privateKey.getPublicKey(TWPublicKeyTypeED25519Cardano);
const auto signature = privateKey.sign(txId, TWCurveED25519ExtendedCardano);
// public key (first 32 bytes) and signature (64 bytes)
signatures.emplace_back(subData(publicKey.bytes, 0, 32), signature);
signatures.emplace_back(publicKey.bytes, signature);
}

return Common::Proto::OK;
}

Cbor::Encode cborizeSignatures(const std::vector<std::pair<Data, Data>>& signatures) {
Cbor::Encode cborizeSignatures(const std::vector<std::pair<Data, Data>>& signatures, const bool addByronSignatures) {
std::map<Cbor::Encode, Cbor::Encode> cborizeSigs;
// signatures as Cbor
// clang-format off
std::vector<Cbor::Encode> sigsCbor;
std::vector<Cbor::Encode> sigsShelly;
std::vector<Cbor::Encode> sigsByron;

for (auto& s : signatures) {
sigsCbor.emplace_back(Cbor::Encode::array({
Cbor::Encode::bytes(s.first),
sigsShelly.emplace_back(Cbor::Encode::array({
// public key (first 32 bytes)
Cbor::Encode::bytes(subData(s.first, 0, 32)),
Cbor::Encode::bytes(s.second)
}));

if (addByronSignatures) {
sigsByron.emplace_back(Cbor::Encode::array({
// skey - public key (first 32 bytes)
Cbor::Encode::bytes(subData(s.first, 0, 32)),
Cbor::Encode::bytes(s.second),
// vkey - public key (second 32 bytes started from 32)
Cbor::Encode::bytes(subData(s.first, 32, 32)),
// payload
Cbor::Encode::bytes(parse_hex("A0"))
}));
}
}

cborizeSigs.emplace(
Cbor::Encode::uint(0),
Cbor::Encode::array(sigsShelly)
);

if (!sigsByron.empty()) {
cborizeSigs.emplace(
Cbor::Encode::uint(2),
Cbor::Encode::array(sigsByron)
);
}

// Cbor-encode txAux & signatures
return Cbor::Encode::map({
std::make_pair(
Cbor::Encode::uint(0),
Cbor::Encode::array(sigsCbor)
)
});
return Cbor::Encode::map(cborizeSigs);
// clang-format on
}

Expand Down Expand Up @@ -242,7 +267,16 @@ Common::Proto::SigningError Signer::encodeTransaction(Data& encoded, Data& txId,
if (sigError != Common::Proto::OK) {
return sigError;
}
const auto sigsCbor = cborizeSignatures(signatures);

bool hasLegacyUtxos = false;
for (const auto& utxo : input.utxos()) {
if (AddressV2::isValid(utxo.address())) {
hasLegacyUtxos = true;
break;
}
}

const auto sigsCbor = cborizeSignatures(signatures, hasLegacyUtxos);

// Cbor-encode txAux & signatures
const auto cbor = Cbor::Encode::array({
Expand Down Expand Up @@ -557,8 +591,17 @@ Data Signer::encodeTransactionWithSig(const Proto::SigningInput &input, const Pu
}

std::vector<std::pair<Data, Data>> signatures;
signatures.emplace_back(subData(publicKey.bytes, 0, 32), signature);
const auto sigsCbor = cborizeSignatures(signatures);
signatures.emplace_back(publicKey.bytes, signature);

bool hasLegacyUtxos = false;
for (const auto& utxo : input.utxos()) {
if (AddressV2::isValid(utxo.address())) {
hasLegacyUtxos = true;
break;
}
}

const auto sigsCbor = cborizeSignatures(signatures, hasLegacyUtxos);

// Cbor-encode txAux & signatures
const auto cbor = Cbor::Encode::array({
Expand Down
8 changes: 8 additions & 0 deletions src/interface/TWCardano.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,11 @@ TWString *_Nonnull TWCardanoGetStakingAddress(TWString *_Nonnull baseAddress) {
return TWStringCreateWithUTF8Bytes("");
}
}

TWString *_Nonnull TWCardanoGetByronAddress(struct TWPublicKey *_Nonnull publicKey) {
try {
return TWStringCreateWithUTF8Bytes(TW::Cardano::AddressV2({ publicKey->impl }).string().c_str());
} catch (...) {
return TWStringCreateWithUTF8Bytes("");
}
}
50 changes: 50 additions & 0 deletions swift/Tests/Blockchains/CardanoTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,56 @@ class CardanoTests: XCTestCase {
let txid = output.txID
XCTAssertEqual(txid.hexString, "9b5b15e133cd73ccaa85307d2986aebc846505118a2eb4e6111e6b4b67d1f389")
}

/// Successfully broadcasted:
/// https://cardanoscan.io/transaction/0203ce2c91f59f169a26e9ef91254639d2b7911afac9c7c0ae64539f88ba46a5
func testSignTransferFromLegacy() throws {
let privateKey = PrivateKey(data: Data(hexString: "98f266d1aac660179bc2f456033941238ee6b2beb8ed0f9f34c9902816781f5a9903d1d395d6ab887b65ea5e344ef09b449507c21a75f0ce8c59d0ed1c6764eba7f484aa383806735c46fd769c679ee41f8952952036a6e2338ada940b8a91f4e890ca4eb6bec44bf751b5a843174534af64d6ad1f44e0613db78a7018781f5aa151d2997f52059466b715d8eefab30a78b874ae6ef4931fa58bb21ef8ce2423d46f19d0fbf75afb0b9a24e31d533f4fd74cee3b56e162568e8defe37123afc4")!)!
let publicKey = privateKey.getPublicKeyEd25519Cardano()
let byronAddress = Cardano.getByronAddress(publicKey: publicKey)

XCTAssertEqual(
publicKey.data.hexString,
"d163c8c4f0be7c22cd3a1152abb013c855ea614b92201497a568c5d93ceeb41ea7f484aa383806735c46fd769c679ee41f8952952036a6e2338ada940b8a91f40b5aaa6103dc10842894a1eeefc5447b9bcb9bcf227d77e57be195d17bc03263d46f19d0fbf75afb0b9a24e31d533f4fd74cee3b56e162568e8defe37123afc4"
)

XCTAssertEqual(
byronAddress,
"Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8"
)
var input = CardanoSigningInput.with {
$0.transferMessage.toAddress = "addr1q90uh2eawrdc9vaemftgd50l28yrh9lqxtjjh4z6dnn0u7ggasexxdyyk9f05atygnjlccsjsggtc87hhqjna32fpv5qeq96ls"
$0.transferMessage.changeAddress = "addr1qx55ymlqemndq8gluv40v58pu76a2tp4mzjnyx8n6zrp2vtzrs43a0057y0edkn8lh9su8vh5lnhs4npv6l9tuvncv8swc7t08"
$0.transferMessage.amount = 3000000
$0.ttl = 190000000
}

input.privateKey.append(privateKey.data)

let utxo1 = CardanoTxInput.with {
$0.outPoint.txHash = Data(hexString: "8316e5007d61fb90652cabb41141972a38b5bc60954d602cf843476aa3f67f63")!
$0.outPoint.outputIndex = 0
$0.address = "Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8"
$0.amount = 2500000
}
input.utxos.append(utxo1)

let utxo2 = CardanoTxInput.with {
$0.outPoint.txHash = Data(hexString: "e29392c59c903fefb905730587d22cae8bda30bd8d9aeec3eca082ae77675946")!
$0.outPoint.outputIndex = 0
$0.address = "Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8"
$0.amount = 1700000
}
input.utxos.append(utxo2)

// Sign
let output: CardanoSigningOutput = AnySigner.sign(input: input, coin: .cardano)
XCTAssertEqual(output.error, TW_Common_Proto_SigningError.ok)

XCTAssertEqual(output.encoded.hexString, "83a400828258208316e5007d61fb90652cabb41141972a38b5bc60954d602cf843476aa3f67f6300825820e29392c59c903fefb905730587d22cae8bda30bd8d9aeec3eca082ae77675946000182825839015fcbab3d70db82b3b9da5686d1ff51c83b97e032e52bd45a6ce6fe7908ec32633484b152fa756444e5fc62128210bc1fd7b8253ec5490b281a002dc6c082583901a9426fe0cee6d01d1fe32af650e1e7b5d52c35d8a53218f3d0861531621c2b1ebdf4f11f96da67fdcb0e1d97a7e778566166be55f193c30f1a000f9ec1021a0002b0bf031a0b532b80a20081825820d163c8c4f0be7c22cd3a1152abb013c855ea614b92201497a568c5d93ceeb41e58406a23ab9267867fbf021c1cb2232bc83d2cdd663d651d22d59b6cddbca5cb106d4db99da50672f69a2309ca8a329a3f9576438afe4538b013de4591a6dfcd4d090281845820d163c8c4f0be7c22cd3a1152abb013c855ea614b92201497a568c5d93ceeb41e58406a23ab9267867fbf021c1cb2232bc83d2cdd663d651d22d59b6cddbca5cb106d4db99da50672f69a2309ca8a329a3f9576438afe4538b013de4591a6dfcd4d095820a7f484aa383806735c46fd769c679ee41f8952952036a6e2338ada940b8a91f441a0f6")

XCTAssertEqual(output.txID.hexString, "0203ce2c91f59f169a26e9ef91254639d2b7911afac9c7c0ae64539f88ba46a5")
}

func testSignTransferToken1() throws {
let toToken = CardanoTokenAmount.with {
Expand Down
33 changes: 18 additions & 15 deletions tests/chains/Cardano/SigningTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,40 +598,43 @@ TEST(CardanoSigning, SignTransfer_0db1ea) {
EXPECT_EQ(hex(txid), "0db1ea8c5c5828bbd027fcef3da02a63b86899db670ad7bb0630cefbe35944fa");
}

/// Successfully broadcasted:
/// https://cardanoscan.io/transaction/0203ce2c91f59f169a26e9ef91254639d2b7911afac9c7c0ae64539f88ba46a5
TEST(CardanoSigning, SignTransferFromLegacy) {
Proto::SigningInput input;
auto* utxo1 = input.add_utxos();
const auto txHash1 = parse_hex("f074134aabbfb13b8aec7cf5465b1e5a862bde5cb88532cc7e64619179b3e767");
const auto txHash1 = parse_hex("8316e5007d61fb90652cabb41141972a38b5bc60954d602cf843476aa3f67f63");
utxo1->mutable_out_point()->set_tx_hash(txHash1.data(), txHash1.size());
utxo1->mutable_out_point()->set_output_index(1);
utxo1->set_address("Ae2tdPwUPEZMRgecV9jV2e9RdbrmnWu7YgRie4de16xLdkWhy6q7ypmRhgn");
utxo1->set_amount(1500000);
utxo1->mutable_out_point()->set_output_index(0);
utxo1->set_address("Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8");
utxo1->set_amount(2500000);
auto* utxo2 = input.add_utxos();
const auto txHash2 = parse_hex("554f2fd942a23d06835d26bbd78f0106fa94c8a551114a0bef81927f66467af0");
const auto txHash2 = parse_hex("e29392c59c903fefb905730587d22cae8bda30bd8d9aeec3eca082ae77675946");
utxo2->mutable_out_point()->set_tx_hash(txHash2.data(), txHash2.size());
utxo2->mutable_out_point()->set_output_index(0);
utxo2->set_address("Ae2tdPwUPEZMRgecV9jV2e9RdbrmnWu7YgRie4de16xLdkWhy6q7ypmRhgn");
utxo2->set_amount(6500000);
utxo2->set_address("Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8");
utxo2->set_amount(1700000);

const auto privateKeyData = parse_hex("c031e942f6bf2b2864700e7da20964ee6bb6d716345ce2e24d8c00e6500b574411111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111");
const auto privateKeyData = parse_hex("98f266d1aac660179bc2f456033941238ee6b2beb8ed0f9f34c9902816781f5a9903d1d395d6ab887b65ea5e344ef09b449507c21a75f0ce8c59d0ed1c6764eba7f484aa383806735c46fd769c679ee41f8952952036a6e2338ada940b8a91f4e890ca4eb6bec44bf751b5a843174534af64d6ad1f44e0613db78a7018781f5aa151d2997f52059466b715d8eefab30a78b874ae6ef4931fa58bb21ef8ce2423d46f19d0fbf75afb0b9a24e31d533f4fd74cee3b56e162568e8defe37123afc4");
{
const auto privKey = PrivateKey(privateKeyData);
const auto pubKey = privKey.getPublicKey(TWPublicKeyTypeED25519Cardano);
const auto addr = AddressV2(pubKey);
EXPECT_EQ(addr.string(), "Ae2tdPwUPEZMRgecV9jV2e9RdbrmnWu7YgRie4de16xLdkWhy6q7ypmRhgn");
EXPECT_EQ(addr.string(), "Ae2tdPwUPEZ6vkqxSjJxaQYmDxHf5DTnxtZ67pFLJGTb9LTnCGkDP6ca3f8");
}
input.add_private_key(privateKeyData.data(), privateKeyData.size());
input.mutable_transfer_message()->set_to_address("addr1q92cmkgzv9h4e5q7mnrzsuxtgayvg4qr7y3gyx97ukmz3dfx7r9fu73vqn25377ke6r0xk97zw07dqr9y5myxlgadl2s0dgke5");
input.mutable_transfer_message()->set_change_address(ownAddress1);
input.mutable_transfer_message()->set_amount(7000000);
input.mutable_transfer_message()->set_to_address("addr1q90uh2eawrdc9vaemftgd50l28yrh9lqxtjjh4z6dnn0u7ggasexxdyyk9f05atygnjlccsjsggtc87hhqjna32fpv5qeq96ls");
input.mutable_transfer_message()->set_change_address("addr1qx55ymlqemndq8gluv40v58pu76a2tp4mzjnyx8n6zrp2vtzrs43a0057y0edkn8lh9su8vh5lnhs4npv6l9tuvncv8swc7t08");
input.mutable_transfer_message()->set_amount(3000000);
input.mutable_transfer_message()->set_use_max_amount(false);
input.set_ttl(53333333);
input.set_ttl(190000000);

auto signer = Signer(input);
const auto output = signer.sign();

EXPECT_EQ(output.error(), Common::Proto::Error_invalid_address);
EXPECT_EQ(hex(output.encoded()), "");
EXPECT_EQ(output.error(), Common::Proto::OK);
EXPECT_EQ(hex(output.encoded()), "83a400828258208316e5007d61fb90652cabb41141972a38b5bc60954d602cf843476aa3f67f6300825820e29392c59c903fefb905730587d22cae8bda30bd8d9aeec3eca082ae77675946000182825839015fcbab3d70db82b3b9da5686d1ff51c83b97e032e52bd45a6ce6fe7908ec32633484b152fa756444e5fc62128210bc1fd7b8253ec5490b281a002dc6c082583901a9426fe0cee6d01d1fe32af650e1e7b5d52c35d8a53218f3d0861531621c2b1ebdf4f11f96da67fdcb0e1d97a7e778566166be55f193c30f1a000f9ec1021a0002b0bf031a0b532b80a20081825820d163c8c4f0be7c22cd3a1152abb013c855ea614b92201497a568c5d93ceeb41e58406a23ab9267867fbf021c1cb2232bc83d2cdd663d651d22d59b6cddbca5cb106d4db99da50672f69a2309ca8a329a3f9576438afe4538b013de4591a6dfcd4d090281845820d163c8c4f0be7c22cd3a1152abb013c855ea614b92201497a568c5d93ceeb41e58406a23ab9267867fbf021c1cb2232bc83d2cdd663d651d22d59b6cddbca5cb106d4db99da50672f69a2309ca8a329a3f9576438afe4538b013de4591a6dfcd4d095820a7f484aa383806735c46fd769c679ee41f8952952036a6e2338ada940b8a91f441a0f6");
EXPECT_EQ(hex(data(output.tx_id())), "0203ce2c91f59f169a26e9ef91254639d2b7911afac9c7c0ae64539f88ba46a5");
}

TEST(CardanoSigning, SignTransferToLegacy) {
Expand Down

0 comments on commit 5dee361

Please sign in to comment.