@@ -21,13 +21,13 @@ import {
2121} from 'shared/lib/typings/migration'
2222import { appRoute , AppRoute } from '@core/router'
2323import Validator from 'shared/lib/validator'
24- import { api , walletSetupType } from 'shared/lib/wallet'
24+ import { api , wallet , walletSetupType } from 'shared/lib/wallet'
2525import { localize } from '@core/i18n'
2626import { showAppNotification } from './notifications'
2727import { LedgerMigrationProgress } from 'shared/lib/typings/migration'
2828import { SetupType } from 'shared/lib/typings/setup'
2929import { convertToHex , decodeUint64 , getJsonRequestOptions , hexToBytes } from '@lib/utils'
30- import { generateAddress } from '@iota/core'
30+ import { createPrepareTransfers , generateAddress } from '@iota/core'
3131import { convertBech32AddressToEd25519Address } from './ed25519'
3232import { Buffer } from 'buffer'
3333import { blake2b } from 'blakejs'
@@ -43,7 +43,10 @@ export const PERMANODE = 'https://chronicle.iota.org/api'
4343export const ADDRESS_SECURITY_LEVEL = 2
4444
4545/** Minimum migration balance */
46- export const MINIMUM_MIGRATION_BALANCE = 1000000
46+ export const MINIMUM_MIGRATION_BALANCE = 0
47+
48+ /** Amount to hardcode in the inputs to bypass legacy validation in ISC */
49+ export const MINIMUM_MIGRATABLE_AMOUNT = 1000000
4750
4851/** Bundle mining timeout for each bundle */
4952export const MINING_TIMEOUT_SECONDS = 10 * 60
@@ -111,8 +114,6 @@ export const migration = writable<MigrationState>({
111114 bundles : writable < Bundle [ ] > ( [ ] ) ,
112115} )
113116
114- export const depositAddressMigration = writable < string | null > ( null )
115-
116117export const didInitialiseMigrationListeners = writable < boolean > ( false )
117118
118119export const hardwareIndexes = writable < HardwareIndexes > ( {
@@ -122,6 +123,8 @@ export const hardwareIndexes = writable<HardwareIndexes>({
122123
123124export const migrationLog = writable < MigrationLog [ ] > ( [ ] )
124125
126+ export const migrationAddress = writable < MigrationAddress > ( )
127+
125128export const createUnsignedBundle = (
126129 outputAddress : string ,
127130 inputAddresses : string [ ] ,
@@ -245,6 +248,45 @@ function iscVluEncode(value: number): Buffer {
245248 return Buffer . from ( buf )
246249}
247250
251+ export const generateMigrationAddress = async ( ledger : boolean = false ) : Promise < MigrationAddress > =>
252+ new Promise < MigrationAddress > ( ( resolve , reject ) => {
253+ if ( ledger ) {
254+ api . getAccounts ( {
255+ onSuccess : ( getAccountsResponse ) => {
256+ api . getMigrationAddress (
257+ false ,
258+ getAccountsResponse . payload [ get ( activeProfile ) . ledgerMigrationCount ] . id ,
259+ {
260+ onSuccess : ( response ) => {
261+ resolve ( response . payload as unknown as MigrationAddress )
262+ } ,
263+ onError : ( error ) => {
264+ console . error ( error )
265+ reject ( error )
266+ } ,
267+ }
268+ )
269+ } ,
270+ onError : ( getAccountsError ) => {
271+ console . error ( getAccountsError )
272+ reject ( getAccountsError )
273+ } ,
274+ } )
275+ } else {
276+ const { accounts } = get ( wallet )
277+
278+ api . getMigrationAddress ( false , get ( accounts ) [ 0 ] . id , {
279+ onSuccess : ( response ) => {
280+ resolve ( response . payload as unknown as MigrationAddress )
281+ } ,
282+ onError : ( error ) => {
283+ console . error ( error )
284+ reject ( error )
285+ } ,
286+ } )
287+ }
288+ } )
289+
248290/**
249291 * Gets migration data and sets it to state
250292 *
@@ -262,19 +304,14 @@ export const getMigrationData = async (migrationSeed: string, initialAddressInde
262304
263305 for ( let index = initialAddressIndex ; index < initialAddressIndex + FIXED_ADDRESSES_GENERATED ; index ++ ) {
264306 const legacyAddress = generateAddress ( migrationSeed , index , ADDRESS_SECURITY_LEVEL )
265- const binaryAddress = '0x' + convertToHex ( legacyAddress )
266- const balance = await fetchMigratableBalance ( binaryAddress )
307+ const hexAddress = '0x' + convertToHex ( legacyAddress )
308+ const balance = await fetchMigratableBalance ( hexAddress )
267309
268- // The correct amount for migration is tracked in totalBalance and is diplayed to the user.
269- // If the totalBalance is less than the Min required storage deposit on stardust the receipt will contain the error messgage
270- // ex. "not enough base tokens for storage deposit: available 211188 < required 239500 base tokens"
271310 totalBalance += balance
272311 if ( balance > 0 ) {
273- // Hardcode MINIMUM_MIGRATION_BALANCE for every input so we bypass legacy validation tool in contract which doesnt allow migrating less than MINIMUM_MIGRATION_BALANCE.
274- // The ISC only cares about the addresses in the bundle, it internaly resolves the balances and does NOT depend on the amounts hardcoded here.
275312 inputs . push ( {
276313 address : legacyAddress ,
277- balance : MINIMUM_MIGRATION_BALANCE ,
314+ balance,
278315 spent : false ,
279316 index,
280317 securityLevel : ADDRESS_SECURITY_LEVEL ,
@@ -312,14 +349,14 @@ export const getMigrationData = async (migrationSeed: string, initialAddressInde
312349 }
313350}
314351
315- async function fetchMigratableBalance ( binaryAddress : string ) : Promise < number > {
352+ async function fetchMigratableBalance ( hexAddress : string ) : Promise < number > {
316353 const body = {
317354 functionName : 'getMigratableBalance' ,
318355 contractName : 'legacymigration' ,
319356 arguments : {
320357 Items : [
321358 {
322- value : binaryAddress ,
359+ value : hexAddress ,
323360 key : '0x61' , // convertToHex("a")
324361 } ,
325362 ] ,
@@ -413,26 +450,28 @@ export const getLedgerMigrationData = (
413450 const _get = async ( addresses : AddressInput [ ] ) : Promise < MigrationData > => {
414451 let totalBalance = 0
415452 const inputs : Input [ ] = [ ]
453+ const { lastCheckedAddressIndex } = get ( get ( migration ) . data )
454+
416455 for ( let index = 0 ; index < addresses . length ; index ++ ) {
417- const legacyAddress = addresses [ index ] . address
418- const binaryAddress = '0x' + convertToHex ( legacyAddress )
419- const balance = await fetchMigratableBalance ( binaryAddress )
456+ const legacyAddress = addresses [ index ]
457+ const hexAddress = '0x' + convertToHex ( legacyAddress . address )
458+ const balance = await fetchMigratableBalance ( hexAddress )
420459
421460 totalBalance += balance
422461 if ( balance > 0 ) {
423462 inputs . push ( {
424- address : legacyAddress ,
463+ address : legacyAddress . address ,
425464 balance,
426465 spent : false ,
427- index,
466+ index : legacyAddress . index ,
428467 securityLevel : ADDRESS_SECURITY_LEVEL ,
429468 spentBundleHashes : [ ] ,
430469 } )
431470 }
432471 }
433472
434473 const migrationData : MigrationData = {
435- lastCheckedAddressIndex : initialAddressIndex + addresses . length ,
474+ lastCheckedAddressIndex : lastCheckedAddressIndex + addresses . length ,
436475 balance : totalBalance ,
437476 inputs : inputs ,
438477 spentAddresses : false ,
@@ -650,49 +689,29 @@ export const createMinedLedgerMigrationBundle = (
650689 */
651690export const createLedgerMigrationBundle = (
652691 bundleIndex : number ,
692+ migrationAddress : MigrationAddress ,
653693 prepareTransfersFn : ( transfers : Transfer [ ] , inputs : Input [ ] ) => Promise < string [ ] > ,
654694 callback : ( ) => void
655- ) : Promise < MigrationBundle > =>
656- new Promise ( ( resolve , reject ) => {
657- api . getAccounts ( {
658- onSuccess ( getAccountsResponse ) {
659- api . getMigrationAddress (
660- false ,
661- getAccountsResponse . payload [ get ( activeProfile ) . ledgerMigrationCount ] . id ,
662- {
663- onSuccess ( response ) {
664- resolve ( response . payload )
665- } ,
666- onError ( error ) {
667- reject ( error )
668- } ,
669- }
670- )
671- } ,
672- onError ( getAccountsError ) {
673- reject ( getAccountsError )
674- } ,
675- } )
676- } ) . then ( ( address : MigrationAddress ) => {
677- depositAddressMigration . set ( address . bech32 )
678- const bundle = findMigrationBundle ( bundleIndex )
679- const transfer = {
680- address : address . trytes . toString ( ) ,
681- value : bundle . inputs . reduce ( ( acc , input ) => acc + input . balance , 0 ) ,
682- tag : 'U' . repeat ( 27 ) ,
683- }
695+ ) : Promise < MigrationBundle > => {
696+ const bundle = findMigrationBundle ( bundleIndex )
684697
685- openLedgerLegacyTransactionPopup ( transfer , bundle . inputs )
698+ const transfer = {
699+ address : migrationAddress . trytes ,
700+ value : bundle . inputs . reduce ( ( acc , input ) => acc + input . balance , 0 ) ,
701+ tag : 'U' . repeat ( 27 ) ,
702+ }
686703
687- return prepareTransfersFn (
688- [ transfer ] ,
689- bundle . inputs . map ( ( input ) => Object . assign ( { } , input , { keyIndex : input . index } ) )
690- ) . then ( ( trytes ) => {
691- updateLedgerBundleState ( bundleIndex , trytes , false )
692- callback ( )
693- return { trytes, bundleHash : asTransactionObject ( trytes [ 0 ] ) . bundle }
694- } )
704+ openLedgerLegacyTransactionPopup ( transfer , bundle . inputs )
705+
706+ return prepareTransfersFn (
707+ [ transfer ] ,
708+ bundle . inputs . map ( ( input ) => Object . assign ( { } , input , { keyIndex : input . index } ) )
709+ ) . then ( ( trytes ) => {
710+ updateLedgerBundleState ( bundleIndex , trytes , false )
711+ callback ( )
712+ return { trytes, bundleHash : asTransactionObject ( trytes [ 0 ] ) . bundle }
695713 } )
714+ }
696715
697716/**
698717 * Sends ledger migration bundle
@@ -729,40 +748,75 @@ export const sendLedgerMigrationBundle = (bundleHash: string, trytes: string[]):
729748 *
730749 * @returns {Promise<Receipt> }
731750 */
732- export const sendOffLedgerMigrationRequest = async ( trytes : string [ ] ) : Promise < any > => {
733- const offLedgerHexRequest = createOffLedgerRequest ( trytes )
734- await fetchOffLedgerRequest ( offLedgerHexRequest . request )
735- const receiptResponse = await fetchReceiptForRequest ( offLedgerHexRequest . requestId )
736- return receiptResponse
751+ export const sendOffLedgerMigrationRequest = async ( trytes : string [ ] , bundleIndex : number ) : Promise < any > => {
752+ const { bundles } = get ( migration )
753+ try {
754+ const offLedgerHexRequest = createOffLedgerRequest ( trytes )
755+ await fetchOffLedgerRequest ( offLedgerHexRequest . request )
756+
757+ const receipt = await fetchReceiptForRequest ( offLedgerHexRequest . requestId )
758+ if ( receipt ?. errorMessage ) {
759+ throw new Error ( receipt ?. errorMessage )
760+ }
761+
762+ // Update bundle and mark it as migrated
763+ bundles . update ( ( _bundles ) =>
764+ _bundles . map ( ( bundle ) => {
765+ if ( bundle . index === bundleIndex ) {
766+ return Object . assign ( { } , bundle , { migrated : true , confirmed : true } )
767+ }
768+
769+ return bundle
770+ } )
771+ )
772+
773+ return receipt
774+ } catch ( err ) {
775+ throw new Error ( err . message || 'Failed to send migration request' )
776+ }
737777}
738778/**
739779 * Creates migration bundle
740780 *
741781 * @method createMigrationBundle
742782 *
743- * @param {number[] } inputIndexes
744- * @param {boolean } mine
783+ * @param {number } bundleIndex
784+ * @param {MigrationAddress } migrationAddress
745785 *
746786 * @returns {Promise }
747787 */
748- export const createMigrationBundle = (
749- inputAddressIndexes : number [ ] ,
750- offset : number ,
751- mine : boolean
752- ) : Promise < MigrationBundle > => {
788+ export const createMigrationBundle = async ( bundle : Bundle , migrationAddress : MigrationAddress ) : Promise < string [ ] > => {
753789 const { seed } = get ( migration )
754790
755- return new Promise ( ( resolve , reject ) => {
756- api . createMigrationBundle ( get ( seed ) , inputAddressIndexes , mine , MINING_TIMEOUT_SECONDS , offset , LOG_FILE_NAME , {
757- onSuccess ( response ) {
758- assignBundleHash ( inputAddressIndexes , response . payload , mine )
759- resolve ( response . payload )
760- } ,
761- onError ( error ) {
762- reject ( error )
763- } ,
791+ const prepareTransfers = createPrepareTransfers ( )
792+
793+ const transfers = [
794+ {
795+ value : bundle . inputs . length * MINIMUM_MIGRATABLE_AMOUNT , // hardcoded amount
796+ address : removeAddressChecksum ( migrationAddress . trytes ) ,
797+ } ,
798+ ]
799+ // The correct amount for migration is tracked in totalBalance and is diplayed to the user.
800+ // If the totalBalance is less than the Min required storage deposit on stardust the receipt will contain the error messgage
801+ // ex. "not enough base tokens for storage deposit: available 211188 < required 239500 base tokens"
802+ // Hardcode MINIMUM_MIGRATABLE_AMOUNT for every input so we bypass legacy validation tool in contract which doesnt allow migrating less than MINIMUM_MIGRATABLE_AMOUNT.
803+ // The ISC only cares about the addresses in the bundle, it internaly resolves the balances and does NOT depend on the amounts hardcoded here.
804+ const inputsForTransfer : any [ ] = bundle . inputs . map ( ( input ) => ( {
805+ address : input . address ,
806+ keyIndex : input . index ,
807+ security : input . securityLevel ,
808+ balance : MINIMUM_MIGRATABLE_AMOUNT , // hardcoded amount
809+ } ) )
810+
811+ try {
812+ const bundleTrytes : string [ ] = await prepareTransfers ( get ( seed ) , transfers , {
813+ inputs : inputsForTransfer ,
764814 } )
765- } )
815+
816+ return bundleTrytes
817+ } catch ( err ) {
818+ throw new Error ( err . message || 'Failed to prepare transfers' )
819+ }
766820}
767821
768822export async function fetchOffLedgerRequest ( request : string ) : Promise < void > {
@@ -787,7 +841,7 @@ export async function fetchOffLedgerRequest(request: string): Promise<void> {
787841 try {
788842 const response = await fetch ( endpoint , requestOptions )
789843
790- if ( response . status == = 400 ) {
844+ if ( response . status > = 400 ) {
791845 return response . json ( ) . then ( ( err ) => {
792846 throw new Error ( `Message: ${ err . Message } , Error: ${ err . Error } ` )
793847 } )
@@ -827,7 +881,7 @@ export async function fetchReceiptForRequest(requestId: string): Promise<any> {
827881 try {
828882 const response = await fetch ( endpoint , requestOptions )
829883
830- if ( response . status == = 400 ) {
884+ if ( response . status > = 400 ) {
831885 return response . json ( ) . then ( ( err ) => {
832886 throw new Error ( `Message: ${ err . Message } , Error: ${ err . Error } ` )
833887 } )
0 commit comments