From d0e5da9939abac122a4f35198bba80562dcac00d Mon Sep 17 00:00:00 2001 From: Manas Ladha Date: Thu, 9 Jan 2025 16:31:18 +0530 Subject: [PATCH 1/3] feat: byron era support for ADA wallets TICKET: WIN-4056 --- modules/sdk-coin-ada/src/lib/utils.ts | 47 +++++++++++++++++++-------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/modules/sdk-coin-ada/src/lib/utils.ts b/modules/sdk-coin-ada/src/lib/utils.ts index 950fcf85be..28c384d410 100644 --- a/modules/sdk-coin-ada/src/lib/utils.ts +++ b/modules/sdk-coin-ada/src/lib/utils.ts @@ -14,6 +14,8 @@ import { } from '@emurgo/cardano-serialization-lib-nodejs'; import { KeyPair } from './keyPair'; import { bech32 } from 'bech32'; +import base58 from 'bs58'; +import cbor from 'cbor'; export const MIN_ADA_FOR_ONE_ASSET = '1500000'; export const VOTE_ALWAYS_ABSTAIN = 'always-abstain'; @@ -149,26 +151,43 @@ export class Utils implements BaseUtils { const POINTER_ADDR_LEN = 52; const VALIDATOR_ADDR_LEN = 56; - // test if this is a bech32 address first - if (new RegExp(bech32PrefixList.join('|')).test(address)) { + //Check for Shelley-era (Bech32) addresses + if (new RegExp(`^(${bech32PrefixList.join('|')})`).test(address)) { try { const decodedBech = bech32.decode(address, 108); const wordLength = decodedBech.words.length; - if (!bech32PrefixList.includes(decodedBech.prefix)) { - return false; + if ( + bech32PrefixList.includes(decodedBech.prefix) && + (wordLength === BASE_ADDR_LEN || + wordLength === REWARD_AND_ENTERPRISE_ADDR_LEN || + wordLength === POINTER_ADDR_LEN) + ) { + return true; } - return ( - wordLength === BASE_ADDR_LEN || - wordLength === REWARD_AND_ENTERPRISE_ADDR_LEN || - wordLength === POINTER_ADDR_LEN - ); - } catch (err) { - return false; + } catch (e) { + console.log(`Address: ${address} failed Bech32 test with error: ${e}`); } - } else { - // maybe this is a validator address - return new RegExp(`^(?!pool)[a-z0-9]\{${VALIDATOR_ADDR_LEN}\}$`).test(address); } + + //Check for Validator addresses + if (new RegExp(`^(?!pool)[a-z0-9]{${VALIDATOR_ADDR_LEN}}$`).test(address)) { + return true; + } + + //Check for Byron-era (Base58 + CBOR) + try { + const decodedBase58 = base58.decode(address); + + const cborData = cbor.decodeFirstSync(decodedBase58); + + if (Array.isArray(cborData) && cborData.length >= 3) { + return true; + } + } catch (e) { + console.log(`Address: ${address} failed Base58 + CBOR test with error: ${e}`); + } + + return false; } /** @inheritdoc */ From ec9cb743363ad3637ce5cd02a19e23dcd4b9fc5b Mon Sep 17 00:00:00 2001 From: Manas Ladha Date: Thu, 9 Jan 2025 17:07:18 +0530 Subject: [PATCH 2/3] chore: add dependencies for sdk-coin-ada TICKET: WIN-4056 --- modules/sdk-coin-ada/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/modules/sdk-coin-ada/package.json b/modules/sdk-coin-ada/package.json index 7228059e21..78e2d6bc79 100644 --- a/modules/sdk-coin-ada/package.json +++ b/modules/sdk-coin-ada/package.json @@ -47,6 +47,8 @@ "@emurgo/cardano-serialization-lib-nodejs": "^12.0.1", "bech32": "^2.0.0", "bignumber.js": "^9.0.2", + "bs58": "^4.0.1", + "cbor": "^9.0.1", "lodash": "^4.17.21", "superagent": "^9.0.1", "tweetnacl": "^1.0.3" From 3773ebf932418c6dd2d4ad36fbd24e97cc6f62b5 Mon Sep 17 00:00:00 2001 From: Manas Ladha Date: Thu, 16 Jan 2025 16:04:46 +0530 Subject: [PATCH 3/3] feat: util and txBuilder changes for byron address support TICKET: WIN-4056 --- modules/sdk-coin-ada/package.json | 2 - modules/sdk-coin-ada/src/lib/transaction.ts | 4 +- .../src/lib/transactionBuilder.ts | 17 ++-- modules/sdk-coin-ada/src/lib/utils.ts | 77 +++++++++++++++--- modules/sdk-coin-ada/test/resources/index.ts | 80 ++++++++++++++++++- .../test/unit/transactionBuilder.ts | 34 +++++++- modules/sdk-coin-ada/test/unit/utils.ts | 10 ++- 7 files changed, 195 insertions(+), 29 deletions(-) diff --git a/modules/sdk-coin-ada/package.json b/modules/sdk-coin-ada/package.json index 78e2d6bc79..7228059e21 100644 --- a/modules/sdk-coin-ada/package.json +++ b/modules/sdk-coin-ada/package.json @@ -47,8 +47,6 @@ "@emurgo/cardano-serialization-lib-nodejs": "^12.0.1", "bech32": "^2.0.0", "bignumber.js": "^9.0.2", - "bs58": "^4.0.1", - "cbor": "^9.0.1", "lodash": "^4.17.21", "superagent": "^9.0.1", "tweetnacl": "^1.0.3" diff --git a/modules/sdk-coin-ada/src/lib/transaction.ts b/modules/sdk-coin-ada/src/lib/transaction.ts index 10dea97a33..971a1b5f00 100644 --- a/modules/sdk-coin-ada/src/lib/transaction.ts +++ b/modules/sdk-coin-ada/src/lib/transaction.ts @@ -148,7 +148,7 @@ export class Transaction extends BaseTransaction { for (let i = 0; i < this._transaction.body().outputs().len(); i++) { const output = this._transaction.body().outputs().get(i); result.outputs.push({ - address: output.address().to_bech32(), + address: adaUtils.getAddressString(output.address()), amount: output.amount().coin().to_str(), multiAssets: output.amount().multiasset() || undefined, }); @@ -237,7 +237,7 @@ export class Transaction extends BaseTransaction { for (let i = 0; i < tx_outputs.len(); i++) { const output = tx_outputs.get(i); outputs.push({ - address: output.address().to_bech32(), + address: adaUtils.getAddressString(output.address()), value: output.amount().coin().to_str(), }); } diff --git a/modules/sdk-coin-ada/src/lib/transactionBuilder.ts b/modules/sdk-coin-ada/src/lib/transactionBuilder.ts index 2766106e8e..1764d75164 100644 --- a/modules/sdk-coin-ada/src/lib/transactionBuilder.ts +++ b/modules/sdk-coin-ada/src/lib/transactionBuilder.ts @@ -148,10 +148,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { this._transactionOutputs.forEach((output) => { const amount = CardanoWasm.BigNum.from_str(output.amount); outputs.add( - CardanoWasm.TransactionOutput.new( - CardanoWasm.Address.from_bech32(output.address), - CardanoWasm.Value.new(amount) - ) + CardanoWasm.TransactionOutput.new(util.getWalletAddress(output.address), CardanoWasm.Value.new(amount)) ); totalAmountToSend = totalAmountToSend.checked_add(amount); }); @@ -160,7 +157,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { // estimate fee // add extra output for the change if (this._changeAddress && this._senderBalance) { - const changeAddress = CardanoWasm.Address.from_bech32(this._changeAddress); + const changeAddress = util.getWalletAddress(this._changeAddress); const utxoBalance = CardanoWasm.BigNum.from_str(this._senderBalance); const adjustment = BigNum.from_str('2000000'); @@ -188,7 +185,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { this._multiAssets.forEach((asset) => { let txOutputBuilder = CardanoWasm.TransactionOutputBuilder.new(); // changeAddress is the root address, which is where we want the tokens assets to be sent to - const toAddress = CardanoWasm.Address.from_bech32(this._changeAddress); + const toAddress = util.getWalletAddress(this._changeAddress); txOutputBuilder = txOutputBuilder.with_address(toAddress); let txOutputAmountBuilder = txOutputBuilder.next(); const assetName = CardanoWasm.AssetName.new(Buffer.from(asset.asset_name, 'hex')); @@ -301,7 +298,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { const quantity = assets!.get(assetName); let txOutputBuilder = CardanoWasm.TransactionOutputBuilder.new(); const outputAmount = CardanoWasm.BigNum.from_str(output.amount); - const toAddress = CardanoWasm.Address.from_bech32(output.address); + const toAddress = util.getWalletAddress(output.address); txOutputBuilder = txOutputBuilder.with_address(toAddress); let txOutputAmountBuilder = txOutputBuilder.next(); const multiAsset = CardanoWasm.MultiAsset.new(); @@ -314,14 +311,14 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { } else { outputs.add( CardanoWasm.TransactionOutput.new( - CardanoWasm.Address.from_bech32(output.address), + util.getWalletAddress(output.address), CardanoWasm.Value.new(CardanoWasm.BigNum.from_str(output.amount)) ) ); } }); if (this._changeAddress && this._senderBalance) { - const changeAddress = CardanoWasm.Address.from_bech32(this._changeAddress); + const changeAddress = util.getWalletAddress(this._changeAddress); const utxoBalance = CardanoWasm.BigNum.from_str(this._senderBalance); const adjustment = BigNum.from_str('2000000'); @@ -348,7 +345,7 @@ export abstract class TransactionBuilder extends BaseTransactionBuilder { this._multiAssets.forEach((asset) => { let txOutputBuilder = CardanoWasm.TransactionOutputBuilder.new(); // changeAddress is the root address, which is where we want the tokens assets to be sent to - const toAddress = CardanoWasm.Address.from_bech32(this._changeAddress); + const toAddress = util.getWalletAddress(this._changeAddress); txOutputBuilder = txOutputBuilder.with_address(toAddress); let txOutputAmountBuilder = txOutputBuilder.next(); const assetName = CardanoWasm.AssetName.new(Buffer.from(asset.asset_name, 'hex')); diff --git a/modules/sdk-coin-ada/src/lib/utils.ts b/modules/sdk-coin-ada/src/lib/utils.ts index 28c384d410..06801cc9cd 100644 --- a/modules/sdk-coin-ada/src/lib/utils.ts +++ b/modules/sdk-coin-ada/src/lib/utils.ts @@ -1,4 +1,4 @@ -import { AddressFormat, BaseUtils } from '@bitgo/sdk-core'; +import { AddressFormat, BaseUtils, InvalidAddressError } from '@bitgo/sdk-core'; import { BaseAddress, PublicKey, @@ -11,11 +11,13 @@ import { Ed25519KeyHash, ScriptHash, DRepKind, + ByronAddress, + Address, + EnterpriseAddress, + PointerAddress, } from '@emurgo/cardano-serialization-lib-nodejs'; import { KeyPair } from './keyPair'; import { bech32 } from 'bech32'; -import base58 from 'bs58'; -import cbor from 'cbor'; export const MIN_ADA_FOR_ONE_ASSET = '1500000'; export const VOTE_ALWAYS_ABSTAIN = 'always-abstain'; @@ -174,17 +176,12 @@ export class Utils implements BaseUtils { return true; } - //Check for Byron-era (Base58 + CBOR) + //Check for Byron-era address try { - const decodedBase58 = base58.decode(address); - - const cborData = cbor.decodeFirstSync(decodedBase58); - - if (Array.isArray(cborData) && cborData.length >= 3) { - return true; - } + return ByronAddress.is_valid(address); } catch (e) { - console.log(`Address: ${address} failed Base58 + CBOR test with error: ${e}`); + console.log(`Address: ${address} failed Byron test with error: ${e}`); + console.log(e.stack); } return false; @@ -247,6 +244,62 @@ export class Utils implements BaseUtils { : Buffer.from(serializedTx, 'base64'); return Buffer.from(CardanoTransaction.from_bytes(bufferRawTransaction).body().to_bytes()).toString('hex'); } + + /** + * Decode wallet address from string. + * Attempts to decode as Shelley (bech32) first, then Byron (base58). + * @param {string} address - Valid Byron or Shelley-era address. + * @returns {Address} - Valid address object. + * @throws {InvalidAddressError} If the address is neither valid Shelley nor Byron. + */ + getWalletAddress(address: string): Address { + if (!address || typeof address !== 'string') { + throw new InvalidAddressError('Provided address is not a valid string'); + } + + // Try decoding as a Shelley (bech32) address first + try { + return Address.from_bech32(address); + } catch (e) { + console.error(`Could not decode shelly address from string '${address}'`); + } + + // Try decoding as a Byron (base58) address later + try { + return ByronAddress.from_base58(address).to_address(); + } catch (e) { + console.error(`Could not decode byron address from string '${address}'`); + } + throw new InvalidAddressError('Provided string is not a valid Shelley or Byron address'); + } + + /** + * Decode address string from Address object. + * Attempts to decode as Shelley (bech32) first, then Byron (base58). + * @param {Address} address - Valid Address object + * @returns {string} - Valid Byron or Shelley-era address string. + * @throws {InvalidAddressError} If the Address object is neither valid Shelley nor Byron. + */ + getAddressString(address: Address): string { + // Check all Shelley address types + if ( + BaseAddress.from_address(address) || + EnterpriseAddress.from_address(address) || + RewardAddress.from_address(address) || + PointerAddress.from_address(address) + ) { + return address.to_bech32(); + } + + // If not Shelley, try Byron + const byronAddress = ByronAddress.from_address(address); + if (byronAddress) { + return byronAddress.to_base58(); + } + + // If neither, it's invalid + throw new InvalidAddressError('Provided Address is not a valid Shelley or Byron address'); + } } const utils = new Utils(); diff --git a/modules/sdk-coin-ada/test/resources/index.ts b/modules/sdk-coin-ada/test/resources/index.ts index 00e0af3ca5..eb2c221183 100644 --- a/modules/sdk-coin-ada/test/resources/index.ts +++ b/modules/sdk-coin-ada/test/resources/index.ts @@ -3,7 +3,7 @@ export const address = { address2: 'addr_test1qzpu9dmeztx7sfrl4qqtw3rvcewt822wn8mnatv8uc5yzdmvvz7nw9gmznn65g4ksrrfvyzhz52knc3mqxdyya47gz2q83wks3', address3: - '37btjrVyb4KDXBNC4haBVPCrro8AQPHwvCMp3RFhhSVWwfFmZ6wwzSK6JK1hY6wHNmtrpTf1kdbva8TCneM2YsiXT7mrzT21EacHnPpz5YyUdj64na', + '37btjrVyb4KDXBNC4haBVPCrro8AQPHwvCMp3RFhhSVWwfFmZ6wwzSK6JK1hY6wHNmtrpTf1kdbva8TCneM2YsiXT7mrzT21EacHnPpz5YyUdj64na', //valid byron testnet address4: 'addr_test1vr8rakm66rcfv4fcxqykg5lf0yv7lsyk9mvapx369jpvtcgfcuk7f', address6: 'addr_test1vqje364ylpl3alxxcclnlt6dcp7ecumzzaxnuy3gg8kyd7ssaj27y', // validator addresses @@ -17,6 +17,14 @@ export const address = { address14: 'pool19yzqr3meksnvzdxh5xf6aknfhldyqdj7eaquxgcjva4mzt5kg3v', address15: 'pool1ddskftmsscw92d7vnj89pldwx5feegkgcmamgt5t0e4lkd7mdp8', address16: 'pool1ddskftmsscw92d7vnj89pldwx5feegkgcmamgt5t0e4lkd7mdp3', + // Byron addresses + byron1: 'FHnt4NL7yPYB9XrjptqPt3jQS4CkXDtoZVFnvLRrbDaMQCoaUbzF3xuaC1NGFKS', // Valid Byron testnet + byron2: 'Ae2tdPwUPEZFRbyhz3cpfC2CumGzNkFBN2L42rcUc2yjQpEkxDbkPodpMAi', // Valid Byron + byron3: + '37btjrVyb4KEB2STADSsj3MYSAdj52X5FrFWpw2r7Wmj2GDzXjFRsHWuZqrw7zSkwopv8Ci3VWeg6bisU9dgJxW5hb2MZYeduNKbQJrqz3zVBsu9nT', // Valid Byron testnet + byron4: 'Ae2tdPwUPE_invalid_address', // Invalid Byron (malformed Base58) + byron5: 'DdzFFzCqr_invalid_base58', // Invalid Byron (malformed Base58) + byron6: '37btjrVyb4KDX_invalid_CBOR', // Invalid CBOR structure }; export const blockHash = { @@ -181,6 +189,76 @@ export const rawTx = { '765ee4f52bd3a2ae85a7d921ab2068698d70cf4ff291af2cf56f0858548d9e30c37b4f3e44c39ca885f18eb3c3648cbcaf30d1acb650d0a9c7d377591a214404', }; +export const rawTxByron = { + signedTx: + '84a40081825820a71708d13fd0f143dd492540c0ec5fd85011860c2c8823c1facd70afd4d6e15a0101828258390027360563c4479c6aa054cb2bd3ca9e394731ab59f8c45511ec8ba851aee1672f3f7fedc48feca58979967030dc8edc340c551b49d067638f1a004c4b4082581d60ce3edb7ad0f096553830096453e97919efc0962ed9d09a3a2c82c5e11a0ecd33be021a00028cad031a03ba7680a100818258209026aa14ba798e0182a60b3365b563c7ccecc0d05f98e530c84f657ee38adb8e58403881b490ee44f926f7c3016ac3f3622fcf18a11bc55b4cf4659a67c0bf73e1507ef2c8205488a246420106770f4c59e2de990a5df00a9f2c0b6cf87903542700f5f6', + unsignedTx: + '84a40081825820a71708d13fd0f143dd492540c0ec5fd85011860c2c8823c1facd70afd4d6e15a0101828258390027360563c4479c6aa054cb2bd3ca9e394731ab59f8c45511ec8ba851aee1672f3f7fedc48feca58979967030dc8edc340c551b49d067638f1a004c4b4082581d60ce3edb7ad0f096553830096453e97919efc0962ed9d09a3a2c82c5e11a0ecd33be0200031a03ba7680a10080f5f6', + unsignedTxBody: + 'a40081825820a71708d13fd0f143dd492540c0ec5fd85011860c2c8823c1facd70afd4d6e15a0101828258390027360563c4479c6aa054cb2bd3ca9e394731ab59f8c45511ec8ba851aee1672f3f7fedc48feca58979967030dc8edc340c551b49d067638f1a004c4b4082581d60ce3edb7ad0f096553830096453e97919efc0962ed9d09a3a2c82c5e11a0ecd33be0200031a03ba7680', + unsignedTx2: + '84a400818258201b53331e069a6e58fe77919d30c0cf299d13a2f5b3d9970ce473c1a66d71bf0301018282582e82d818582483581cc24e680a0c0b4cd7fd2ba9a886530d76eda1f0b6ed91fb8cdece5059a1024101001af7a4a80d1a0bebc20082582e82d818582483581c703ca7bafde5ffc5c8eddd83e83c56c9399da060c29978f1855b17a5a1024101001ad54e22d01a2fa65f73021a00028e0d031a2faf0800a0f5f6', + unsignedTx3: + '84a400818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba210101828258390027360563c4479c6aa054cb2bd3ca9e394731ab59f8c45511ec8ba851aee1672f3f7fedc48feca58979967030dc8edc340c551b49d067638f821a0016e360a1581ce16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed72a1434d494e1a001e84808258390027360563c4479c6aa054cb2bd3ca9e394731ab59f8c45511ec8ba851aee1672f3f7fedc48feca58979967030dc8edc340c551b49d067638f1a0117b093021a0002990d031a2faf0800a0f5f6', + unsignedTx4: + '84a400818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba210101838258390027360563c4479c6aa054cb2bd3ca9e394731ab59f8c45511ec8ba851aee1672f3f7fedc48feca58979967030dc8edc340c551b49d067638f821a0016e360a1581c279c909f348e533da5808898f87f9a14bb2c3dfbbacccd631d927a3fa144534e454b1a005b8d808258390027360563c4479c6aa054cb2bd3ca9e394731ab59f8c45511ec8ba851aee1672f3f7fedc48feca58979967030dc8edc340c551b49d067638f821a0016e360a1581c1f7a58a1aa1e6b047a42109ade331ce26c9c2cce027d043ff264fb1fa146425249434b531a004c4b408258390027360563c4479c6aa054cb2bd3ca9e394731ab59f8c45511ec8ba851aee1672f3f7fedc48feca58979967030dc8edc340c551b49d067638f1a0100ba1f021a0002ac21031a2faf0800a0f5f6', + unsignedTx5: + '84a400818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba210101818258390027360563c4479c6aa054cb2bd3ca9e394731ab59f8c45511ec8ba851aee1672f3f7fedc48feca58979967030dc8edc340c551b49d067638f1a012ea657021a000286a9031a2faf0800a0f5f6', + signedTx2: + '84a400818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba210101828258390027360563c4479c6aa054cb2bd3ca9e394731ab59f8c45511ec8ba851aee1672f3f7fedc48feca58979967030dc8edc340c551b49d067638f1a00775f1182581d60ce3edb7ad0f096553830096453e97919efc0962ed9d09a3a2c82c5e11a00c70041021a00028d05031a2faf0800a10081825820a5cdaab58f8c0cb82897b855b8a2315fba8061122072fcae1e0790641d9f9e675840f93024e952ab089c1a21f7f17af651cb61010c806ca94085ea1af735ef006a9621c09849aa6d3997aed17ab32e09c4b556ab09908bde4b02a711ccaf418d8804f5f6', + txHash: '0933ee2669649595c39150cdad64418303744352e1d315aa2f060f291980639a', + txHash2: 'a01c892a8241c83c1ce48b0d7cca6723a7aef3fdca59e79e85e03dabf20c3837', + txHash3: '9bd530c481278231bcfcc9222922be7100aefe3c983e7c850aaa51a4921e1c0c', + txHash4: '2283f0d3769140712f6d7410b3942d34292dde8230426898aa1809b6a5919bb8', + txHash5: 'e55ca00c9a6644d34b835a343629c345010b44dec29a8a4465f79b0de69669e3', + outputAddress1: { + address: 'FHnt4NL7yPYB9XrjptqPt3jQS4CkXDtoZVFnvLRrbDaMQCoaUbzF3xuaC1NGFKS', + value: '5000000', + }, + outputAddress2: { + address: 'FHnt4NL7yPXy1PeWKihJTbZzHPQsJVg9NeFZVKDhUai4JDgE6tH37LCSovJ2S5D', + value: '248329150', + }, + unsignedVoteDelegationTx: + '84a500818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba2101018182583901c7b28bcea90d440b5455a6a02a27ca59b8696f067fc1967f47f933e79558e969caa9e57adcfc40b9907eb794363b590faf42fff48c38eb881a003a76a7021a00029259031a2faf0800048183098200581c188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb8200581c8b75035882d4165bea8000c4d3f2c123ae33c1d92a751a78135a2402a0f5f6', + unsignedVoteDelegationTxBody: + 'a500818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba2101018182583901c7b28bcea90d440b5455a6a02a27ca59b8696f067fc1967f47f933e79558e969caa9e57adcfc40b9907eb794363b590faf42fff48c38eb881a003a76a7021a00029259031a2faf0800048183098200581c188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb8200581c8b75035882d4165bea8000c4d3f2c123ae33c1d92a751a78135a2402', + unsignedVoteDelegationTxHash: '6e80e3a2a78ee67f2c79070f37c5bde90845b636972a94cb7766af11d8d907db', + unsignedStakingActiveTx: + '84a500818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba2101018182583901c7b28bcea90d440b5455a6a02a27ca59b8696f067fc1967f47f933e79558e969caa9e57adcfc40b9907eb794363b590faf42fff48c38eb881a001be677021a00029e09031a2faf0800048382008200581c188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb83028200581c188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb581c7a623c48348501c2380e60ac2307fcd1b67df4218f819930821a15b383098200581c188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb8102a0f5f6', + unsignedStakingActiveTxBody: + 'a500818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba2101018182583901c7b28bcea90d440b5455a6a02a27ca59b8696f067fc1967f47f933e79558e969caa9e57adcfc40b9907eb794363b590faf42fff48c38eb881a001be677021a00029e09031a2faf0800048382008200581c188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb83028200581c188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb581c7a623c48348501c2380e60ac2307fcd1b67df4218f819930821a15b383098200581c188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb8102', + unsignedStakingActiveTxHash: 'd8ecaa7bfee2e28691673be378ea6583bc8efd5a6e29ca9cfb278279a06dd216', + unsignedStakingDeactiveTx: + '84a500818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba2101018182583901c7b28bcea90d440b5455a6a02a27ca59b8696f067fc1967f47f933e79558e969caa9e57adcfc40b9907eb794363b590faf42fff48c38eb881a005900a7021a00028cd9031a2faf0800048182018200581c188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdba0f5f6', + unsignedStakingDeactiveTxBody: + 'a500818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba2101018182583901c7b28bcea90d440b5455a6a02a27ca59b8696f067fc1967f47f933e79558e969caa9e57adcfc40b9907eb794363b590faf42fff48c38eb881a005900a7021a00028cd9031a2faf0800048182018200581c188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb', + unsignedStakingDeactiveTxHash: '69b22d013b9f0218568433e3e656ae758f974f7f3fff31936bc55be485e7ef68', + unsignedStakingWithdrawTx: + '84a500818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba2101018182583901c7b28bcea90d440b5455a6a02a27ca59b8696f067fc1967f47f933e79558e969caa9e57adcfc40b9907eb794363b590faf42fff48c38eb881a004d6496021a00028d31031a2faf080005a1581de0188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb1a0012e8c7a0f5f6', + unsignedStakingWithdrawTxBody: + 'a500818258203677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba2101018182583901c7b28bcea90d440b5455a6a02a27ca59b8696f067fc1967f47f933e79558e969caa9e57adcfc40b9907eb794363b590faf42fff48c38eb881a004d6496021a00028d31031a2faf080005a1581de0188fde65b1f9bd69b0edcc4e5a65fa93a13773090e1e2eef7a25cfdb1a0012e8c7', + unsignedStakingWithdrawTxHash: 'b38a52c79714916eb55c2a1cf62de47b93d3762527bf5adac6d0dc25c10106d0', + unsignedNewPledgeTx: + '84a5008282582078e05b7941011b5275552d0e5074056273125e18aac81643bfc3de59abac0e8600825820ce6d283af95b4da0e4b86f20ddf25dfb0343a7402e35877307c1465bd7beeafa000181825839006d57dea46753025b2c4e0fd9244df6a08fdd059dd1432af5eb7abbec6d57dea46753025b2c4e0fd9244df6a08fdd059dd1432af5eb7abbec1a59682f00021a000f42400319ea6004828a03581c10324dc34187735de46f6260d94620cdcc819f7ed1f93e3fc58d06a058201cc18daee56cb67a5dfb860194cd1e878be38401f3990efd92e16c5f8f4d959c1a05f5e1001a1dcd6500d81e820314581de0a9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a16181581ca9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a161818301191770782572656c6179732d6e65772e63617264616e6f2d746573746e65742e696f686b6465762e696f827368747470733a2f2f72622e67792f697a747a71582010c343fe0f6c01291df08de0ddc8fcbc07bccb503c51ffc051785e783b8d2f4483028200581ca9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a161581c10324dc34187735de46f6260d94620cdcc819f7ed1f93e3fc58d06a0a0f5f6', + unsignedNewPledgeTxBody: + 'a5008282582078e05b7941011b5275552d0e5074056273125e18aac81643bfc3de59abac0e8600825820ce6d283af95b4da0e4b86f20ddf25dfb0343a7402e35877307c1465bd7beeafa000181825839006d57dea46753025b2c4e0fd9244df6a08fdd059dd1432af5eb7abbec6d57dea46753025b2c4e0fd9244df6a08fdd059dd1432af5eb7abbec1a59682f00021a000f42400319ea6004828a03581c10324dc34187735de46f6260d94620cdcc819f7ed1f93e3fc58d06a058201cc18daee56cb67a5dfb860194cd1e878be38401f3990efd92e16c5f8f4d959c1a05f5e1001a1dcd6500d81e820314581de0a9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a16181581ca9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a161818301191770782572656c6179732d6e65772e63617264616e6f2d746573746e65742e696f686b6465762e696f827368747470733a2f2f72622e67792f697a747a71582010c343fe0f6c01291df08de0ddc8fcbc07bccb503c51ffc051785e783b8d2f4483028200581ca9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a161581c10324dc34187735de46f6260d94620cdcc819f7ed1f93e3fc58d06a0', + unsignedNewPledgeTxHash: '2acd6d314772eaa046d0cca7ef0306599d9d8dd961ad38da69e5f5b4cefafd7d', + unsignedUpdatePledgeTx: + '84a5008282582078e05b7941011b5275552d0e5074056273125e18aac81643bfc3de59abac0e8600825820ce6d283af95b4da0e4b86f20ddf25dfb0343a7402e35877307c1465bd7beeafa000181825839006d57dea46753025b2c4e0fd9244df6a08fdd059dd1432af5eb7abbec6d57dea46753025b2c4e0fd9244df6a08fdd059dd1432af5eb7abbec1a59682f00021a000f42400319ea6004818a03581c10324dc34187735de46f6260d94620cdcc819f7ed1f93e3fc58d06a058201cc18daee56cb67a5dfb860194cd1e878be38401f3990efd92e16c5f8f4d959c1a05f5e1001a1dcd6500d81e820314581de0a9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a16181581ca9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a161818301191770782572656c6179732d6e65772e63617264616e6f2d746573746e65742e696f686b6465762e696f827368747470733a2f2f72622e67792f697a747a71582010c343fe0f6c01291df08de0ddc8fcbc07bccb503c51ffc051785e783b8d2f44a0f5f6', + unsignedUpdatePledgeTxBody: + 'a5008282582078e05b7941011b5275552d0e5074056273125e18aac81643bfc3de59abac0e8600825820ce6d283af95b4da0e4b86f20ddf25dfb0343a7402e35877307c1465bd7beeafa000181825839006d57dea46753025b2c4e0fd9244df6a08fdd059dd1432af5eb7abbec6d57dea46753025b2c4e0fd9244df6a08fdd059dd1432af5eb7abbec1a59682f00021a000f42400319ea6004818a03581c10324dc34187735de46f6260d94620cdcc819f7ed1f93e3fc58d06a058201cc18daee56cb67a5dfb860194cd1e878be38401f3990efd92e16c5f8f4d959c1a05f5e1001a1dcd6500d81e820314581de0a9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a16181581ca9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a161818301191770782572656c6179732d6e65772e63617264616e6f2d746573746e65742e696f686b6465762e696f827368747470733a2f2f72622e67792f697a747a71582010c343fe0f6c01291df08de0ddc8fcbc07bccb503c51ffc051785e783b8d2f44', + unsignedUpdatePledgeTxHash: '671dfd283740d707e03a8ee5d21b3b9e3e50f57db68dc930606740ac7043151c', + partiallySignedPledgeTx: + '84a5008282582078e05b7941011b5275552d0e5074056273125e18aac81643bfc3de59abac0e8600825820ce6d283af95b4da0e4b86f20ddf25dfb0343a7402e35877307c1465bd7beeafa000181825839006d57dea46753025b2c4e0fd9244df6a08fdd059dd1432af5eb7abbec6d57dea46753025b2c4e0fd9244df6a08fdd059dd1432af5eb7abbec1a59682f00021a000f42400319ea6004828a03581c10324dc34187735de46f6260d94620cdcc819f7ed1f93e3fc58d06a058201cc18daee56cb67a5dfb860194cd1e878be38401f3990efd92e16c5f8f4d959c1a05f5e1001a1dcd6500d81e820314581de0a9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a16181581ca9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a161818301191770782572656c6179732d6e65772e63617264616e6f2d746573746e65742e696f686b6465762e696f827368747470733a2f2f72622e67792f697a747a71582010c343fe0f6c01291df08de0ddc8fcbc07bccb503c51ffc051785e783b8d2f4483028200581ca9fd4c265da033970e0b22b06422e12b3479e8dbd35abc82d405a161581c10324dc34187735de46f6260d94620cdcc819f7ed1f93e3fc58d06a0a100818258201b400d60aaf34eaf6dcbab9bba46001a23497886cf11066f7846933d30e5ad3f58406c92508135cb060187a2706ade8154782867b1526e9615d06742be5c56f037ab85894c098c2ab07971133c0477baee92adf3527ad7cc816f13e1e4c361041206f5f6', + pledgeNodeKeyPubkey: '1b400d60aaf34eaf6dcbab9bba46001a23497886cf11066f7846933d30e5ad3f', + pledgeNodeWitnessSignature: + '6c92508135cb060187a2706ade8154782867b1526e9615d06742be5c56f037ab85894c098c2ab07971133c0477baee92adf3527ad7cc816f13e1e4c361041206', + pledgeWalletKeyPubkey: 'a5cdaab58f8c0cb82897b855b8a2315fba8061122072fcae1e0790641d9f9e67', + pledgeWalletWitnessSignature: + '765ee4f52bd3a2ae85a7d921ab2068698d70cf4ff291af2cf56f0858548d9e30c37b4f3e44c39ca885f18eb3c3648cbcaf30d1acb650d0a9c7d377591a214404', +}; + export const wrwUser = { userKey: '{"iv":"BU+LhM/iNc6iFofnAggkxA==","v":1,"iter":10000,"ks":256,"ts":64,"mode"\n' + diff --git a/modules/sdk-coin-ada/test/unit/transactionBuilder.ts b/modules/sdk-coin-ada/test/unit/transactionBuilder.ts index ca4ab53298..e104a441a6 100644 --- a/modules/sdk-coin-ada/test/unit/transactionBuilder.ts +++ b/modules/sdk-coin-ada/test/unit/transactionBuilder.ts @@ -8,7 +8,39 @@ import { Transaction } from '../../src/lib/transaction'; describe('ADA Transaction Builder', async () => { const factory = new TransactionBuilderFactory(coins.get('tada')); - it('start and build an unsigned transfer tx', async () => { + it('start and build an unsigned transfer tx for byron address', async () => { + const txBuilder = factory.getTransferBuilder(); + txBuilder.input({ + transaction_id: '1b53331e069a6e58fe77919d30c0cf299d13a2f5b3d9970ce473c1a66d71bf03', + transaction_index: 1, + }); + const outputAmount = 200000000; + txBuilder.output({ + address: testData.rawTxByron.outputAddress1.address, + amount: outputAmount.toString(), + }); + const totalInput = 999600000; + txBuilder.changeAddress(testData.rawTxByron.outputAddress2.address, totalInput.toString()); + txBuilder.ttl(800000000); + // txBuilder.fee('200000'); + const tx = (await txBuilder.build()) as Transaction; + should.equal(tx.type, TransactionType.Send); + const txData = tx.toJson(); + txData.witnesses.length.should.equal(0); + txData.certs.length.should.equal(0); + txData.withdrawals.length.should.equal(0); + txData.outputs.length.should.equal(2); + txData.outputs[0].address.should.equal(testData.rawTxByron.outputAddress1.address); + txData.outputs[1].address.should.equal(testData.rawTxByron.outputAddress2.address); + const fee = tx.getFee; + txData.outputs[1].amount.should.equal((totalInput - outputAmount - Number(fee)).toString()); + fee.should.equal('167437'); + txData.id.should.equal(testData.rawTxByron.txHash2); + const txBroadcast = tx.toBroadcastFormat(); + should.equal(txBroadcast, testData.rawTxByron.unsignedTx2); + }); + + it('start and build an unsigned transfer tx for shelley address', async () => { const txBuilder = factory.getTransferBuilder(); txBuilder.input({ transaction_id: '3677e75c7ba699bfdc6cd57d42f246f86f63aefd76025006ac78313fad2bba21', diff --git a/modules/sdk-coin-ada/test/unit/utils.ts b/modules/sdk-coin-ada/test/unit/utils.ts index 00643a1075..ec02277531 100644 --- a/modules/sdk-coin-ada/test/unit/utils.ts +++ b/modules/sdk-coin-ada/test/unit/utils.ts @@ -17,7 +17,7 @@ describe('utils', () => { it('should validate addresses correctly', () => { should.equal(Utils.default.isValidAddress(address.address1), true); should.equal(Utils.default.isValidAddress(address.address2), true); - should.equal(Utils.default.isValidAddress(address.address3), false); + should.equal(Utils.default.isValidAddress(address.address3), true); should.equal(Utils.default.isValidAddress(address.address4), true); should.equal(Utils.default.isValidAddress('dfjk35y'), false); should.equal(Utils.default.isValidAddress(undefined as unknown as string), false); @@ -34,6 +34,14 @@ describe('utils', () => { should.equal(Utils.default.isValidAddress(address.address14), false); should.equal(Utils.default.isValidAddress(address.address15), false); should.equal(Utils.default.isValidAddress(address.address16), false); + + // Byron addresses + should.equal(Utils.default.isValidAddress(address.byron1), true); + should.equal(Utils.default.isValidAddress(address.byron2), true); + should.equal(Utils.default.isValidAddress(address.byron3), true); + should.equal(Utils.default.isValidAddress(address.byron4), false); + should.equal(Utils.default.isValidAddress(address.byron5), false); + should.equal(Utils.default.isValidAddress(address.byron6), false); }); it('should create stake and payment keys correctly', () => {