Skip to content

Commit c2d0ecd

Browse files
brancodercpl121
andauthored
Fix: Update submitting multiple bundles (#63)
* fix: refactor software profile submiting offledger request for single and multiple bundles * fix: add submitting multiple bundles for ledger devices * fix: update submitting multiple modules for ledger devices * fix: error "tx not added to the mempool" * fix: add migration log for multiple bundles * fix: remove extra routing after migration * fix: address indexes in bundles * fix: address indexes in bundles * fix: remove log file --------- Co-authored-by: cpl121 <[email protected]>
1 parent 40b5397 commit c2d0ecd

File tree

4 files changed

+291
-411
lines changed

4 files changed

+291
-411
lines changed

packages/shared/lib/migration.ts

Lines changed: 137 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ import {
2121
} from 'shared/lib/typings/migration'
2222
import { appRoute, AppRoute } from '@core/router'
2323
import Validator from 'shared/lib/validator'
24-
import { api, walletSetupType } from 'shared/lib/wallet'
24+
import { api, wallet, walletSetupType } from 'shared/lib/wallet'
2525
import { localize } from '@core/i18n'
2626
import { showAppNotification } from './notifications'
2727
import { LedgerMigrationProgress } from 'shared/lib/typings/migration'
2828
import { SetupType } from 'shared/lib/typings/setup'
2929
import { convertToHex, decodeUint64, getJsonRequestOptions, hexToBytes } from '@lib/utils'
30-
import { generateAddress } from '@iota/core'
30+
import { createPrepareTransfers, generateAddress } from '@iota/core'
3131
import { convertBech32AddressToEd25519Address } from './ed25519'
3232
import { Buffer } from 'buffer'
3333
import { blake2b } from 'blakejs'
@@ -43,7 +43,10 @@ export const PERMANODE = 'https://chronicle.iota.org/api'
4343
export 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 */
4952
export 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-
116117
export const didInitialiseMigrationListeners = writable<boolean>(false)
117118

118119
export const hardwareIndexes = writable<HardwareIndexes>({
@@ -122,6 +123,8 @@ export const hardwareIndexes = writable<HardwareIndexes>({
122123

123124
export const migrationLog = writable<MigrationLog[]>([])
124125

126+
export const migrationAddress = writable<MigrationAddress>()
127+
125128
export 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
*/
651690
export 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

768822
export 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
})

packages/shared/routes/setup/Congratulations.svelte

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
migrationLog,
1212
resetMigrationState,
1313
totalMigratedBalance,
14-
depositAddressMigration,
14+
migrationAddress,
1515
} from 'shared/lib/migration'
1616
import { showAppNotification } from 'shared/lib/notifications'
1717
import { Platform } from 'shared/lib/platform'
@@ -133,9 +133,9 @@
133133
function consultExplorerClick() {
134134
let urlToOpen = ''
135135
if ($activeProfile.isDeveloperProfile) {
136-
urlToOpen = `https://explorer.iota-alphanet.iotaledger.net/devnet/addr/${$depositAddressMigration}`
136+
urlToOpen = `https://explorer.iota-alphanet.iotaledger.net/devnet/addr/${$migrationAddress.bech32}`
137137
} else {
138-
urlToOpen = `https://explorer.stardust-mainnet.iotaledger.net/mainnet/addr/${$depositAddressMigration}`
138+
urlToOpen = `https://explorer.stardust-mainnet.iotaledger.net/mainnet/addr/${$migrationAddress.bech32}`
139139
}
140140
Platform.openUrl(urlToOpen)
141141
}

0 commit comments

Comments
 (0)