mirror of
https://github.com/trezor/trezor-suite.git
synced 2026-03-02 21:45:14 +01:00
fix(suite): fix label drop for RBG transactions
This commit is contained in:
committed by
Peter Sanderson
parent
b4327a4bd8
commit
96d12a424c
@@ -350,7 +350,13 @@ export type SuiteAnalyticsEvent =
|
||||
| {
|
||||
type: EventType.SettingsGeneralLabelingProvider;
|
||||
payload: {
|
||||
provider: 'dropbox' | 'google' | 'fileSystem' | 'sdCard' | 'missing-provider' | '';
|
||||
provider:
|
||||
| 'dropbox'
|
||||
| 'google'
|
||||
| 'fileSystem'
|
||||
| 'missing-provider'
|
||||
| 'inMemoryTest'
|
||||
| ''; // Todo: 'sdCard' not implemented yet
|
||||
};
|
||||
}
|
||||
| {
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
selectMetadata,
|
||||
selectSelectedProviderForLabels,
|
||||
} from 'src/reducers/suite/metadataReducer';
|
||||
import { InMemoryTestProvider } from '../../services/suite/metadata/InMemoryTestProvider';
|
||||
|
||||
export const setAccountAdd = createAction(METADATA.ACCOUNT_ADD, (payload: Account) => ({
|
||||
payload,
|
||||
@@ -80,11 +81,12 @@ export type MetadataAction =
|
||||
// needs to be declared here in top level context because it's not recommended to keep classes instances in redux state (serialization)
|
||||
const providerInstance: Record<
|
||||
DataType,
|
||||
DropboxProvider | GoogleProvider | FileSystemProvider | undefined
|
||||
DropboxProvider | GoogleProvider | FileSystemProvider | InMemoryTestProvider | undefined
|
||||
> = {
|
||||
labels: undefined,
|
||||
passwords: undefined,
|
||||
};
|
||||
|
||||
const fetchIntervals: { [deviceState: string]: any } = {}; // any because of native at the moment, otherwise number | undefined
|
||||
|
||||
const createProviderInstance = (
|
||||
@@ -93,6 +95,7 @@ const createProviderInstance = (
|
||||
environment: OAuthServerEnvironment = 'production',
|
||||
clientId?: string,
|
||||
) => {
|
||||
// eslint-disable-next-line default-case
|
||||
switch (type) {
|
||||
case 'dropbox':
|
||||
return new DropboxProvider({
|
||||
@@ -103,8 +106,8 @@ const createProviderInstance = (
|
||||
return new GoogleProvider(tokens, environment);
|
||||
case 'fileSystem':
|
||||
return new FileSystemProvider();
|
||||
default:
|
||||
throw new Error(`provider of type ${type} is not implemented`);
|
||||
case 'inMemoryTest':
|
||||
return new InMemoryTestProvider();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -803,8 +806,13 @@ export const addAccountMetadata =
|
||||
|
||||
if (payload.type === 'outputLabel') {
|
||||
if (typeof payload.value !== 'string' || payload.value.length === 0) {
|
||||
if (!nextMetadata.outputLabels[payload.txid])
|
||||
return Promise.resolve({ success: false });
|
||||
if (!nextMetadata.outputLabels[payload.txid]) {
|
||||
// If we try to delete already deleted label it's ok.
|
||||
// No problem happened. ¯\_ (ツ)_/¯
|
||||
|
||||
return Promise.resolve({ success: true });
|
||||
}
|
||||
|
||||
delete nextMetadata.outputLabels[payload.txid][payload.outputIndex];
|
||||
if (Object.keys(nextMetadata.outputLabels[payload.txid]).length === 0) {
|
||||
delete nextMetadata.outputLabels[payload.txid];
|
||||
|
||||
@@ -0,0 +1,570 @@
|
||||
import { AccountsRootState } from '@suite-common/wallet-core';
|
||||
import { Account } from '@suite-common/wallet-types';
|
||||
|
||||
export const accountSpendingCoins: Account = {
|
||||
deviceState: 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q@AC94BB9C1B08FE73BE1E3322:0',
|
||||
index: 0,
|
||||
backendType: undefined,
|
||||
misc: undefined,
|
||||
marker: undefined,
|
||||
path: "m/84'/1'/0'",
|
||||
descriptor:
|
||||
'(accountSpendingCoins:descriptor)vpub5YX1yJFY8E236pH3iNvCpThsXLxoQoC4nwraaS5h4TZwaSp1Gg9SQoxCsrumxjh7nZRQQkNfH29TEDeMvAZVmD3rpmsDnFc5Sj4JgJG6m4b',
|
||||
key: '(accountSpendingCoins:key)vpub5YX1yJFY8E236pH3iNvCpThsXLxoQoC4nwraaS5h4TZwaSp1Gg9SQoxCsrumxjh7nZRQQkNfH29TEDeMvAZVmD3rpmsDnFc5Sj4JgJG6m4b-regtest-mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q@AC94BB9C1B08FE73BE1E3322:0',
|
||||
accountType: 'normal',
|
||||
symbol: 'regtest',
|
||||
empty: false,
|
||||
visible: true,
|
||||
balance: '199993110',
|
||||
availableBalance: '199993110',
|
||||
formattedBalance: '1.9999311',
|
||||
tokens: [],
|
||||
addresses: {
|
||||
change: [
|
||||
{
|
||||
address: 'bcrt1qejqxwzfld7zr6mf7ygqy5s5se5xq7vmt8ntmj0',
|
||||
path: "m/84'/1'/0'/1/0",
|
||||
transfers: 1,
|
||||
balance: '199993110',
|
||||
sent: '0',
|
||||
received: '199993110',
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qze76uzqteg6un6jfcryrxhwvfvjj58tsdeh9xy',
|
||||
path: "m/84'/1'/0'/1/1",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qr5p6f5sk09sms57ket074vywfymuthlg7y8tn0',
|
||||
path: "m/84'/1'/0'/1/2",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qwn0s88t9r39g72m78mcaxj72sy3ct4m4dulavf',
|
||||
path: "m/84'/1'/0'/1/3",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qguznsd2hyl69gjx2axd6f5qu9k274qj9v5syhd',
|
||||
path: "m/84'/1'/0'/1/4",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q8zx9dlztqz9apm7y5gtx8a0tlz57fhncycvun5',
|
||||
path: "m/84'/1'/0'/1/5",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qger2dlc2mykcavfxs0ad8eupr058njwp2e8n6m',
|
||||
path: "m/84'/1'/0'/1/6",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qjm4p4nykvsczt26llswppmfe7xraane9nfruqv',
|
||||
path: "m/84'/1'/0'/1/7",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qm3sx7jlgj7yd3y2ad0jm587k98pcc2x5wfq5jf',
|
||||
path: "m/84'/1'/0'/1/8",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qcvgld0z38vnx9fnpsgwuc583838ldv8sf38pwz',
|
||||
path: "m/84'/1'/0'/1/9",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1quja53ex7clst8yhkwenhy8p67aa36kedqszlun',
|
||||
path: "m/84'/1'/0'/1/10",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qlxvp7fwy0azketw0afgw0snxssyphmtthe4g8g',
|
||||
path: "m/84'/1'/0'/1/11",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1ql02lgacsfm543teeymtw2p7xz9unxe6572mxeh',
|
||||
path: "m/84'/1'/0'/1/12",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qnuafw94yvu6td7tcfqea823y342ttrc9d32qnx',
|
||||
path: "m/84'/1'/0'/1/13",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q92khcru77q7hrctf7ter2kltpgtrz23nhnkcaz',
|
||||
path: "m/84'/1'/0'/1/14",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qu8ts4a80ylfq7hgy9aqt0rk65gekmt5p029ymm',
|
||||
path: "m/84'/1'/0'/1/15",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qc0zg0xrs0grvrmr0hrq7u0rdthadsrk406w0dk',
|
||||
path: "m/84'/1'/0'/1/16",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1quvm4wfs9pjrqvr4rmy60k8uevg009jhtx9zzxr',
|
||||
path: "m/84'/1'/0'/1/17",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qetngs772lxz97x94v9ycfjtwelmu7aqmuu5vkl',
|
||||
path: "m/84'/1'/0'/1/18",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qaydzjvcf0qnfxs9aw8zmazt88f6j0wjtgqqn22',
|
||||
path: "m/84'/1'/0'/1/19",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qlecqdxptwt65c52uqzmdqk9njyt4rmygf2vsvd',
|
||||
path: "m/84'/1'/0'/1/20",
|
||||
transfers: 0,
|
||||
},
|
||||
],
|
||||
used: [
|
||||
{
|
||||
address: 'bcrt1qkvwu9g3k2pdxewfqr7syz89r3gj557l374sg5v',
|
||||
path: "m/84'/1'/0'/0/0",
|
||||
transfers: 2,
|
||||
balance: '0',
|
||||
sent: '1000000000',
|
||||
received: '1000000000',
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qldlynaqp0hy4zc2aag3pkenzvxy65saej0huey',
|
||||
path: "m/84'/1'/0'/0/1",
|
||||
transfers: 2,
|
||||
balance: '0',
|
||||
sent: '1000000000',
|
||||
received: '1000000000',
|
||||
},
|
||||
],
|
||||
unused: [
|
||||
{
|
||||
address: 'bcrt1q9l0rk0gkgn73d0gc57qn3t3cwvucaj3h98jwg4',
|
||||
path: "m/84'/1'/0'/0/2",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qtxe2hdle9he8hc2xds7yl2m8zutjksv0gmszw2',
|
||||
path: "m/84'/1'/0'/0/3",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qglrv8xrtf68udd5pxj2pxyq5s7lynq204v2da8',
|
||||
path: "m/84'/1'/0'/0/4",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qds6ygc07t7d8prjs60qnx0nv4gexx9hex07wwl',
|
||||
path: "m/84'/1'/0'/0/5",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q86udlgffezp9kgjvqlfah7a6c8dpepameugfw5',
|
||||
path: "m/84'/1'/0'/0/6",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q503m8pxyvf7ypurcvwv2kp0ajyjumsjq5ad7xq',
|
||||
path: "m/84'/1'/0'/0/7",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qg805w4uhsz3sy9stasdx2rkwp4haf446ew055v',
|
||||
path: "m/84'/1'/0'/0/8",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qy2f6mkfa3aaecqz2s2xr0utf6edza7qzh7gnnn',
|
||||
path: "m/84'/1'/0'/0/9",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q4tm6cgxd3m7uqgzmwxfclruqz894qdv5w05kss',
|
||||
path: "m/84'/1'/0'/0/10",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qguvdun4cjty8js34wswdn4nv2ne7jamajjwgkj',
|
||||
path: "m/84'/1'/0'/0/11",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qp6py2d8acmqcvdfeht3escetv5aunru5d4vlk0',
|
||||
path: "m/84'/1'/0'/0/12",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q88fkyl4zxrcejt4s75ynkunpps3n9kchzvnaw8',
|
||||
path: "m/84'/1'/0'/0/13",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qjfvfjqsp3khtgdkqw87up39skp6zvp062q7y93',
|
||||
path: "m/84'/1'/0'/0/14",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qf49m5zxk9957z8yzyfed6glrcvz3r7y4demdex',
|
||||
path: "m/84'/1'/0'/0/15",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qfmej7qk4f66vx8a5aq5t5nlvp0hxuwe0fg9rrp',
|
||||
path: "m/84'/1'/0'/0/16",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qlfxf67wwud59ru0d4e7qa36zh0daxcfr6ec53g',
|
||||
path: "m/84'/1'/0'/0/17",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qcmmen68dyt59pkh7dv2xxf07tme7qxzn0upszf',
|
||||
path: "m/84'/1'/0'/0/18",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qpcgw9fuec7wjjnq8rl0cwfwa7mqvrheud24890',
|
||||
path: "m/84'/1'/0'/0/19",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qxukydnhdldsjf0c8rguxmja9kxsydjzwj486hk',
|
||||
path: "m/84'/1'/0'/0/20",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qq7tkmktggcwp46jefmnh7ytade562ka8qte4un',
|
||||
path: "m/84'/1'/0'/0/21",
|
||||
transfers: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
utxo: [
|
||||
{
|
||||
txid: '4ec6d03abb2e3e52a50301ee353621cbda13d7a6cb57bc8f373519af5b25026b(originalTransaction)',
|
||||
vout: 0,
|
||||
amount: '199993110',
|
||||
blockHeight: 153,
|
||||
address: 'bcrt1qejqxwzfld7zr6mf7ygqy5s5se5xq7vmt8ntmj0',
|
||||
path: "m/84'/1'/0'/1/0",
|
||||
confirmations: 1,
|
||||
},
|
||||
],
|
||||
history: { total: 3, unconfirmed: 0, addrTxCount: 5 },
|
||||
metadata: {
|
||||
'1': {
|
||||
fileName: '7061500d8482d422b07cbd59784db51ae60f72a5c25f47d3d344888585e0c37d.mtdt',
|
||||
aesKey: '16994717c3c3a64fefd0725e4e4599826ea82bdc1b56c3cf664541c83ccef7d4',
|
||||
},
|
||||
key: 'tpubDCZB6sR48s4T5Cr8qHUYSZEFCQMMHRg8AoVKVmvcAP5bRw7ArDKeoNwKAJujV3xCPkBvXH5ejSgbgyN6kREmF7sMd41NdbuHa8n1DZNxSMg',
|
||||
},
|
||||
networkType: 'bitcoin',
|
||||
page: { index: 1, size: 25, total: 1 },
|
||||
};
|
||||
|
||||
export const accountReceivingCoins: Account = {
|
||||
deviceState: 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q@AC94BB9C1B08FE73BE1E3322:0',
|
||||
index: 1,
|
||||
backendType: undefined,
|
||||
misc: undefined,
|
||||
marker: undefined,
|
||||
path: "m/84'/1'/1'",
|
||||
descriptor:
|
||||
'(accountReceivingCoins:descriptor)vpub5YX1yJFY8E238aESifzcpXQHLzNDYJC22yLWqCwJ5pN85E27ku5wUXdhnh3HSMs3HibDQzeWmVeH52bAAa9LvkK4L1V9XfZbmHxGDuZSJks',
|
||||
key: '(accountReceivingCoins:key)vpub5YX1yJFY8E238aESifzcpXQHLzNDYJC22yLWqCwJ5pN85E27ku5wUXdhnh3HSMs3HibDQzeWmVeH52bAAa9LvkK4L1V9XfZbmHxGDuZSJks-regtest-mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q@AC94BB9C1B08FE73BE1E3322:0',
|
||||
accountType: 'normal',
|
||||
symbol: 'regtest',
|
||||
empty: false,
|
||||
visible: true,
|
||||
balance: '1799997910',
|
||||
availableBalance: '1799997910',
|
||||
formattedBalance: '17.9999791',
|
||||
tokens: [],
|
||||
addresses: {
|
||||
change: [
|
||||
{
|
||||
address: 'bcrt1q757q50q0mgt3xkqfneflvutpyktxv3x3jfupg8',
|
||||
path: "m/84'/1'/1'/1/0",
|
||||
transfers: 1,
|
||||
balance: '99997910',
|
||||
sent: '0',
|
||||
received: '99997910',
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q5k7s87q26syf6muqthlprn06sxhklq693u69lu',
|
||||
path: "m/84'/1'/1'/1/1",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qaugvv7tvw6h434feqs4ep62qxv7e0xdm9txmft',
|
||||
path: "m/84'/1'/1'/1/2",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qrm08dns67sj0ycvsqm0rnqzp7ff2crdgurmjzd',
|
||||
path: "m/84'/1'/1'/1/3",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qnrk8ewh48ynxrqlvtmaepgxax3623rx043zate',
|
||||
path: "m/84'/1'/1'/1/4",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qz4xx7glecua7fy0xvdvwx3vhh4zpa7pyfw7dhy',
|
||||
path: "m/84'/1'/1'/1/5",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qr2fm62qd8r9thyvkn44drxr0877jgy88xukyam',
|
||||
path: "m/84'/1'/1'/1/6",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qhzhpctls7v8l2cvxnhz743m3lkpptq4twq6wu9',
|
||||
path: "m/84'/1'/1'/1/7",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qcg80e2vyv52vl8fx5842y2raxx4lp4f5wg85dm',
|
||||
path: "m/84'/1'/1'/1/8",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qtayc24uac0hm95eyvmz4rcalnhj46hasutljcy',
|
||||
path: "m/84'/1'/1'/1/9",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qrspwywt63gp07uwn7f5n0522v4jxnhglpskzjl',
|
||||
path: "m/84'/1'/1'/1/10",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qjkgrmaffye33epk5p4cy67ynnhj4njml0j4lmu',
|
||||
path: "m/84'/1'/1'/1/11",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qq7n68efyh97v7fvdkq8eh7thnlaag4z7kpme7g',
|
||||
path: "m/84'/1'/1'/1/12",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qc0qc6wjds0mlw29zu5rn7ngkqu5p6rnkp2zdeu',
|
||||
path: "m/84'/1'/1'/1/13",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q8pdptz6j4z7ky5e264sjcf9c4g6ushvlc75m7l',
|
||||
path: "m/84'/1'/1'/1/14",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qp4fqac7tqmtsxuef7sgud90xljyza2ffaqm5a2',
|
||||
path: "m/84'/1'/1'/1/15",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q5a4vteamypse527xxm9995h6vempc8jps5ttq6',
|
||||
path: "m/84'/1'/1'/1/16",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qx2t5x8ce6wvdc5t9ax04rf2ruudd84f6lmaysq',
|
||||
path: "m/84'/1'/1'/1/17",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qrcdafxz8wtjlxcryzddulrqe2mtgjz38t8s9ha',
|
||||
path: "m/84'/1'/1'/1/18",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qvw8wmaz2qvfkcuz9fm7dyy4yzuy6evle7z8uaj',
|
||||
path: "m/84'/1'/1'/1/19",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qnt0rdkhrzd5550ca57ja0zjxr9uq57ydpm3tzw',
|
||||
path: "m/84'/1'/1'/1/20",
|
||||
transfers: 0,
|
||||
},
|
||||
],
|
||||
used: [
|
||||
{
|
||||
address: 'bcrt1q7r9yvcdgcl6wmtta58yxf29a8kc96jkyyk8fsw',
|
||||
path: "m/84'/1'/1'/0/0",
|
||||
transfers: 2,
|
||||
balance: '0',
|
||||
sent: '900000000',
|
||||
received: '900000000',
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qq80deypyenykvjm6sws5522937u344vuhjk4qq',
|
||||
path: "m/84'/1'/1'/0/1",
|
||||
transfers: 2,
|
||||
balance: '0',
|
||||
sent: '900000000',
|
||||
received: '900000000',
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q6p7we05ktaksrp9c3m0rgnheqstdaljdx9gjaf',
|
||||
path: "m/84'/1'/1'/0/2",
|
||||
transfers: 1,
|
||||
balance: '1700000000',
|
||||
sent: '0',
|
||||
received: '1700000000',
|
||||
},
|
||||
],
|
||||
unused: [
|
||||
{
|
||||
address: 'bcrt1qs3krye0f3hhknsf9wudy82zkmp5j35rs9wjg33',
|
||||
path: "m/84'/1'/1'/0/3",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qpdq7f5vv90ydwjjzc0r5z5c6yp7qhrj4r8egfy',
|
||||
path: "m/84'/1'/1'/0/4",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qlksrfcwqlzlphpdsglh2cj00efayz2nh846v6x',
|
||||
path: "m/84'/1'/1'/0/5",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1ql47490ve5j98wltlar03a25v4lupjgqhrg4dp8',
|
||||
path: "m/84'/1'/1'/0/6",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1q87dfkaegfr3aqqda2t5kr3a04pah67gckx5stl',
|
||||
path: "m/84'/1'/1'/0/7",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qtusttyvgpaaneh2c78fqejm48g9j95sux0a9rz',
|
||||
path: "m/84'/1'/1'/0/8",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qanwed8uyhlm33hya47ps6kv9sl6kuh45hdt6m6',
|
||||
path: "m/84'/1'/1'/0/9",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qcmrfzuenh02ntrv28t0acm4mwc23u0lan9mzdt',
|
||||
path: "m/84'/1'/1'/0/10",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qajh9yx9hwppjskfndmpcs5vdu02an0pfgvhu5m',
|
||||
path: "m/84'/1'/1'/0/11",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qswtgqxygvj8kqfagqrj45lnjutuzec4qz2js27',
|
||||
path: "m/84'/1'/1'/0/12",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qg0n0mwxg5frrrzqaclgzur6qkc4q8my64wu09g',
|
||||
path: "m/84'/1'/1'/0/13",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qcm66dfrtjnpg7vte7pwnt45jvct4jmckjth8yk',
|
||||
path: "m/84'/1'/1'/0/14",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qvgntsus4syjj9zehr7240l90ese76kwfg5rkt3',
|
||||
path: "m/84'/1'/1'/0/15",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qvcxpmklkjjn7f4rpuqf92tvtk4mlllgke4hurp',
|
||||
path: "m/84'/1'/1'/0/16",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qa464t8hqjk86f2z0xt2v064jut4w8zstdvmpfp',
|
||||
path: "m/84'/1'/1'/0/17",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qaxhydk5qcaj3ctqy0uktc85e534lzqqvz97v3n',
|
||||
path: "m/84'/1'/1'/0/18",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qcwcue88vje7k6cz0xcdm6wkrkxv06ask6gqeah',
|
||||
path: "m/84'/1'/1'/0/19",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qlvfg066zcyvp0l5mn9sf8p62j9lsyzm8ur4s05',
|
||||
path: "m/84'/1'/1'/0/20",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qn9czsla64h9dq3mtqmwwhznwsvq3892hj7gkg0',
|
||||
path: "m/84'/1'/1'/0/21",
|
||||
transfers: 0,
|
||||
},
|
||||
{
|
||||
address: 'bcrt1qtg5atnpz4mh3e9px2a8jlqu0j66jql26vf0lr2',
|
||||
path: "m/84'/1'/1'/0/22",
|
||||
transfers: 0,
|
||||
},
|
||||
],
|
||||
},
|
||||
utxo: [
|
||||
{
|
||||
txid: '46c84bcd1ef55ea64dab2853e577dffb26f31022fbf49c18981f2c186a3a2d80(chainSpendingReceivedCoins)',
|
||||
vout: 0,
|
||||
amount: '99997910',
|
||||
blockHeight: 153,
|
||||
address: 'bcrt1q757q50q0mgt3xkqfneflvutpyktxv3x3jfupg8',
|
||||
path: "m/84'/1'/1'/1/0",
|
||||
confirmations: 1,
|
||||
},
|
||||
{
|
||||
txid: '46c84bcd1ef55ea64dab2853e577dffb26f31022fbf49c18981f2c186a3a2d80(chainSpendingReceivedCoins)',
|
||||
vout: 1,
|
||||
amount: '1700000000',
|
||||
blockHeight: 153,
|
||||
address: 'bcrt1q6p7we05ktaksrp9c3m0rgnheqstdaljdx9gjaf',
|
||||
path: "m/84'/1'/1'/0/2",
|
||||
confirmations: 1,
|
||||
},
|
||||
],
|
||||
history: { total: 2, unconfirmed: 0, addrTxCount: 6 },
|
||||
metadata: {
|
||||
'1': {
|
||||
fileName: '803c346fae1cac3580afdf34c480d0691b57bce10f4fccf671ecbf902c9c7b20.mtdt',
|
||||
aesKey: '29ed09b52c608ebcc162d3e83e51ac788e3a580937d66f42b34cb8e9e74b997b',
|
||||
},
|
||||
key: 'tpubDCZB6sR48s4T6xoXqaYxScvf23kmQvg5QpyFkYnDBjsmviKHLSG9s6cp593Exg87tuMjXXMWDvBRXnJtzppcQf8Z8HdJP1rothfxm4qnPXo',
|
||||
},
|
||||
networkType: 'bitcoin',
|
||||
page: { index: 1, size: 25, total: 1 },
|
||||
};
|
||||
|
||||
export const moveLabelsForRbfAccountsFixture: AccountsRootState['wallet']['accounts'] = [
|
||||
accountSpendingCoins,
|
||||
accountReceivingCoins,
|
||||
];
|
||||
@@ -0,0 +1,49 @@
|
||||
import { MetadataState } from '@suite-common/metadata-types';
|
||||
import {
|
||||
originalTransactionSpendAccount,
|
||||
chainSpendingReceivedCoins,
|
||||
} from './moveLabelsForRbfTransactions.fixture';
|
||||
|
||||
export const moveLabelsForRbfMetadataStateFixture: MetadataState = {
|
||||
enabled: true,
|
||||
initiating: false,
|
||||
providers: [
|
||||
{
|
||||
type: 'inMemoryTest',
|
||||
isCloud: false,
|
||||
tokens: {},
|
||||
user: '',
|
||||
clientId: '',
|
||||
data: {
|
||||
'7061500d8482d422b07cbd59784db51ae60f72a5c25f47d3d344888585e0c37d.mtdt': {
|
||||
accountLabel: '',
|
||||
outputLabels: {
|
||||
[originalTransactionSpendAccount.txid]: {
|
||||
'1': '1A',
|
||||
'2': '1B',
|
||||
},
|
||||
},
|
||||
addressLabels: {},
|
||||
},
|
||||
'803c346fae1cac3580afdf34c480d0691b57bce10f4fccf671ecbf902c9c7b20.mtdt': {
|
||||
accountLabel: '',
|
||||
outputLabels: {
|
||||
[originalTransactionSpendAccount.txid]: {
|
||||
'1': '2A',
|
||||
'2': '2B',
|
||||
},
|
||||
[chainSpendingReceivedCoins.txid]: {
|
||||
'1': '2C',
|
||||
},
|
||||
},
|
||||
addressLabels: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
selectedProvider: {
|
||||
labels: '',
|
||||
passwords: '',
|
||||
},
|
||||
error: {},
|
||||
};
|
||||
@@ -0,0 +1,267 @@
|
||||
import { TransactionsRootState } from '@suite-common/wallet-core';
|
||||
import { WalletAccountTransaction } from '@suite-common/wallet-types';
|
||||
import { accountReceivingCoins, accountSpendingCoins } from './moveLabelsForRbfAccounts.fixture';
|
||||
|
||||
export const originalTransactionSpendAccount: WalletAccountTransaction = {
|
||||
descriptor: accountSpendingCoins.descriptor,
|
||||
deviceState: 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q@AC94BB9C1B08FE73BE1E3322:0',
|
||||
symbol: 'regtest',
|
||||
type: 'sent',
|
||||
txid: '4ec6d03abb2e3e52a50301ee353621cbda13d7a6cb57bc8f373519af5b25026b(originalTransaction)',
|
||||
blockTime: 1702460477,
|
||||
blockHeight: undefined,
|
||||
blockHash: '2aa61579eee0e8a8263361c63c1632281a0b88af496fa9d1ff50380aa7931bc9',
|
||||
amount: '1800000000',
|
||||
fee: '6890',
|
||||
vsize: 240,
|
||||
feeRate: '28.71',
|
||||
targets: [
|
||||
{
|
||||
n: 1,
|
||||
addresses: ['bcrt1qq80deypyenykvjm6sws5522937u344vuhjk4qq'],
|
||||
isAddress: true,
|
||||
amount: '900000000',
|
||||
},
|
||||
{
|
||||
n: 2,
|
||||
addresses: ['bcrt1q7r9yvcdgcl6wmtta58yxf29a8kc96jkyyk8fsw'],
|
||||
isAddress: true,
|
||||
amount: '900000000',
|
||||
},
|
||||
],
|
||||
tokens: [],
|
||||
internalTransfers: [],
|
||||
rbf: true,
|
||||
details: {
|
||||
vin: [
|
||||
{
|
||||
txid: '17b3aa686f4da9b5e12cdb556d277fe407fb4b3be7c571c527a53309824f76f7',
|
||||
sequence: 4294967293,
|
||||
n: 0,
|
||||
addresses: ['bcrt1qldlynaqp0hy4zc2aag3pkenzvxy65saej0huey'],
|
||||
isAddress: true,
|
||||
isOwn: true,
|
||||
value: '1000000000',
|
||||
isAccountOwned: true,
|
||||
},
|
||||
{
|
||||
txid: '1f10a72efb295d2161800fce9ae6496dfa23f1f08f816a76b4dcae34102f88f2',
|
||||
vout: 1,
|
||||
sequence: 4294967293,
|
||||
n: 1,
|
||||
addresses: ['bcrt1qkvwu9g3k2pdxewfqr7syz89r3gj557l374sg5v'],
|
||||
isAddress: true,
|
||||
isOwn: true,
|
||||
value: '1000000000',
|
||||
isAccountOwned: true,
|
||||
},
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: '199993110',
|
||||
n: 0,
|
||||
hex: '0014cc8067093f6f843d6d3e22004a4290cd0c0f336b',
|
||||
addresses: ['bcrt1qejqxwzfld7zr6mf7ygqy5s5se5xq7vmt8ntmj0'],
|
||||
isAddress: true,
|
||||
isOwn: true,
|
||||
isAccountOwned: true,
|
||||
},
|
||||
{
|
||||
value: '900000000',
|
||||
n: 1,
|
||||
spent: true,
|
||||
hex: '001401dedc9024ccc9664b7a83a14a29458fb91ad59c',
|
||||
addresses: ['bcrt1qq80deypyenykvjm6sws5522937u344vuhjk4qq'],
|
||||
isAddress: true,
|
||||
},
|
||||
{
|
||||
value: '900000000',
|
||||
n: 2,
|
||||
spent: true,
|
||||
hex: '0014f0ca4661a8c7f4edad7da1c864a8bd3db05d4ac4',
|
||||
addresses: ['bcrt1q7r9yvcdgcl6wmtta58yxf29a8kc96jkyyk8fsw'],
|
||||
isAddress: true,
|
||||
},
|
||||
],
|
||||
size: 402,
|
||||
totalInput: '2000000000',
|
||||
totalOutput: '1999993110',
|
||||
},
|
||||
};
|
||||
|
||||
export const transactionSendingCoinsReplacement: WalletAccountTransaction = {
|
||||
...originalTransactionSpendAccount,
|
||||
txid: 'fd763c2bdf671f896a83b95d46a66c886812e1908abbf68540bb218be818868d(replacementTransaction)',
|
||||
};
|
||||
|
||||
export const originalTransactionReceivingAccount: WalletAccountTransaction = {
|
||||
descriptor: accountReceivingCoins.descriptor,
|
||||
deviceState: 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q@AC94BB9C1B08FE73BE1E3322:0',
|
||||
symbol: 'regtest',
|
||||
type: 'recv',
|
||||
txid: '4ec6d03abb2e3e52a50301ee353621cbda13d7a6cb57bc8f373519af5b25026b(originalTransaction)',
|
||||
blockTime: 1702460477,
|
||||
blockHeight: undefined,
|
||||
blockHash: '2aa61579eee0e8a8263361c63c1632281a0b88af496fa9d1ff50380aa7931bc9',
|
||||
amount: '1800000000',
|
||||
fee: '6890',
|
||||
vsize: 240,
|
||||
feeRate: '28.71',
|
||||
targets: [
|
||||
{
|
||||
n: 1,
|
||||
addresses: ['bcrt1qq80deypyenykvjm6sws5522937u344vuhjk4qq'],
|
||||
isAddress: true,
|
||||
amount: '900000000',
|
||||
isAccountTarget: true,
|
||||
},
|
||||
{
|
||||
n: 2,
|
||||
addresses: ['bcrt1q7r9yvcdgcl6wmtta58yxf29a8kc96jkyyk8fsw'],
|
||||
isAddress: true,
|
||||
amount: '900000000',
|
||||
isAccountTarget: true,
|
||||
},
|
||||
],
|
||||
tokens: [],
|
||||
internalTransfers: [],
|
||||
rbf: true,
|
||||
details: {
|
||||
vin: [
|
||||
{
|
||||
txid: '17b3aa686f4da9b5e12cdb556d277fe407fb4b3be7c571c527a53309824f76f7',
|
||||
sequence: 4294967293,
|
||||
n: 0,
|
||||
addresses: ['bcrt1qldlynaqp0hy4zc2aag3pkenzvxy65saej0huey'],
|
||||
isAddress: true,
|
||||
value: '1000000000',
|
||||
},
|
||||
{
|
||||
txid: '1f10a72efb295d2161800fce9ae6496dfa23f1f08f816a76b4dcae34102f88f2',
|
||||
vout: 1,
|
||||
sequence: 4294967293,
|
||||
n: 1,
|
||||
addresses: ['bcrt1qkvwu9g3k2pdxewfqr7syz89r3gj557l374sg5v'],
|
||||
isAddress: true,
|
||||
value: '1000000000',
|
||||
},
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: '199993110',
|
||||
n: 0,
|
||||
hex: '0014cc8067093f6f843d6d3e22004a4290cd0c0f336b',
|
||||
addresses: ['bcrt1qejqxwzfld7zr6mf7ygqy5s5se5xq7vmt8ntmj0'],
|
||||
isAddress: true,
|
||||
},
|
||||
{
|
||||
value: '900000000',
|
||||
n: 1,
|
||||
spent: true,
|
||||
hex: '001401dedc9024ccc9664b7a83a14a29458fb91ad59c',
|
||||
addresses: ['bcrt1qq80deypyenykvjm6sws5522937u344vuhjk4qq'],
|
||||
isAddress: true,
|
||||
isOwn: true,
|
||||
isAccountOwned: true,
|
||||
},
|
||||
{
|
||||
value: '900000000',
|
||||
n: 2,
|
||||
spent: true,
|
||||
hex: '0014f0ca4661a8c7f4edad7da1c864a8bd3db05d4ac4',
|
||||
addresses: ['bcrt1q7r9yvcdgcl6wmtta58yxf29a8kc96jkyyk8fsw'],
|
||||
isAddress: true,
|
||||
isOwn: true,
|
||||
isAccountOwned: true,
|
||||
},
|
||||
],
|
||||
size: 402,
|
||||
totalInput: '2000000000',
|
||||
totalOutput: '1999993110',
|
||||
},
|
||||
};
|
||||
|
||||
export const chainSpendingReceivedCoins: WalletAccountTransaction = {
|
||||
descriptor: accountReceivingCoins.descriptor,
|
||||
deviceState: 'mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q@AC94BB9C1B08FE73BE1E3322:0',
|
||||
symbol: 'regtest',
|
||||
type: 'self',
|
||||
txid: '46c84bcd1ef55ea64dab2853e577dffb26f31022fbf49c18981f2c186a3a2d80(chainSpendingReceivedCoins)',
|
||||
blockTime: 1702460477,
|
||||
blockHeight: undefined,
|
||||
blockHash: '2aa61579eee0e8a8263361c63c1632281a0b88af496fa9d1ff50380aa7931bc9',
|
||||
amount: '2090',
|
||||
fee: '2090',
|
||||
vsize: 209,
|
||||
feeRate: '10',
|
||||
targets: [
|
||||
{
|
||||
n: 1,
|
||||
addresses: ['bcrt1q6p7we05ktaksrp9c3m0rgnheqstdaljdx9gjaf'],
|
||||
isAddress: true,
|
||||
amount: '1700000000',
|
||||
isAccountTarget: true,
|
||||
},
|
||||
],
|
||||
tokens: [],
|
||||
internalTransfers: [],
|
||||
rbf: true,
|
||||
details: {
|
||||
vin: [
|
||||
{
|
||||
txid: '4ec6d03abb2e3e52a50301ee353621cbda13d7a6cb57bc8f373519af5b25026b(originalTransaction)',
|
||||
vout: 1,
|
||||
sequence: 4294967293,
|
||||
n: 0,
|
||||
addresses: ['bcrt1qq80deypyenykvjm6sws5522937u344vuhjk4qq'],
|
||||
isAddress: true,
|
||||
isOwn: true,
|
||||
value: '900000000',
|
||||
isAccountOwned: true,
|
||||
},
|
||||
{
|
||||
txid: '4ec6d03abb2e3e52a50301ee353621cbda13d7a6cb57bc8f373519af5b25026b(originalTransaction)',
|
||||
vout: 2,
|
||||
sequence: 4294967293,
|
||||
n: 1,
|
||||
addresses: ['bcrt1q7r9yvcdgcl6wmtta58yxf29a8kc96jkyyk8fsw'],
|
||||
isAddress: true,
|
||||
isOwn: true,
|
||||
value: '900000000',
|
||||
isAccountOwned: true,
|
||||
},
|
||||
],
|
||||
vout: [
|
||||
{
|
||||
value: '99997910',
|
||||
n: 0,
|
||||
hex: '0014f53c0a3c0fda171358099e53f6716125966644d1',
|
||||
addresses: ['bcrt1q757q50q0mgt3xkqfneflvutpyktxv3x3jfupg8'],
|
||||
isAddress: true,
|
||||
isOwn: true,
|
||||
isAccountOwned: true,
|
||||
},
|
||||
{
|
||||
value: '1700000000',
|
||||
n: 1,
|
||||
hex: '0014d07cecbe965f6d0184b88ede344ef90416defe4d',
|
||||
addresses: ['bcrt1q6p7we05ktaksrp9c3m0rgnheqstdaljdx9gjaf'],
|
||||
isAddress: true,
|
||||
isOwn: true,
|
||||
isAccountOwned: true,
|
||||
},
|
||||
],
|
||||
size: 372,
|
||||
totalInput: '1800000000',
|
||||
totalOutput: '1799997910',
|
||||
},
|
||||
};
|
||||
|
||||
export const moveLabelsForRbfTransactionsFixture: TransactionsRootState['wallet']['transactions']['transactions'] =
|
||||
{
|
||||
[accountSpendingCoins.key]: [originalTransactionSpendAccount],
|
||||
[accountReceivingCoins.key]: [
|
||||
originalTransactionReceivingAccount,
|
||||
chainSpendingReceivedCoins,
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,105 @@
|
||||
import { combineReducers } from '@reduxjs/toolkit';
|
||||
import { accountsReducer, transactionsReducer } from '../../../reducers/wallet';
|
||||
import { configureMockStore, initPreloadedState } from '@suite-common/test-utils';
|
||||
import { findLabelsToBeMovedOrDeleted, moveLabelsForRbfAction } from '../moveLabelsForRbfActions';
|
||||
import {
|
||||
accountReceivingCoins,
|
||||
accountSpendingCoins,
|
||||
moveLabelsForRbfAccountsFixture,
|
||||
} from '../__fixtures__/moveLabelsForRbf/moveLabelsForRbfAccounts.fixture';
|
||||
import {
|
||||
moveLabelsForRbfTransactionsFixture,
|
||||
originalTransactionSpendAccount,
|
||||
transactionSendingCoinsReplacement,
|
||||
} from '../__fixtures__/moveLabelsForRbf/moveLabelsForRbfTransactions.fixture';
|
||||
import metadataReducer, {
|
||||
selectLabelingDataForAccount,
|
||||
} from '../../../reducers/suite/metadataReducer';
|
||||
import { moveLabelsForRbfMetadataStateFixture } from '../__fixtures__/moveLabelsForRbf/moveLabelsForRbfMetadataState.fixture';
|
||||
import suiteReducer from '../../../reducers/suite/suiteReducer';
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
wallet: combineReducers({
|
||||
accounts: accountsReducer,
|
||||
transactions: transactionsReducer,
|
||||
}),
|
||||
metadata: metadataReducer,
|
||||
suite: suiteReducer,
|
||||
});
|
||||
|
||||
type TestState = ReturnType<typeof rootReducer>;
|
||||
|
||||
const initStore = ({
|
||||
wallet,
|
||||
metadata,
|
||||
}: {
|
||||
wallet: TestState['wallet'];
|
||||
metadata: TestState['metadata'];
|
||||
}) => {
|
||||
// State != suite AppState, therefore <any>
|
||||
const store = configureMockStore<any>({
|
||||
reducer: rootReducer,
|
||||
preloadedState: initPreloadedState({
|
||||
rootReducer,
|
||||
partialState: {
|
||||
wallet,
|
||||
metadata,
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
return store;
|
||||
};
|
||||
|
||||
describe(moveLabelsForRbfAction.name, () => {
|
||||
it('moves the labels onto new RBF transaction and deletes the label of the chained transaction', async () => {
|
||||
const store = initStore({
|
||||
wallet: {
|
||||
accounts: moveLabelsForRbfAccountsFixture,
|
||||
transactions: {
|
||||
isLoading: false,
|
||||
error: null,
|
||||
transactions: moveLabelsForRbfTransactionsFixture,
|
||||
},
|
||||
},
|
||||
metadata: moveLabelsForRbfMetadataStateFixture,
|
||||
});
|
||||
|
||||
const toBeMovedOrDeletedList = store.dispatch(
|
||||
findLabelsToBeMovedOrDeleted({
|
||||
prevTxid: originalTransactionSpendAccount.txid,
|
||||
}),
|
||||
);
|
||||
|
||||
await store.dispatch(
|
||||
moveLabelsForRbfAction({
|
||||
toBeMovedOrDeletedList,
|
||||
newTxid: transactionSendingCoinsReplacement.txid,
|
||||
}),
|
||||
);
|
||||
|
||||
const accountSpendingCoinsMetadata = selectLabelingDataForAccount(
|
||||
store.getState(),
|
||||
accountSpendingCoins.key,
|
||||
);
|
||||
|
||||
expect(accountSpendingCoinsMetadata.outputLabels).toStrictEqual({
|
||||
[transactionSendingCoinsReplacement.txid]: {
|
||||
'1': '1A',
|
||||
'2': '1B',
|
||||
},
|
||||
});
|
||||
|
||||
const accountReceivingCoinsMetadata = selectLabelingDataForAccount(
|
||||
store.getState(),
|
||||
accountReceivingCoins.key,
|
||||
);
|
||||
|
||||
expect(accountReceivingCoinsMetadata.outputLabels).toStrictEqual({
|
||||
[transactionSendingCoinsReplacement.txid]: {
|
||||
'1': '2A',
|
||||
'2': '2B',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
149
packages/suite/src/actions/wallet/moveLabelsForRbfActions.ts
Normal file
149
packages/suite/src/actions/wallet/moveLabelsForRbfActions.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import { selectLabelingDataForAccount } from '../../reducers/suite/metadataReducer';
|
||||
import { findChainedTransactions, findTransactions } from '@suite-common/wallet-utils';
|
||||
import { Dispatch, GetState } from 'src/types/suite';
|
||||
import * as metadataActions from 'src/actions/suite/metadataActions';
|
||||
import { AccountLabels, AccountOutputLabels } from '@suite-common/metadata-types';
|
||||
import { AccountKey, WalletAccountTransaction } from '@suite-common/wallet-types';
|
||||
|
||||
type DeleteAllOutputLabelsParams = {
|
||||
labels: AccountLabels['outputLabels']['labels'];
|
||||
dispatch: Dispatch;
|
||||
accountKey: AccountKey;
|
||||
txid: string;
|
||||
};
|
||||
|
||||
const deleteDanglingLabels = async ({
|
||||
labels,
|
||||
dispatch,
|
||||
accountKey,
|
||||
txid,
|
||||
}: DeleteAllOutputLabelsParams) => {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const outputIndex of Object.keys(labels)) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await dispatch(
|
||||
metadataActions.addMetadata({
|
||||
type: 'outputLabel',
|
||||
entityKey: accountKey,
|
||||
txid,
|
||||
outputIndex: Number(outputIndex),
|
||||
defaultValue: '',
|
||||
value: '',
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
type MoveLabelToNewTransactionParams = {
|
||||
accountOutputLabels: AccountOutputLabels;
|
||||
dispatch: Dispatch;
|
||||
accountKey: AccountKey;
|
||||
newTxid: string;
|
||||
};
|
||||
|
||||
export const copyLabelToNewTransaction = async ({
|
||||
accountOutputLabels,
|
||||
dispatch,
|
||||
accountKey,
|
||||
newTxid,
|
||||
}: MoveLabelToNewTransactionParams) => {
|
||||
// eslint-disable-next-line no-restricted-syntax,
|
||||
for (const outputIndex of Object.keys(accountOutputLabels)) {
|
||||
const value = accountOutputLabels[outputIndex];
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await dispatch(
|
||||
metadataActions.addMetadata({
|
||||
type: 'outputLabel',
|
||||
entityKey: accountKey,
|
||||
txid: newTxid,
|
||||
outputIndex: Number(outputIndex),
|
||||
defaultValue: '',
|
||||
value,
|
||||
}),
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
type FindLabelsToBeMovedOrDeletedParams = {
|
||||
prevTxid: string;
|
||||
};
|
||||
|
||||
export type LabelsToBeMovedOrDeleted = Record<
|
||||
AccountKey,
|
||||
{
|
||||
toBeMoved: WalletAccountTransaction;
|
||||
toBeDeleted: WalletAccountTransaction[];
|
||||
}
|
||||
>;
|
||||
|
||||
export const findLabelsToBeMovedOrDeleted =
|
||||
({ prevTxid }: FindLabelsToBeMovedOrDeletedParams) =>
|
||||
(_dispatch: Dispatch, getState: GetState): LabelsToBeMovedOrDeleted => {
|
||||
const accountTransactions = findTransactions(
|
||||
prevTxid,
|
||||
getState().wallet.transactions.transactions,
|
||||
);
|
||||
|
||||
return accountTransactions.reduce((result, accountTransaction) => {
|
||||
const chainedTransactionsToDrop = findChainedTransactions(
|
||||
accountTransaction.tx.descriptor,
|
||||
accountTransaction.tx.txid,
|
||||
getState().wallet.transactions.transactions,
|
||||
);
|
||||
|
||||
const allAccountsTransactionsIncludingChained: WalletAccountTransaction[] = [
|
||||
accountTransaction.tx,
|
||||
...(chainedTransactionsToDrop?.own ?? []),
|
||||
// Intentionally using `chainedTransactionsToDrop?.others`, they will be found when we query another account in the loop
|
||||
];
|
||||
|
||||
result[accountTransaction.key] = {
|
||||
toBeDeleted: allAccountsTransactionsIncludingChained,
|
||||
toBeMoved: accountTransaction.tx,
|
||||
};
|
||||
|
||||
return result;
|
||||
}, {} as LabelsToBeMovedOrDeleted);
|
||||
};
|
||||
|
||||
type MoveLabelsForRbfParams = {
|
||||
newTxid: string;
|
||||
toBeMovedOrDeletedList: LabelsToBeMovedOrDeleted;
|
||||
};
|
||||
|
||||
export const moveLabelsForRbfAction =
|
||||
({ toBeMovedOrDeletedList, newTxid }: MoveLabelsForRbfParams) =>
|
||||
async (dispatch: Dispatch, getState: GetState) => {
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const toBeMovedOrDeleted of Object.entries(toBeMovedOrDeletedList)) {
|
||||
const [accountKey, data] = toBeMovedOrDeleted;
|
||||
|
||||
const accountMetadata = selectLabelingDataForAccount(getState(), accountKey);
|
||||
const accountOutputLabelsToBeMoved: AccountOutputLabels =
|
||||
accountMetadata?.outputLabels?.[data.toBeMoved.txid] ?? {};
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await copyLabelToNewTransaction({
|
||||
accountKey,
|
||||
accountOutputLabels: accountOutputLabelsToBeMoved,
|
||||
newTxid,
|
||||
dispatch,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-restricted-syntax
|
||||
for (const transactionToDrop of data.toBeDeleted) {
|
||||
const accountOutputLabelsToBeDeleted: AccountOutputLabels =
|
||||
accountMetadata?.outputLabels?.[transactionToDrop.txid] ?? {};
|
||||
|
||||
const deleteParams: DeleteAllOutputLabelsParams = {
|
||||
accountKey,
|
||||
dispatch,
|
||||
labels: accountOutputLabelsToBeDeleted,
|
||||
txid: transactionToDrop.txid,
|
||||
};
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await deleteDanglingLabels(deleteParams);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -26,7 +26,7 @@ import {
|
||||
PrecomposedTransactionFinal,
|
||||
PrecomposedTransactionFinalCardano,
|
||||
} from '@suite-common/wallet-types';
|
||||
import { cloneObject } from '@trezor/utils';
|
||||
import { cloneObject, getSynchronize } from '@trezor/utils';
|
||||
|
||||
import * as modalActions from 'src/actions/suite/modalActions';
|
||||
import * as metadataActions from 'src/actions/suite/metadataActions';
|
||||
@@ -40,6 +40,7 @@ import * as sendFormEthereumActions from './send/sendFormEthereumActions';
|
||||
import * as sendFormRippleActions from './send/sendFormRippleActions';
|
||||
import * as sendFormSolanaActions from './send/sendFormSolanaActions';
|
||||
import * as sendFormCardanoActions from './send/sendFormCardanoActions';
|
||||
import { findLabelsToBeMovedOrDeleted, moveLabelsForRbfAction } from './moveLabelsForRbfActions';
|
||||
|
||||
export type SendFormAction =
|
||||
| {
|
||||
@@ -213,6 +214,12 @@ const pushTransaction =
|
||||
const device = selectDevice(getState());
|
||||
if (!signedTx || !precomposedTx || !account) return;
|
||||
|
||||
const isRbf = precomposedTx.prevTxid !== undefined;
|
||||
|
||||
const toBeMovedOrDeletedList = isRbf
|
||||
? dispatch(findLabelsToBeMovedOrDeleted({ prevTxid: precomposedTx.prevTxid }))
|
||||
: undefined;
|
||||
|
||||
const sentTx = await TrezorConnect.pushTransaction(signedTx);
|
||||
// const sentTx = { success: true, payload: { txid: 'ABC ' } };
|
||||
|
||||
@@ -250,7 +257,16 @@ const pushTransaction =
|
||||
}),
|
||||
);
|
||||
|
||||
if (precomposedTx.prevTxid) {
|
||||
if (isRbf) {
|
||||
if (toBeMovedOrDeletedList !== undefined) {
|
||||
await dispatch(
|
||||
moveLabelsForRbfAction({
|
||||
toBeMovedOrDeletedList,
|
||||
newTxid: txid,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
// notification from the backend may be delayed.
|
||||
// modify affected transaction(s) in the reducer until the real account update occurs.
|
||||
// this will update transaction details (like time, fee etc.)
|
||||
@@ -317,6 +333,8 @@ const pushTransaction =
|
||||
outputsPermutation = precomposedTx?.outputsPermutation;
|
||||
}
|
||||
|
||||
const synchronize = getSynchronize();
|
||||
|
||||
precomposedForm?.outputs
|
||||
// create array of metadata objects
|
||||
.map((formOutput, index) => {
|
||||
@@ -340,7 +358,10 @@ const pushTransaction =
|
||||
// propagate metadata to reducers and persistent storage
|
||||
.forEach((output, index, arr) => {
|
||||
const isLast = index === arr.length - 1;
|
||||
dispatch(metadataActions.addAccountMetadata(output, isLast));
|
||||
|
||||
synchronize(() =>
|
||||
dispatch(metadataActions.addAccountMetadata(output, isLast)),
|
||||
);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
} from 'src/actions/suite/constants/metadataConstants';
|
||||
|
||||
import { SuiteRootState } from './suiteReducer';
|
||||
import { AccountKey } from '@suite-common/wallet-types';
|
||||
|
||||
export const initialState: MetadataState = {
|
||||
// is Suite trying to load metadata (get master key -> sync cloud)?
|
||||
@@ -141,7 +142,7 @@ export const selectLabelingDataForSelectedAccount = (state: {
|
||||
*/
|
||||
export const selectLabelingDataForAccount = (
|
||||
state: { metadata: MetadataState; wallet: { accounts: Account[] } },
|
||||
accountKey: string,
|
||||
accountKey: AccountKey,
|
||||
) => {
|
||||
const provider = selectSelectedProviderForLabels(state);
|
||||
const account = selectAccountByKey(state, accountKey);
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import { AbstractMetadataProvider } from 'src/types/suite/metadata';
|
||||
|
||||
export class InMemoryTestProvider extends AbstractMetadataProvider {
|
||||
#files: Record<string, string> = {};
|
||||
|
||||
isCloud = false;
|
||||
constructor() {
|
||||
super('inMemoryTest');
|
||||
}
|
||||
|
||||
get clientId() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
connect() {
|
||||
return Promise.resolve(this.ok());
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
return Promise.resolve(this.ok());
|
||||
}
|
||||
|
||||
// eslint-disable-next-line
|
||||
async getProviderDetails() {
|
||||
return this.ok({
|
||||
type: this.type,
|
||||
isCloud: this.isCloud,
|
||||
tokens: {},
|
||||
user: '',
|
||||
clientId: this.clientId,
|
||||
});
|
||||
}
|
||||
|
||||
getFileContent(file: string) {
|
||||
return Promise.resolve(this.ok(Buffer.from(this.#files[file], 'hex')));
|
||||
}
|
||||
|
||||
setFileContent(file: string, content: Buffer) {
|
||||
this.#files[file] = content.toString('hex');
|
||||
|
||||
return Promise.resolve(this.ok(undefined));
|
||||
}
|
||||
|
||||
getFilesList() {
|
||||
return Promise.resolve(this.ok(Object.keys(this.#files)));
|
||||
}
|
||||
|
||||
renameFile(from: string, to: string) {
|
||||
this.#files[to] = this.#files[from];
|
||||
delete this.#files[from];
|
||||
|
||||
return Promise.resolve(this.ok(undefined));
|
||||
}
|
||||
|
||||
isConnected() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -26,3 +26,5 @@ export const getSynchronize = () => {
|
||||
return lock;
|
||||
};
|
||||
};
|
||||
|
||||
export type Synchronize = ReturnType<typeof getSynchronize>;
|
||||
|
||||
@@ -50,7 +50,7 @@ export type MetadataAddPayload =
|
||||
// }
|
||||
export type MetadataItem = string;
|
||||
|
||||
export type MetadataProviderType = 'dropbox' | 'google' | 'fileSystem' | 'sdCard';
|
||||
export type MetadataProviderType = 'dropbox' | 'google' | 'fileSystem' | 'inMemoryTest'; // Todo: | 'sdCard'
|
||||
|
||||
export type Tokens = {
|
||||
accessToken?: string;
|
||||
@@ -176,9 +176,11 @@ export abstract class AbstractMetadataProvider {
|
||||
}
|
||||
}
|
||||
|
||||
export type AccountOutputLabels = { [index: string]: MetadataItem };
|
||||
|
||||
export interface AccountLabels {
|
||||
accountLabel?: MetadataItem;
|
||||
outputLabels: { [txid: string]: { [index: string]: MetadataItem } };
|
||||
outputLabels: { [txid: string]: AccountOutputLabels };
|
||||
addressLabels: { [address: string]: MetadataItem };
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
WalletAccountTransaction,
|
||||
ChainedTransactions,
|
||||
PrecomposedTransactionFinal,
|
||||
AccountKey,
|
||||
} from '@suite-common/wallet-types';
|
||||
import {
|
||||
AccountAddress,
|
||||
@@ -254,14 +255,14 @@ export const findTransactions = (
|
||||
export const findChainedTransactions = (
|
||||
descriptor: string,
|
||||
txid: string,
|
||||
transactions: Record<string, WalletAccountTransaction[]>,
|
||||
transactions: Record<AccountKey, WalletAccountTransaction[]>,
|
||||
result: ChainedTransactions = { own: [], others: [] },
|
||||
) => {
|
||||
Object.keys(transactions).forEach(key => {
|
||||
Object.keys(transactions).forEach(accountKey => {
|
||||
const ownTxs = result.own.map(tx => tx.txid);
|
||||
const othersTxs = result.others.map(tx => tx.txid);
|
||||
// check if any pending transaction is using the utxo/vin with requested txid
|
||||
const txs = transactions[key].filter(tx => {
|
||||
const txs = transactions[accountKey].filter(tx => {
|
||||
if (!isPending(tx) || !tx.details.vin.find(i => i.txid === txid)) {
|
||||
return false;
|
||||
}
|
||||
@@ -273,10 +274,12 @@ export const findChainedTransactions = (
|
||||
result.own.push(tx);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!ownTxs.includes(tx.txid) && !othersTxs.includes(tx.txid)) {
|
||||
result.others.push(tx);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user