diff --git a/modules/abstract-utxo/src/offlineVault/OfflineVaultHalfSigned.ts b/modules/abstract-utxo/src/offlineVault/OfflineVaultHalfSigned.ts index 23f6c61146..aa25614725 100644 --- a/modules/abstract-utxo/src/offlineVault/OfflineVaultHalfSigned.ts +++ b/modules/abstract-utxo/src/offlineVault/OfflineVaultHalfSigned.ts @@ -1,5 +1,6 @@ import * as utxolib from '@bitgo/utxo-lib'; import { BIP32Interface } from '@bitgo/utxo-lib'; +import { BaseCoin } from '@bitgo/sdk-core'; import { getNetworkFromChain } from '../names'; @@ -14,11 +15,17 @@ function createHalfSignedFromPsbt(psbt: utxolib.Psbt): OfflineVaultHalfSigned { return { halfSigned: { txHex: psbt.toHex() } }; } -export function createHalfSigned(coin: string, prv: string | BIP32Interface, tx: unknown): OfflineVaultHalfSigned { +export function createHalfSigned( + coin: string, + prv: string | BIP32Interface, + derivationId: string, + tx: unknown +): OfflineVaultHalfSigned { const network = getNetworkFromChain(coin); if (typeof prv === 'string') { prv = utxolib.bip32.fromBase58(prv); } + prv = BaseCoin.deriveKeyWithSeedBip32(prv, derivationId).key; if (!OfflineVaultUnsigned.is(tx)) { throw new Error('unsupported transaction type'); } diff --git a/modules/abstract-utxo/src/offlineVault/OfflineVaultUnsigned.ts b/modules/abstract-utxo/src/offlineVault/OfflineVaultUnsigned.ts index 48dd14c7b4..2827ece32c 100644 --- a/modules/abstract-utxo/src/offlineVault/OfflineVaultUnsigned.ts +++ b/modules/abstract-utxo/src/offlineVault/OfflineVaultUnsigned.ts @@ -3,7 +3,7 @@ import { Triple } from '@bitgo/sdk-core'; import * as t from 'io-ts'; export const XPubWithDerivationPath = t.intersection( - [t.type({ xpub: t.string }), t.partial({ derivationPath: t.string })], + [t.type({ xpub: t.string }), t.partial({ derivedFromParentWithSeed: t.string })], 'XPubWithDerivationPath' ); diff --git a/modules/abstract-utxo/test/offlineVault/fixtures/Wsh2Of3.buildAdmin.custodial.json b/modules/abstract-utxo/test/offlineVault/fixtures/Wsh2Of3.buildAdmin.custodial.json index be1e098311..293bda0690 100644 --- a/modules/abstract-utxo/test/offlineVault/fixtures/Wsh2Of3.buildAdmin.custodial.json +++ b/modules/abstract-utxo/test/offlineVault/fixtures/Wsh2Of3.buildAdmin.custodial.json @@ -1,21 +1,33 @@ { "walletKeys": [ - "xprv9zXudaVgkhXsjTeXgpJ3K62R6bZDYQ5L5TVYfhGPLDDLNhfLtCYwHm4R4aMnMMeRpHSiM5Krxxbrux7iz99f7rSmZyddtBogiSch4PRVVXZ", - "xpub6CYwP1gQmPLwzD67x2nBoxiKquYs2CQExaqyQ3KbcntynZCoUGKErxXNg6Mft3x7r5c1xtHTp827ZRQY7dwUa8XYjQ5RCPUwtTPAe6bSv8b", - "xprv9s21ZrQH143K3Kh6W9VDkrpUSDrikEYKbbEKyB5Xn9bJeBPRSRSyWqQ5Fzoujj4eFmRKrxFPipYtfVqyu3aNYH4Lojrdhemi4aUdX8CjD8W" + { + "xpub": "xpub6CncomMyftm44Wo7zJNgmuQcT153FeE3eb2bDPrWMaStw1eCoheYxCdLszWMqYUWU7HVB57s6mD42HrxqqrETvVu6EcjhbhsQyRwrcyq9ph", + "xprv": "xprv9yoGQFq5qXCkr2ietGqgQmTstyEYrBWCHN6zR1StoEuv4DK4GALJQQJs2i6VUPfA9zKfCd8odpvS8rjrrz9BW3a7XE385MC7SMx7PiXNrM8", + "parent": { + "xpub": "xpub661MyMwAqRbcFh2wn3RP2zv6En76RjUWxqPT3dT3ZUi7TxxMJZXb3yoBHZAy71DUyqKewkXjxiGB2JzeYwUdPFzESq3PjSufeFgUiYqVPqu", + "xprv": "xprv9s21ZrQH143K3CxUg1tNfryMgkGc2GkfbcTrFF3S19B8bAdCm2DLWBUhSKLhLfPzZirDPuMP8inXZbQbd4Z1Z6dsAx4zV2tbjAfSwavLqNq" + } + }, + { + "xpub": "xpub6C3a1dkbEx4NReyHcdckxRDwedQmKH1EnnUf9xetKpBKaAo2qVckgBAaQfi6FdkQ7wX5YmmwakHsf4RWKFrUm3AGtD1WhkAR7nApvwkABC8" + }, + { + "xpub": "xpub661MyMwAqRbcFzLg5VNruBcXR52hePxoeszcGETvb5ksucEGKArew5k4mhfTkkPt7NfJ1RCGnGpm7LvNtakVGfg9kBiVi4Ybc43Yv7Uthtc", + "xprv": "xprv9s21ZrQH143K3WGCyTqrY3fns3CDEwExHf51Tr4K2kDu2ou7mdYQPHRavPnmk5YskxerZkGeTfo948rYQWpATKidSuPM9CH6dWdQPWtRSi9" + } ], "response": { - "txBase64": "cHNidP8BAN0CAAAAAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAAD9////AQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAP3///8DQEIPAAAAAAAiACAuAn5Z4A9++9biGFSGSJS+3cnn3ohmFQFpd0KlDIOfDYCEHgAAAAAAIgAgLgJ+WeAPfvvW4hhUhkiUvt3J596IZhUBaXdCpQyDnw376b0LAAAAACIAIHLLoHpPlak2CJhRYi7qO2MjLed3pKYntyo8SVjwbzOhAAAAAAABASsA4fUFAAAAACIAIC4CflngD3771uIYVIZIlL7dyefeiGYVAWl3QqUMg58NAQVpUiEC9wkjs3h1EBsdSbCEm+/vS3u5+Q8/Vx96MYf5jrRaBh4hAtIS5E2sC0WGyraJxWaWPsyZTTAFCJORgMu3B+E6jDLfIQI722k8S/c1hwtcvieb8+hrEd+73y/VQpRbvO+Nlt0Xe1OuIgYCO9tpPEv3NYcLXL4nm/PoaxHfu98v1UKUW7zvjZbdF3sMWeYqcQAAAAAAAAAAIgYC0hLkTawLRYbKtonFZpY+zJlNMAUIk5GAy7cH4TqMMt8MFQhHCwAAAAAAAAAAIgYC9wkjs3h1EBsdSbCEm+/vS3u5+Q8/Vx96MYf5jrRaBh4MKhST6AAAAAAAAAAAAAEBKwDh9QUAAAAAIgAgLgJ+WeAPfvvW4hhUhkiUvt3J596IZhUBaXdCpQyDnw0BBWlSIQL3CSOzeHUQGx1JsISb7+9Le7n5Dz9XH3oxh/mOtFoGHiEC0hLkTawLRYbKtonFZpY+zJlNMAUIk5GAy7cH4TqMMt8hAjvbaTxL9zWHC1y+J5vz6GsR37vfL9VClFu8742W3Rd7U64iBgI722k8S/c1hwtcvieb8+hrEd+73y/VQpRbvO+Nlt0XewxZ5ipxAAAAAAAAAAAiBgLSEuRNrAtFhsq2icVmlj7MmU0wBQiTkYDLtwfhOowy3wwVCEcLAAAAAAAAAAAiBgL3CSOzeHUQGx1JsISb7+9Le7n5Dz9XH3oxh/mOtFoGHgwqFJPoAAAAAAAAAAAAAQFpUiEC9wkjs3h1EBsdSbCEm+/vS3u5+Q8/Vx96MYf5jrRaBh4hAtIS5E2sC0WGyraJxWaWPsyZTTAFCJORgMu3B+E6jDLfIQI722k8S/c1hwtcvieb8+hrEd+73y/VQpRbvO+Nlt0Xe1OuIgICO9tpPEv3NYcLXL4nm/PoaxHfu98v1UKUW7zvjZbdF3sMWeYqcQAAAAAAAAAAIgIC0hLkTawLRYbKtonFZpY+zJlNMAUIk5GAy7cH4TqMMt8MFQhHCwAAAAAAAAAAIgIC9wkjs3h1EBsdSbCEm+/vS3u5+Q8/Vx96MYf5jrRaBh4MKhST6AAAAAAAAAAAAAEBaVIhAvcJI7N4dRAbHUmwhJvv70t7ufkPP1cfejGH+Y60WgYeIQLSEuRNrAtFhsq2icVmlj7MmU0wBQiTkYDLtwfhOowy3yECO9tpPEv3NYcLXL4nm/PoaxHfu98v1UKUW7zvjZbdF3tTriICAjvbaTxL9zWHC1y+J5vz6GsR37vfL9VClFu8742W3Rd7DFnmKnEAAAAAAAAAACICAtIS5E2sC0WGyraJxWaWPsyZTTAFCJORgMu3B+E6jDLfDBUIRwsAAAAAAAAAACICAvcJI7N4dRAbHUmwhJvv70t7ufkPP1cfejGH+Y60WgYeDCoUk+gAAAAAAAAAAAABAWlSIQNEoEL2IutxoZ+A74v7hk8gaO0tBkPRZbps5nQTTZy5RiED/TztbXrbe277ngeo5gQl9z+4gqai6uQb8wOqEQwOhXEhArSwlLUidtqWhqmgN5ZNm2N7ulwrPy97hSH7qUhRApoWU64iAgK0sJS1InbaloapoDeWTZtje7pcKz8ve4Uh+6lIUQKaFgxZ5ipxAAAAAAEAAAAiAgNEoEL2IutxoZ+A74v7hk8gaO0tBkPRZbps5nQTTZy5RgwqFJPoAAAAAAEAAAAiAgP9PO1tett7bvueB6jmBCX3P7iCpqLq5BvzA6oRDA6FcQwVCEcLAAAAAAEAAAAA", + "txBase64": "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", "descriptors": [ { "name": "external", - "value": "wsh(multi(2,xpub6DXG362ab56Awwiznqq3gDy9edPhwroBSgR9U5fztYkKFVzVRjsBqZNtusyuT3U841NogK9ByRFHz6Zhb5jTGWkiJyu3SVBqKiPFzw2GcyV/0/*,xpub6CYwP1gQmPLwzD67x2nBoxiKquYs2CQExaqyQ3KbcntynZCoUGKErxXNg6Mft3x7r5c1xtHTp827ZRQY7dwUa8XYjQ5RCPUwtTPAe6bSv8b/0/*,xpub661MyMwAqRbcFomZcB2E7zmCzFhD9hGAxp9vmZV9LV8HWyiZyxmE4diZ7EREPnU5XdHjx1w9Xp2o7qtP3mGmWM6SWYD1zGcA2VuU6VEjomd/0/*))#gw7wwcku", + "value": "wsh(multi(2,xpub6CncomMyftm44Wo7zJNgmuQcT153FeE3eb2bDPrWMaStw1eCoheYxCdLszWMqYUWU7HVB57s6mD42HrxqqrETvVu6EcjhbhsQyRwrcyq9ph/0/*,xpub6C3a1dkbEx4NReyHcdckxRDwedQmKH1EnnUf9xetKpBKaAo2qVckgBAaQfi6FdkQ7wX5YmmwakHsf4RWKFrUm3AGtD1WhkAR7nApvwkABC8/0/*,xpub661MyMwAqRbcFzLg5VNruBcXR52hePxoeszcGETvb5ksucEGKArew5k4mhfTkkPt7NfJ1RCGnGpm7LvNtakVGfg9kBiVi4Ybc43Yv7Uthtc/0/*))#9t6e8p38", "signatures": [], "lastIndex": 1 }, { "name": "internal", - "value": "wsh(multi(2,xpub6DXG362ab56Awwiznqq3gDy9edPhwroBSgR9U5fztYkKFVzVRjsBqZNtusyuT3U841NogK9ByRFHz6Zhb5jTGWkiJyu3SVBqKiPFzw2GcyV/1/*,xpub6CYwP1gQmPLwzD67x2nBoxiKquYs2CQExaqyQ3KbcntynZCoUGKErxXNg6Mft3x7r5c1xtHTp827ZRQY7dwUa8XYjQ5RCPUwtTPAe6bSv8b/1/*,xpub661MyMwAqRbcFomZcB2E7zmCzFhD9hGAxp9vmZV9LV8HWyiZyxmE4diZ7EREPnU5XdHjx1w9Xp2o7qtP3mGmWM6SWYD1zGcA2VuU6VEjomd/1/*))#sw3k4yqr", + "value": "wsh(multi(2,xpub6CncomMyftm44Wo7zJNgmuQcT153FeE3eb2bDPrWMaStw1eCoheYxCdLszWMqYUWU7HVB57s6mD42HrxqqrETvVu6EcjhbhsQyRwrcyq9ph/1/*,xpub6C3a1dkbEx4NReyHcdckxRDwedQmKH1EnnUf9xetKpBKaAo2qVckgBAaQfi6FdkQ7wX5YmmwakHsf4RWKFrUm3AGtD1WhkAR7nApvwkABC8/1/*,xpub661MyMwAqRbcFzLg5VNruBcXR52hePxoeszcGETvb5ksucEGKArew5k4mhfTkkPt7NfJ1RCGnGpm7LvNtakVGfg9kBiVi4Ybc43Yv7Uthtc/1/*))#at4pua8c", "signatures": [], "lastIndex": 0 } @@ -23,32 +35,32 @@ "formatVersion": 1, "coin": "btc", "pubs": [ - "xpub6DXG362ab56Awwiznqq3gDy9edPhwroBSgR9U5fztYkKFVzVRjsBqZNtusyuT3U841NogK9ByRFHz6Zhb5jTGWkiJyu3SVBqKiPFzw2GcyV", - "xpub6CYwP1gQmPLwzD67x2nBoxiKquYs2CQExaqyQ3KbcntynZCoUGKErxXNg6Mft3x7r5c1xtHTp827ZRQY7dwUa8XYjQ5RCPUwtTPAe6bSv8b", - "xpub661MyMwAqRbcFomZcB2E7zmCzFhD9hGAxp9vmZV9LV8HWyiZyxmE4diZ7EREPnU5XdHjx1w9Xp2o7qtP3mGmWM6SWYD1zGcA2VuU6VEjomd" + "xpub6CncomMyftm44Wo7zJNgmuQcT153FeE3eb2bDPrWMaStw1eCoheYxCdLszWMqYUWU7HVB57s6mD42HrxqqrETvVu6EcjhbhsQyRwrcyq9ph", + "xpub6C3a1dkbEx4NReyHcdckxRDwedQmKH1EnnUf9xetKpBKaAo2qVckgBAaQfi6FdkQ7wX5YmmwakHsf4RWKFrUm3AGtD1WhkAR7nApvwkABC8", + "xpub661MyMwAqRbcFzLg5VNruBcXR52hePxoeszcGETvb5ksucEGKArew5k4mhfTkkPt7NfJ1RCGnGpm7LvNtakVGfg9kBiVi4Ybc43Yv7Uthtc" ], "xpubsWithDerivationPath": { "user": { - "xpub": "xpub6DXG362ab56Awwiznqq3gDy9edPhwroBSgR9U5fztYkKFVzVRjsBqZNtusyuT3U841NogK9ByRFHz6Zhb5jTGWkiJyu3SVBqKiPFzw2GcyV", - "derivedFromParentWithSeed": "143700591154482" + "xpub": "xpub6CncomMyftm44Wo7zJNgmuQcT153FeE3eb2bDPrWMaStw1eCoheYxCdLszWMqYUWU7HVB57s6mD42HrxqqrETvVu6EcjhbhsQyRwrcyq9ph", + "derivedFromParentWithSeed": "102411319365644" }, "backup": { - "xpub": "xpub6CYwP1gQmPLwzD67x2nBoxiKquYs2CQExaqyQ3KbcntynZCoUGKErxXNg6Mft3x7r5c1xtHTp827ZRQY7dwUa8XYjQ5RCPUwtTPAe6bSv8b", - "derivedFromParentWithSeed": "210593312354420" + "xpub": "xpub6C3a1dkbEx4NReyHcdckxRDwedQmKH1EnnUf9xetKpBKaAo2qVckgBAaQfi6FdkQ7wX5YmmwakHsf4RWKFrUm3AGtD1WhkAR7nApvwkABC8", + "derivedFromParentWithSeed": "31343056841989" }, "bitgo": { - "xpub": "xpub661MyMwAqRbcFomZcB2E7zmCzFhD9hGAxp9vmZV9LV8HWyiZyxmE4diZ7EREPnU5XdHjx1w9Xp2o7qtP3mGmWM6SWYD1zGcA2VuU6VEjomd" + "xpub": "xpub661MyMwAqRbcFzLg5VNruBcXR52hePxoeszcGETvb5ksucEGKArew5k4mhfTkkPt7NfJ1RCGnGpm7LvNtakVGfg9kBiVi4Ybc43Yv7Uthtc" } }, - "walletId": "6788d3cf8eaf7aa1db27d4575218103c", + "walletId": "678a3f70d333194b9330abe16e0b3ee4", "walletLabel": "UtxoWalletClient", "amount": "199995579", - "address": "bc1q9cp8uk0qpal0h4hzrp2gvjy5hmwune773pnp2qtfwap22ryrnuxsehzwgh", - "pendingApprovalId": "6788d3cf8eaf7aa1db27d4f563e0e411", - "creatorId": "6788d3ce8eaf7aa1db27d18bc5baa93d", - "creatorEmail": "testuser-1737020360683@example.com", - "createDate": "2025-01-16T09:39:27.667Z", - "enterpriseId": "6788d3ce8eaf7aa1db27d2a664daec54", + "address": "bc1q96awm56777g6enlzp6qskc2r6hjxvv5ay0d4vrf356nl0255s3xq94kt80", + "pendingApprovalId": "678a3f70d333194b9330ac7fd64996bd", + "creatorId": "678a3f6fd333194b9330a924b8ef81fa", + "creatorEmail": "testuser-1737113447468@example.com", + "createDate": "2025-01-17T11:30:56.504Z", + "enterpriseId": "678a3f6fd333194b9330aa30f75a9219", "enterpriseName": "Foo Enterprises", "enterpriseFeatureFlags": [ "enableMMI" @@ -61,13 +73,13 @@ "waived": true }, "coinSpecific": { - "txHex": "70736274ff0100dd020000000201010101010101010101010101010101010101010101010101010101010101010000000000fdffffff01010101010101010101010101010101010101010101010101010101010101010100000000fdffffff0340420f00000000002200202e027e59e00f7efbd6e21854864894beddc9e7de88661501697742a50c839f0d80841e00000000002200202e027e59e00f7efbd6e21854864894beddc9e7de88661501697742a50c839f0dfbe9bd0b0000000022002072cba07a4f95a936089851622eea3b63232de777a4a627b72a3c4958f06f33a1000000000001012b00e1f505000000002200202e027e59e00f7efbd6e21854864894beddc9e7de88661501697742a50c839f0d010569522102f70923b37875101b1d49b0849befef4b7bb9f90f3f571f7a3187f98eb45a061e2102d212e44dac0b4586cab689c566963ecc994d300508939180cbb707e13a8c32df21023bdb693c4bf735870b5cbe279bf3e86b11dfbbdf2fd542945bbcef8d96dd177b53ae2206023bdb693c4bf735870b5cbe279bf3e86b11dfbbdf2fd542945bbcef8d96dd177b0c59e62a710000000000000000220602d212e44dac0b4586cab689c566963ecc994d300508939180cbb707e13a8c32df0c1508470b0000000000000000220602f70923b37875101b1d49b0849befef4b7bb9f90f3f571f7a3187f98eb45a061e0c2a1493e800000000000000000001012b00e1f505000000002200202e027e59e00f7efbd6e21854864894beddc9e7de88661501697742a50c839f0d010569522102f70923b37875101b1d49b0849befef4b7bb9f90f3f571f7a3187f98eb45a061e2102d212e44dac0b4586cab689c566963ecc994d300508939180cbb707e13a8c32df21023bdb693c4bf735870b5cbe279bf3e86b11dfbbdf2fd542945bbcef8d96dd177b53ae2206023bdb693c4bf735870b5cbe279bf3e86b11dfbbdf2fd542945bbcef8d96dd177b0c59e62a710000000000000000220602d212e44dac0b4586cab689c566963ecc994d300508939180cbb707e13a8c32df0c1508470b0000000000000000220602f70923b37875101b1d49b0849befef4b7bb9f90f3f571f7a3187f98eb45a061e0c2a1493e8000000000000000000010169522102f70923b37875101b1d49b0849befef4b7bb9f90f3f571f7a3187f98eb45a061e2102d212e44dac0b4586cab689c566963ecc994d300508939180cbb707e13a8c32df21023bdb693c4bf735870b5cbe279bf3e86b11dfbbdf2fd542945bbcef8d96dd177b53ae2202023bdb693c4bf735870b5cbe279bf3e86b11dfbbdf2fd542945bbcef8d96dd177b0c59e62a710000000000000000220202d212e44dac0b4586cab689c566963ecc994d300508939180cbb707e13a8c32df0c1508470b0000000000000000220202f70923b37875101b1d49b0849befef4b7bb9f90f3f571f7a3187f98eb45a061e0c2a1493e8000000000000000000010169522102f70923b37875101b1d49b0849befef4b7bb9f90f3f571f7a3187f98eb45a061e2102d212e44dac0b4586cab689c566963ecc994d300508939180cbb707e13a8c32df21023bdb693c4bf735870b5cbe279bf3e86b11dfbbdf2fd542945bbcef8d96dd177b53ae2202023bdb693c4bf735870b5cbe279bf3e86b11dfbbdf2fd542945bbcef8d96dd177b0c59e62a710000000000000000220202d212e44dac0b4586cab689c566963ecc994d300508939180cbb707e13a8c32df0c1508470b0000000000000000220202f70923b37875101b1d49b0849befef4b7bb9f90f3f571f7a3187f98eb45a061e0c2a1493e800000000000000000001016952210344a042f622eb71a19f80ef8bfb864f2068ed2d0643d165ba6ce674134d9cb9462103fd3ced6d7adb7b6efb9e07a8e60425f73fb882a6a2eae41bf303aa110c0e85712102b4b094b52276da9686a9a037964d9b637bba5c2b3f2f7b8521fba94851029a1653ae220202b4b094b52276da9686a9a037964d9b637bba5c2b3f2f7b8521fba94851029a160c59e62a71000000000100000022020344a042f622eb71a19f80ef8bfb864f2068ed2d0643d165ba6ce674134d9cb9460c2a1493e80000000001000000220203fd3ced6d7adb7b6efb9e07a8e60425f73fb882a6a2eae41bf303aa110c0e85710c1508470b000000000100000000", + "txHex": "70736274ff0100dd020000000201010101010101010101010101010101010101010101010101010101010101010000000000fdffffff01010101010101010101010101010101010101010101010101010101010101010100000000fdffffff0340420f00000000002200202ebaedd35ef791accfe20e810b6143d5e466329d23db560d31a6a7f7aa94844c80841e00000000002200202ebaedd35ef791accfe20e810b6143d5e466329d23db560d31a6a7f7aa94844cfbe9bd0b00000000220020f93495909b34ba1d2ca94c7da9797d8aa1581b62e722d82a03f3c7643dec7e4d000000000001012b00e1f505000000002200202ebaedd35ef791accfe20e810b6143d5e466329d23db560d31a6a7f7aa94844c01056952210231066324132f6e21cf8180dfc44a0b0c588f67ec94abfb11282c6757fbdaa83e2103411a3c0e12c0dd260200ba6967215df7351f1271dc91a02e17105093781e92c821031131c3f2b783a0fd33116ec839505dacd867f944828c2617e44cd9692559e9a753ae22060231066324132f6e21cf8180dfc44a0b0c588f67ec94abfb11282c6757fbdaa83e0cac73ca3800000000000000002206031131c3f2b783a0fd33116ec839505dacd867f944828c2617e44cd9692559e9a70cf200daf10000000000000000220603411a3c0e12c0dd260200ba6967215df7351f1271dc91a02e17105093781e92c80c065caa7300000000000000000001012b00e1f505000000002200202ebaedd35ef791accfe20e810b6143d5e466329d23db560d31a6a7f7aa94844c01056952210231066324132f6e21cf8180dfc44a0b0c588f67ec94abfb11282c6757fbdaa83e2103411a3c0e12c0dd260200ba6967215df7351f1271dc91a02e17105093781e92c821031131c3f2b783a0fd33116ec839505dacd867f944828c2617e44cd9692559e9a753ae22060231066324132f6e21cf8180dfc44a0b0c588f67ec94abfb11282c6757fbdaa83e0cac73ca3800000000000000002206031131c3f2b783a0fd33116ec839505dacd867f944828c2617e44cd9692559e9a70cf200daf10000000000000000220603411a3c0e12c0dd260200ba6967215df7351f1271dc91a02e17105093781e92c80c065caa7300000000000000000001016952210231066324132f6e21cf8180dfc44a0b0c588f67ec94abfb11282c6757fbdaa83e2103411a3c0e12c0dd260200ba6967215df7351f1271dc91a02e17105093781e92c821031131c3f2b783a0fd33116ec839505dacd867f944828c2617e44cd9692559e9a753ae22020231066324132f6e21cf8180dfc44a0b0c588f67ec94abfb11282c6757fbdaa83e0cac73ca3800000000000000002202031131c3f2b783a0fd33116ec839505dacd867f944828c2617e44cd9692559e9a70cf200daf10000000000000000220203411a3c0e12c0dd260200ba6967215df7351f1271dc91a02e17105093781e92c80c065caa7300000000000000000001016952210231066324132f6e21cf8180dfc44a0b0c588f67ec94abfb11282c6757fbdaa83e2103411a3c0e12c0dd260200ba6967215df7351f1271dc91a02e17105093781e92c821031131c3f2b783a0fd33116ec839505dacd867f944828c2617e44cd9692559e9a753ae22020231066324132f6e21cf8180dfc44a0b0c588f67ec94abfb11282c6757fbdaa83e0cac73ca3800000000000000002202031131c3f2b783a0fd33116ec839505dacd867f944828c2617e44cd9692559e9a70cf200daf10000000000000000220203411a3c0e12c0dd260200ba6967215df7351f1271dc91a02e17105093781e92c80c065caa730000000000000000000101695221036d8e4569e3b5aed40218b638381e63503f2480de88537aee5608075a0fe84db121029b64f0ed527ddb4c816e66b7951f10ce0c41648a2bf41022ea11b98bf4361b342102c9e58a9123aff3ecd80bcded4d6827dae2b19de00cabe01cb49e9f3c08926c1b53ae2202029b64f0ed527ddb4c816e66b7951f10ce0c41648a2bf41022ea11b98bf4361b340c065caa730000000001000000220202c9e58a9123aff3ecd80bcded4d6827dae2b19de00cabe01cb49e9f3c08926c1b0cf200daf100000000010000002202036d8e4569e3b5aed40218b638381e63503f2480de88537aee5608075a0fe84db10cac73ca38000000000100000000", "inputIds": [ "0101010101010101010101010101010101010101010101010101010101010101:0", "0101010101010101010101010101010101010101010101010101010101010101:1" ] }, "recipientsInfo": [], - "keyDerivationPath": "143700591154482" + "keyDerivationPath": "102411319365644" } } diff --git a/modules/abstract-utxo/test/offlineVault/halfSigned.ts b/modules/abstract-utxo/test/offlineVault/halfSigned.ts index 11644493d6..62964cfc09 100644 --- a/modules/abstract-utxo/test/offlineVault/halfSigned.ts +++ b/modules/abstract-utxo/test/offlineVault/halfSigned.ts @@ -3,6 +3,7 @@ import assert from 'assert'; import crypto from 'crypto'; import * as t from 'io-ts'; +import { decodeOrElse } from '@bitgo/sdk-core'; import * as utxolib from '@bitgo/utxo-lib'; import { createHalfSigned } from '../../src/offlineVault'; @@ -14,8 +15,13 @@ function getFixturesNames(): string[] { return fs.readdirSync(__dirname + '/fixtures').filter((f) => f.endsWith('.json')); } +const KeyPair = t.intersection([t.type({ xpub: t.string }), t.partial({ xprv: t.string })]); + +const KeyWithParent = t.intersection([KeyPair, t.partial({ parent: KeyPair })]); +type KeyWithParent = t.TypeOf; + const Fixture = t.type({ - walletKeys: t.array(t.string), + walletKeys: t.array(KeyWithParent), response: t.unknown, }); @@ -23,10 +29,9 @@ type Fixture = t.TypeOf; async function readFixture(name: string): Promise { const data = JSON.parse(await fs.promises.readFile(__dirname + '/fixtures/' + name, 'utf-8')); - if (!Fixture.is(data)) { - throw new Error(`Invalid fixture ${name}`); - } - return data; + return decodeOrElse('Fixture', Fixture, data, (e) => { + throw new Error(`failed to decode fixture ${name}: ${e}`); + }); } function withRotatedXpubs(tx: DescriptorTransaction): DescriptorTransaction { @@ -63,17 +68,30 @@ function withoutDescriptors(tx: DescriptorTransaction): DescriptorTransaction { }; } +function getDerivationId(v: DescriptorTransaction['xpubsWithDerivationPath']): string { + const id = v.user.derivedFromParentWithSeed; + assert(id); + return id; +} + +function getRootPrv(walletKeys: KeyWithParent[]): utxolib.BIP32Interface { + assert(walletKeys[0]); + assert(walletKeys[0].parent); + assert(walletKeys[0].parent.xprv); + return utxolib.bip32.fromBase58(walletKeys[0].parent.xprv); +} + describe('OfflineVaultHalfSigned', function () { for (const fixtureName of getFixturesNames()) { it(`can sign fixture ${fixtureName}`, async function () { const { walletKeys, response } = await readFixture(fixtureName); - const prv = utxolib.bip32.fromBase58(walletKeys[0]); - createHalfSigned('btc', prv, response); - assert(DescriptorTransaction.is(response)); + const rootPrv = getRootPrv(walletKeys); + const derivationId = getDerivationId(response.xpubsWithDerivationPath); + createHalfSigned('btc', rootPrv, derivationId, response); const mutations = [withRotatedXpubs(response), withRandomXpubs(response), withoutDescriptors(response)]; for (const mutation of mutations) { - assert.throws(() => createHalfSigned('btc', prv, mutation)); + assert.throws(() => createHalfSigned('btc', rootPrv, derivationId, mutation)); } }); }