Merge branch 'master' into renovate/react-native-permissions-5.x
This commit is contained in:
commit
a50b50496f
10
.github/workflows/e2e-ios.yml
vendored
10
.github/workflows/e2e-ios.yml
vendored
@ -194,9 +194,6 @@ jobs:
|
||||
mkdir -p ios/build/Build/Products/Release-iphonesimulator
|
||||
tar -xzf BlueWallet.app.tar.gz -C ios/build/Build/Products/Release-iphonesimulator
|
||||
|
||||
- name: Disable simulator animations
|
||||
run: defaults write com.apple.iphonesimulator SlowMotionAnimation -bool NO
|
||||
|
||||
# Pre-boot simulator so first detox launchApp lands warm.
|
||||
- name: Pre-boot iOS simulator
|
||||
run: |
|
||||
@ -210,6 +207,13 @@ jobs:
|
||||
xcrun simctl bootstatus "$UDID" -b
|
||||
xcrun simctl launch "$UDID" com.apple.springboard >/dev/null 2>&1 || true
|
||||
|
||||
# Cut animations so detox sync stays steady on slow CI VMs; Reduce Motion makes reanimated skip to final value.
|
||||
- name: Disable simulator animations
|
||||
run: |
|
||||
defaults write com.apple.iphonesimulator SlowMotionAnimation -bool NO
|
||||
xcrun simctl spawn booted defaults write com.apple.Accessibility ReduceMotionEnabled -bool true
|
||||
xcrun simctl spawn booted notifyutil -p com.apple.Accessibility.ReduceMotionStatusDidChange
|
||||
|
||||
- name: Run detox tests
|
||||
timeout-minutes: 360
|
||||
run: |
|
||||
|
||||
@ -147,11 +147,10 @@ export class BlueApp {
|
||||
console.warn('error reading', key, error.message);
|
||||
console.warn('fallback to realm');
|
||||
const realmKeyValue = await this.openRealmKeyValue();
|
||||
const obj = realmKeyValue.objectForPrimaryKey('KeyValue', key); // search for a realm object with a primary key
|
||||
const obj = realmKeyValue.objectForPrimaryKey<{ key: string; value: string }>('KeyValue', key);
|
||||
value = obj?.value;
|
||||
realmKeyValue.close();
|
||||
if (value) {
|
||||
// @ts-ignore value.length
|
||||
console.warn('successfully recovered', value.length, 'bytes from realm for key', key);
|
||||
return value;
|
||||
}
|
||||
@ -547,10 +546,11 @@ export class BlueApp {
|
||||
(walletToInflate._txs_by_internal_index[tx.index] as Transaction[]).push(transaction);
|
||||
}
|
||||
} else {
|
||||
if (!Array.isArray(walletToInflate._txs_by_external_index)) walletToInflate._txs_by_external_index = [];
|
||||
walletToInflate._txs_by_external_index = walletToInflate._txs_by_external_index || [];
|
||||
// Legacy single-address wallets - store under index 0
|
||||
walletToInflate._txs_by_external_index = walletToInflate._txs_by_external_index || {};
|
||||
walletToInflate._txs_by_external_index[0] = walletToInflate._txs_by_external_index[0] || [];
|
||||
const transaction = JSON.parse(tx.tx);
|
||||
(walletToInflate._txs_by_external_index as Transaction[]).push(transaction);
|
||||
walletToInflate._txs_by_external_index[0].push(transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -559,32 +559,6 @@ export class BlueApp {
|
||||
const id = wallet.getID();
|
||||
const walletToSave = ('_hdWalletInstance' in wallet && wallet._hdWalletInstance) || wallet;
|
||||
|
||||
if (Array.isArray(walletToSave._txs_by_external_index)) {
|
||||
// if this var is an array that means its a single-address wallet class, and this var is a flat array
|
||||
// with transactions
|
||||
realm.write(() => {
|
||||
// cleanup all existing transactions for the wallet first
|
||||
const walletTransactionsToDelete = realm.objects('WalletTransactions').filtered(`walletid = '${id}'`);
|
||||
realm.delete(walletTransactionsToDelete);
|
||||
|
||||
// @ts-ignore walletToSave._txs_by_external_index is array
|
||||
for (const tx of walletToSave._txs_by_external_index) {
|
||||
realm.create(
|
||||
'WalletTransactions',
|
||||
{
|
||||
walletid: id,
|
||||
tx: JSON.stringify(tx),
|
||||
},
|
||||
Realm.UpdateMode.Modified,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/// ########################################################################################################
|
||||
|
||||
if (walletToSave._txs_by_external_index) {
|
||||
realm.write(() => {
|
||||
// cleanup all existing transactions for the wallet first
|
||||
@ -592,16 +566,14 @@ export class BlueApp {
|
||||
realm.delete(walletTransactionsToDelete);
|
||||
|
||||
// insert new ones:
|
||||
for (const index of Object.keys(walletToSave._txs_by_external_index)) {
|
||||
// @ts-ignore index is number
|
||||
const txs = walletToSave._txs_by_external_index[index];
|
||||
for (const [indexStr, txs] of Object.entries(walletToSave._txs_by_external_index)) {
|
||||
for (const tx of txs) {
|
||||
realm.create(
|
||||
'WalletTransactions',
|
||||
{
|
||||
walletid: id,
|
||||
internal: false,
|
||||
index: parseInt(index, 10),
|
||||
index: parseInt(indexStr, 10),
|
||||
tx: JSON.stringify(tx),
|
||||
},
|
||||
Realm.UpdateMode.Modified,
|
||||
@ -609,16 +581,14 @@ export class BlueApp {
|
||||
}
|
||||
}
|
||||
|
||||
for (const index of Object.keys(walletToSave._txs_by_internal_index)) {
|
||||
// @ts-ignore index is number
|
||||
const txs = walletToSave._txs_by_internal_index[index];
|
||||
for (const [indexStr, txs] of Object.entries(walletToSave._txs_by_internal_index)) {
|
||||
for (const tx of txs) {
|
||||
realm.create(
|
||||
'WalletTransactions',
|
||||
{
|
||||
walletid: id,
|
||||
internal: true,
|
||||
index: parseInt(index, 10),
|
||||
index: parseInt(indexStr, 10),
|
||||
tx: JSON.stringify(tx),
|
||||
},
|
||||
Realm.UpdateMode.Modified,
|
||||
|
||||
@ -390,7 +390,7 @@ export class HDSegwitBech32Transaction {
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore stfu
|
||||
return { tx, inputs, outputs, fee };
|
||||
// Non-null assertions are safe here because the while loop always runs at least once (add starts at 0)
|
||||
return { tx: tx!, inputs: inputs!, outputs: outputs!, fee: fee! };
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
* @return {Promise.<Uint8Array>} The random bytes
|
||||
*/
|
||||
export async function randomBytes(size: number): Promise<Uint8Array> {
|
||||
const g: any = globalThis as any;
|
||||
const g = globalThis as any;
|
||||
const rnCrypto = g && g.crypto;
|
||||
if (!rnCrypto || typeof rnCrypto.getRandomValues !== 'function') {
|
||||
throw new Error('crypto.getRandomValues is not available');
|
||||
|
||||
@ -45,9 +45,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||
_balances_by_external_index: Record<number, BalanceByIndex>;
|
||||
_balances_by_internal_index: Record<number, BalanceByIndex>;
|
||||
|
||||
// @ts-ignore
|
||||
_txs_by_external_index: Record<number, Transaction[]>;
|
||||
// @ts-ignore
|
||||
_txs_by_internal_index: Record<number, Transaction[]>;
|
||||
|
||||
_utxo: any[];
|
||||
@ -204,70 +202,37 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||
return child.toWIF();
|
||||
}
|
||||
|
||||
_getNodeAddressByIndex(node: number, index: number): string {
|
||||
index = index * 1; // cast to int
|
||||
_getNodeByIndex(node: 0 | 1, index: number): BIP32Interface {
|
||||
const cachedNode = node === 0 ? this._node0 : this._node1;
|
||||
if (cachedNode) {
|
||||
return cachedNode.derive(index);
|
||||
}
|
||||
|
||||
const xpub = this._zpubToXpub(this.getXpub());
|
||||
const hdNode = bip32.fromBase58(xpub).derive(node);
|
||||
|
||||
if (node === 0) {
|
||||
if (this.external_addresses_cache[index]) return this.external_addresses_cache[index]; // cache hit
|
||||
}
|
||||
|
||||
if (node === 1) {
|
||||
if (this.internal_addresses_cache[index]) return this.internal_addresses_cache[index]; // cache hit
|
||||
}
|
||||
|
||||
if (node === 0 && !this._node0) {
|
||||
const xpub = this._zpubToXpub(this.getXpub());
|
||||
const hdNode = bip32.fromBase58(xpub);
|
||||
this._node0 = hdNode.derive(node);
|
||||
}
|
||||
|
||||
if (node === 1 && !this._node1) {
|
||||
const xpub = this._zpubToXpub(this.getXpub());
|
||||
const hdNode = bip32.fromBase58(xpub);
|
||||
this._node1 = hdNode.derive(node);
|
||||
}
|
||||
|
||||
let address: string;
|
||||
if (node === 0) {
|
||||
// @ts-ignore
|
||||
address = this._hdNodeToAddress(this._node0.derive(index));
|
||||
this._node0 = hdNode;
|
||||
} else {
|
||||
// tbh the only possible else is node === 1
|
||||
// @ts-ignore
|
||||
address = this._hdNodeToAddress(this._node1.derive(index));
|
||||
this._node1 = hdNode;
|
||||
}
|
||||
|
||||
if (node === 0) {
|
||||
return (this.external_addresses_cache[index] = address);
|
||||
} else {
|
||||
// tbh the only possible else option is node === 1
|
||||
return (this.internal_addresses_cache[index] = address);
|
||||
}
|
||||
return hdNode.derive(index);
|
||||
}
|
||||
|
||||
_getNodePubkeyByIndex(node: number, index: number) {
|
||||
index = index * 1; // cast to int
|
||||
_getNodeAddressByIndex(node: 0 | 1, index: number): string {
|
||||
const cache = node === 0 ? this.external_addresses_cache : this.internal_addresses_cache;
|
||||
|
||||
if (node === 0 && !this._node0) {
|
||||
const xpub = this._zpubToXpub(this.getXpub());
|
||||
const hdNode = bip32.fromBase58(xpub);
|
||||
this._node0 = hdNode.derive(node);
|
||||
}
|
||||
if (cache[index]) return cache[index]; // cache hit
|
||||
|
||||
if (node === 1 && !this._node1) {
|
||||
const xpub = this._zpubToXpub(this.getXpub());
|
||||
const hdNode = bip32.fromBase58(xpub);
|
||||
this._node1 = hdNode.derive(node);
|
||||
}
|
||||
const hdNode = this._getNodeByIndex(node, index);
|
||||
const address = this._hdNodeToAddress(hdNode);
|
||||
|
||||
if (node === 0 && this._node0) {
|
||||
return this._node0.derive(index).publicKey;
|
||||
}
|
||||
return (cache[index] = address);
|
||||
}
|
||||
|
||||
if (node === 1 && this._node1) {
|
||||
return this._node1.derive(index).publicKey;
|
||||
}
|
||||
|
||||
throw new Error('Internal error: this._node0 or this._node1 is undefined');
|
||||
_getNodePubkeyByIndex(node: 0 | 1, index: number) {
|
||||
return this._getNodeByIndex(node, index).publicKey;
|
||||
}
|
||||
|
||||
_getExternalAddressByIndex(index: number): string {
|
||||
@ -610,8 +575,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||
let lastHistoriesWithUsedAddresses = null;
|
||||
for (let c = 0; c < Math.round(index / this.gap_limit); c++) {
|
||||
const histories = await BlueElectrum.multiGetHistoryByAddress(gerenateChunkAddresses(c));
|
||||
// @ts-ignore
|
||||
if (this.constructor._getTransactionsFromHistories(histories).length > 0) {
|
||||
if (AbstractHDElectrumWallet._getTransactionsFromHistories(histories).length > 0) {
|
||||
// in this particular chunk we have used addresses
|
||||
lastChunkWithUsedAddressesNum = c;
|
||||
lastHistoriesWithUsedAddresses = histories;
|
||||
@ -653,8 +617,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||
let lastHistoriesWithUsedAddresses = null;
|
||||
for (let c = 0; c < Math.round(index / this.gap_limit); c++) {
|
||||
const histories = await BlueElectrum.multiGetHistoryByAddress(gerenateChunkAddresses(c));
|
||||
// @ts-ignore
|
||||
if (this.constructor._getTransactionsFromHistories(histories).length > 0) {
|
||||
if (AbstractHDElectrumWallet._getTransactionsFromHistories(histories).length > 0) {
|
||||
// in this particular chunk we have used addresses
|
||||
lastChunkWithUsedAddressesNum = c;
|
||||
lastHistoriesWithUsedAddresses = histories;
|
||||
@ -696,8 +659,7 @@ export class AbstractHDElectrumWallet extends AbstractHDWallet {
|
||||
let lastHistoriesWithUsedAddresses = null;
|
||||
for (let c = 0; c < Math.round(index / this.gap_limit); c++) {
|
||||
const histories = await BlueElectrum.multiGetHistoryByAddress(generateChunkAddresses(c));
|
||||
// @ts-ignore
|
||||
if (this.constructor._getTransactionsFromHistories(histories).length > 0) {
|
||||
if (AbstractHDElectrumWallet._getTransactionsFromHistories(histories).length > 0) {
|
||||
// in this particular chunk we have used addresses
|
||||
lastChunkWithUsedAddressesNum = c;
|
||||
lastHistoriesWithUsedAddresses = histories;
|
||||
|
||||
@ -315,7 +315,7 @@ export class AbstractHDWallet extends LegacyWallet {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
_getNodePubkeyByIndex(node: number, index: number): Uint8Array | undefined {
|
||||
_getNodePubkeyByIndex(node: 0 | 1, index: number): Uint8Array | undefined {
|
||||
throw new Error('Not implemented');
|
||||
}
|
||||
|
||||
|
||||
@ -27,8 +27,8 @@ export class LegacyWallet extends AbstractWallet {
|
||||
// @ts-ignore: override
|
||||
public readonly typeReadable: string;
|
||||
|
||||
_txs_by_external_index: Transaction[] = [];
|
||||
_txs_by_internal_index: Transaction[] = [];
|
||||
_txs_by_external_index: Record<number, Transaction[]> = {};
|
||||
_txs_by_internal_index: Record<number, Transaction[]> = {};
|
||||
|
||||
constructor(typeReadable?: string) {
|
||||
super();
|
||||
@ -344,14 +344,14 @@ export class LegacyWallet extends AbstractWallet {
|
||||
}
|
||||
}
|
||||
|
||||
this._txs_by_external_index = _txsByExternalIndex;
|
||||
this._txs_by_external_index = { 0: _txsByExternalIndex };
|
||||
this._lastTxFetch = +new Date();
|
||||
}
|
||||
|
||||
getTransactions(): Transaction[] {
|
||||
// a hacky code reuse from electrum HD wallet:
|
||||
this._txs_by_external_index = this._txs_by_external_index || [];
|
||||
this._txs_by_internal_index = [];
|
||||
this._txs_by_external_index = this._txs_by_external_index || {};
|
||||
this._txs_by_internal_index = {};
|
||||
|
||||
const { HDSegwitBech32Wallet } = require('./hd-segwit-bech32-wallet') as {
|
||||
HDSegwitBech32Wallet: typeof HDSegwitBech32WalletT;
|
||||
|
||||
@ -515,15 +515,7 @@ interface WalletsCarouselProps extends Partial<FlatListProps<any>> {
|
||||
animateChanges?: boolean;
|
||||
}
|
||||
|
||||
type FlatListRefType = FlatList<any> & {
|
||||
scrollToEnd(params?: { animated?: boolean | null }): void;
|
||||
scrollToIndex(params: { animated?: boolean | null; index: number; viewOffset?: number; viewPosition?: number }): void;
|
||||
scrollToItem(params: { animated?: boolean | null; item: TWallet; viewPosition?: number }): void;
|
||||
scrollToOffset(params: { animated?: boolean | null; offset: number }): void;
|
||||
recordInteraction(): void;
|
||||
flashScrollIndicators(): void;
|
||||
getNativeScrollRef(): View;
|
||||
};
|
||||
export type CarouselListRefType = FlatList<TWallet>;
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
listHeaderSeparator: {
|
||||
@ -534,7 +526,7 @@ const styles = StyleSheet.create({
|
||||
|
||||
const ListHeaderSeparator = () => <View style={styles.listHeaderSeparator} />;
|
||||
|
||||
const WalletsCarousel = forwardRef<FlatListRefType, WalletsCarouselProps>((props, ref) => {
|
||||
const WalletsCarousel = forwardRef<CarouselListRefType, WalletsCarouselProps>((props, ref) => {
|
||||
const {
|
||||
horizontal = true,
|
||||
data,
|
||||
@ -569,7 +561,7 @@ const WalletsCarousel = forwardRef<FlatListRefType, WalletsCarouselProps>((props
|
||||
const scrollTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||
const isInitialMount = useRef(true);
|
||||
|
||||
const flatListRef = useRef<FlatList<any>>(null);
|
||||
const flatListRef = useRef<FlatList<TWallet>>(null);
|
||||
const walletRefs = useRef<Record<string, React.MutableRefObject<View | null>>>({});
|
||||
|
||||
const { sizeClass } = useSizeClass();
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
PODS:
|
||||
- BugsnagReactNative (8.8.1):
|
||||
- BugsnagReactNative (8.9.0):
|
||||
- hermes-engine
|
||||
- RCTRequired
|
||||
- RCTTypeSafety
|
||||
@ -29,7 +29,7 @@ PODS:
|
||||
- hermes-engine/Pre-built (= 250829098.0.10)
|
||||
- hermes-engine/Pre-built (250829098.0.10)
|
||||
- lottie-ios (4.6.0)
|
||||
- lottie-react-native (7.3.7):
|
||||
- lottie-react-native (7.3.8):
|
||||
- hermes-engine
|
||||
- lottie-ios (= 4.6.0)
|
||||
- RCTRequired
|
||||
@ -2018,6 +2018,8 @@ PODS:
|
||||
- ReactNativeDependencies (0.85.3)
|
||||
- RealmJS (20.2.0):
|
||||
- React
|
||||
- RNBackgroundFetch (4.2.9):
|
||||
- React-Core
|
||||
- RNCAsyncStorage (2.2.0):
|
||||
- hermes-engine
|
||||
- RCTRequired
|
||||
@ -2543,6 +2545,7 @@ DEPENDENCIES:
|
||||
- ReactNativeCameraKit (from `../node_modules/react-native-camera-kit-no-google`)
|
||||
- ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)
|
||||
- RealmJS (from `../node_modules/realm`)
|
||||
- RNBackgroundFetch (from `../node_modules/react-native-background-fetch`)
|
||||
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
|
||||
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
|
||||
- RNDefaultPreference (from `../node_modules/react-native-default-preference`)
|
||||
@ -2762,6 +2765,8 @@ EXTERNAL SOURCES:
|
||||
:podspec: "../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec"
|
||||
RealmJS:
|
||||
:path: "../node_modules/realm"
|
||||
RNBackgroundFetch:
|
||||
:path: "../node_modules/react-native-background-fetch"
|
||||
RNCAsyncStorage:
|
||||
:path: "../node_modules/@react-native-async-storage/async-storage"
|
||||
RNCClipboard:
|
||||
@ -2802,13 +2807,13 @@ EXTERNAL SOURCES:
|
||||
:path: "../node_modules/react-native/ReactCommon/yoga"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
BugsnagReactNative: bee770e3f497a8571feb1579bdc083a070bee1f3
|
||||
BugsnagReactNative: 73ce58aac04585e7cba3081c0abba06d848d62fc
|
||||
BVLinearGradient: cb006ba232a1f3e4f341bb62c42d1098c284da70
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
FBLazyVector: 24e62c765683b8d89006a88a2c8f5cf019f0074d
|
||||
hermes-engine: 86cdbf283775c54dc008895c3eacd24a1f2a40b4
|
||||
hermes-engine: 4ed74710a31e8e31f20356c641eab1d8f7d54595
|
||||
lottie-ios: 8f959969761e9c45d70353667d00af0e5b9cadb3
|
||||
lottie-react-native: 26b365c3d5615e87f4db048dcb151de3eb9a8e76
|
||||
lottie-react-native: ee142214581f3bb68fbda7efcf07b835a189eeda
|
||||
RCTDeprecation: a4c521821fab57cbb125b36effe84d897d0dfa12
|
||||
RCTRequired: 9f3a7e5645d4bc3f551593de7550bb66ab6e42bc
|
||||
RCTSwiftUI: 239ed2eb9e73de5a6f518810630f0c95e01c8702
|
||||
@ -2817,7 +2822,7 @@ SPEC CHECKSUMS:
|
||||
React: e2dc35338068bbd299c66f043ae0d7f25de8499e
|
||||
React-callinvoker: 28b25d21b124c26cebaea713ba7d801b9351dc48
|
||||
React-Core: 02ed7d2ffb70437bdf2aba074a13078a7b0b9ff0
|
||||
React-Core-prebuilt: 9e875134f667c471ab68bf9edf1661fa11b86540
|
||||
React-Core-prebuilt: 3445f1028d9b206cd45c8bbb7e2427ee891f810e
|
||||
React-CoreModules: b3a5a42dadcde3b5d47b325bd912eb2ced89e146
|
||||
React-cxxreact: fe8f88dda044e5905e99a00f41b7a874c3908716
|
||||
React-debug: 92944dc4d89f56d640e75498266cbde557a48189
|
||||
@ -2898,8 +2903,9 @@ SPEC CHECKSUMS:
|
||||
ReactCodegen: 1bd7f2174582b0e142f8671735b5c906c08b72ea
|
||||
ReactCommon: 7dfc3250793bf36cf221096ff59e1179e13eef7f
|
||||
ReactNativeCameraKit: 5974256fc608631c1c812710cd98abe95dae0f88
|
||||
ReactNativeDependencies: 0a5c93845772e4b1c5ad065c59a859518b13a6b7
|
||||
ReactNativeDependencies: 75299c281f422106c723e79dc1f6ce7ef03241be
|
||||
RealmJS: 1c37c6bdfe060f4caa0f9175aa0eedb962622ee1
|
||||
RNBackgroundFetch: 64b1215fbb8ec58afba877ca0ce177e009ce12b7
|
||||
RNCAsyncStorage: 2ad919e88b8bc2cd80e8697ce66d04d006743283
|
||||
RNCClipboard: 715fa7c6c8366f17d00f05a439ee7488f390fa5f
|
||||
RNDefaultPreference: 8a089ee8ce829a66c5453e3c5434f0785499d1c3
|
||||
|
||||
28
package-lock.json
generated
28
package-lock.json
generated
@ -10,8 +10,8 @@
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@arkade-os/boltz-swap": "0.3.38",
|
||||
"@arkade-os/sdk": "0.4.33",
|
||||
"@arkade-os/boltz-swap": "0.3.40",
|
||||
"@arkade-os/sdk": "0.4.35",
|
||||
"@babel/preset-env": "7.29.5",
|
||||
"@bugsnag/react-native": "8.9.0",
|
||||
"@bugsnag/source-maps": "2.3.3",
|
||||
@ -25,7 +25,7 @@
|
||||
"@react-native-community/cli-platform-android": "20.1.3",
|
||||
"@react-native-community/cli-platform-ios": "20.1.3",
|
||||
"@react-native-documents/picker": "12.0.1",
|
||||
"@react-native-vector-icons/entypo": "13.1.1",
|
||||
"@react-native-vector-icons/entypo": "13.1.2",
|
||||
"@react-native-vector-icons/fontawesome": "13.1.2",
|
||||
"@react-native-vector-icons/fontawesome6": "13.1.2",
|
||||
"@react-native-vector-icons/ionicons": "13.1.2",
|
||||
@ -179,12 +179,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@arkade-os/boltz-swap": {
|
||||
"version": "0.3.38",
|
||||
"resolved": "https://registry.npmjs.org/@arkade-os/boltz-swap/-/boltz-swap-0.3.38.tgz",
|
||||
"integrity": "sha512-BVbyw9Fj+1eQn771t0ZO9uW7E1BgViAPLFddb4pnW9p3rM9fCIdWEs2ZrjPnq70leDdhrUxRy++cJuK7zFThuA==",
|
||||
"version": "0.3.40",
|
||||
"resolved": "https://registry.npmjs.org/@arkade-os/boltz-swap/-/boltz-swap-0.3.40.tgz",
|
||||
"integrity": "sha512-Q1myKKXC5c44wzAD6eb4lrq3rro0qwyJqNqf0powjfbhSTzHfk5Do6DfZYrciueEK4agilynLNurWCYsoE8yEw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@arkade-os/sdk": "0.4.33",
|
||||
"@arkade-os/sdk": "0.4.35",
|
||||
"@noble/curves": "2.0.1",
|
||||
"@noble/hashes": "2.0.1",
|
||||
"@scure/base": "2.0.0",
|
||||
@ -218,9 +218,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@arkade-os/sdk": {
|
||||
"version": "0.4.33",
|
||||
"resolved": "https://registry.npmjs.org/@arkade-os/sdk/-/sdk-0.4.33.tgz",
|
||||
"integrity": "sha512-EvfmDhSyAiZ7DW89o5D1N4woDEFMfZLHXi/zh9C1xKlPHB2PCezEkHpVe51lNF0Vx3rgkf6bx54QXoGOvg1p9A==",
|
||||
"version": "0.4.35",
|
||||
"resolved": "https://registry.npmjs.org/@arkade-os/sdk/-/sdk-0.4.35.tgz",
|
||||
"integrity": "sha512-gMARWDEgy5YL15vE4hBoUf4IGBi94tDRymtVwIehL+2MQylFm6cO1Qt50/aA6dwle5Ae+XMfF99Wf6k/Gc257A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@bitcoinerlab/descriptors-scure": "3.1.7",
|
||||
@ -3953,12 +3953,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@react-native-vector-icons/entypo": {
|
||||
"version": "13.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-vector-icons/entypo/-/entypo-13.1.1.tgz",
|
||||
"integrity": "sha512-K3uZ/S0Nr0a/vuXw81tZDhKJaUfaGeTG+50vPHO60Ucl/L9b3O4KUtzMJa7zd0c400CO0vl5Lr97Wk266eXwLQ==",
|
||||
"version": "13.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@react-native-vector-icons/entypo/-/entypo-13.1.2.tgz",
|
||||
"integrity": "sha512-oxfKPz8amwmI/IiYadwgKlGBo4y68bwYVhx5N4dTffaIR4n73Lk6AUlNUcYzSoMzSAYZVfySGPq7YV8whrc8dw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@react-native-vector-icons/common": "^13.0.0"
|
||||
"@react-native-vector-icons/common": "^13.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18.0.0"
|
||||
|
||||
@ -93,8 +93,8 @@
|
||||
"unit": "jest -b tests/unit/*"
|
||||
},
|
||||
"dependencies": {
|
||||
"@arkade-os/boltz-swap": "0.3.38",
|
||||
"@arkade-os/sdk": "0.4.33",
|
||||
"@arkade-os/boltz-swap": "0.3.40",
|
||||
"@arkade-os/sdk": "0.4.35",
|
||||
"@babel/preset-env": "7.29.5",
|
||||
"@bugsnag/react-native": "8.9.0",
|
||||
"@bugsnag/source-maps": "2.3.3",
|
||||
@ -108,7 +108,7 @@
|
||||
"@react-native-community/cli-platform-android": "20.1.3",
|
||||
"@react-native-community/cli-platform-ios": "20.1.3",
|
||||
"@react-native-documents/picker": "12.0.1",
|
||||
"@react-native-vector-icons/entypo": "13.1.1",
|
||||
"@react-native-vector-icons/entypo": "13.1.2",
|
||||
"@react-native-vector-icons/fontawesome": "13.1.2",
|
||||
"@react-native-vector-icons/fontawesome6": "13.1.2",
|
||||
"@react-native-vector-icons/ionicons": "13.1.2",
|
||||
|
||||
@ -46,7 +46,7 @@ const LNDViewInvoice = () => {
|
||||
const [isFetchingInvoices, setIsFetchingInvoices] = useState<boolean>(true);
|
||||
const [invoiceStatusChanged, setInvoiceStatusChanged] = useState<boolean>(false);
|
||||
const [qrCodeSize, setQRCodeSize] = useState<number>(90);
|
||||
const fetchInvoiceInterval = useRef<any>(null);
|
||||
const fetchInvoiceInterval = useRef<ReturnType<typeof setInterval> | undefined>(undefined);
|
||||
const isModal = useNavigationState(state => state.routeNames[0] === LNDCreateInvoice.routeName);
|
||||
|
||||
// Per-swap claim/refund lookup, by the `swap-${id}` prefix mapped onto
|
||||
@ -179,7 +179,6 @@ const LNDViewInvoice = () => {
|
||||
fetchInvoiceInterval.current = setInterval(async () => {
|
||||
if (isFetchingInvoices) {
|
||||
try {
|
||||
// @ts-ignore - getUserInvoices is not set on TWallet
|
||||
const userInvoices: LightningTransaction[] = await wallet.getUserInvoices(20);
|
||||
// fetching only last 20 invoices
|
||||
// for invoice that was created just now - that should be enough (it is basically the last one, so limit=1 would be sufficient)
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { RouteProp, StackActions, useIsFocused, useRoute } from '@react-navigation/native';
|
||||
import * as bitcoin from 'bitcoinjs-lib';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { ActivityIndicator, ScrollView, StyleSheet, View } from 'react-native';
|
||||
import { ActivityIndicator, ScrollView, StyleSheet, View, TouchableOpacity } from 'react-native';
|
||||
import presentAlert from '../../components/Alert';
|
||||
import { DynamicQRCode } from '../../components/DynamicQRCode';
|
||||
import SaveFileButton from '../../components/SaveFileButton';
|
||||
@ -23,7 +23,7 @@ type RouteParams = RouteProp<SendDetailsStackParamList, 'PsbtMultisigQRCode'>;
|
||||
const PsbtMultisigQRCode: React.FC = () => {
|
||||
const navigation = useExtendedNavigation();
|
||||
const { colors } = useTheme();
|
||||
const openScannerButton = useRef<any>(null);
|
||||
const openScannerButton = useRef<React.ElementRef<typeof TouchableOpacity>>(null);
|
||||
const { params } = useRoute<RouteParams>();
|
||||
const { psbtBase64, isShowOpenScanner, walletID } = params;
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
@ -91,7 +91,7 @@ const SendDetails = () => {
|
||||
const payjoinUrl = route.params?.payjoinUrl;
|
||||
const isTransactionReplaceable = route.params?.isTransactionReplaceable;
|
||||
const routeParams = route.params;
|
||||
const scrollView = useRef<FlatList<any>>(null);
|
||||
const scrollView = useRef<FlatList<IPaymentDestinations>>(null);
|
||||
const scrollIndex = useRef(0);
|
||||
/** Used so we only clear coin-selection (utxos) when the user switches wallet, not on first mount (e.g. Send opened from wallet details with pre-selected UTXOs). */
|
||||
const prevWalletIdForCoinResetRef = useRef<string | null>(null);
|
||||
@ -221,9 +221,6 @@ const SendDetails = () => {
|
||||
}
|
||||
return updatedAddresses;
|
||||
});
|
||||
|
||||
// @ts-ignore: Fix later
|
||||
setParams(prevParams => ({ ...prevParams, addRecipientParams: undefined }));
|
||||
} else {
|
||||
setAddresses([{ address: '', key: String(Math.random()), unit: amountUnit }]); // key is for the FlatList
|
||||
}
|
||||
|
||||
@ -5,7 +5,7 @@ import { StyleSheet, View, ViewStyle, Animated, ScrollView } from 'react-native'
|
||||
import { TWallet } from '../../class/wallets/types';
|
||||
import { Header } from '../../components/Header';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import WalletsCarousel from '../../components/WalletsCarousel';
|
||||
import WalletsCarousel, { CarouselListRefType } from '../../components/WalletsCarousel';
|
||||
import loc from '../../loc';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import TotalWalletsBalance from '../../components/TotalWalletsBalance';
|
||||
@ -94,7 +94,7 @@ const DrawerList: React.FC<DrawerContentComponentProps> = memo((props: DrawerCon
|
||||
const drawerNavigation = props.navigation;
|
||||
|
||||
const [state, dispatch] = useReducer(walletReducer, initialState);
|
||||
const walletsCarousel = useRef<any>(null);
|
||||
const walletsCarousel = useRef<CarouselListRefType>(null);
|
||||
const { wallets, selectedWalletID } = useStorage();
|
||||
const { colors } = useTheme();
|
||||
const isFocused = useIsFocused();
|
||||
|
||||
@ -78,7 +78,7 @@ const ExportMultisigCoordinationSetup: React.FC = () => {
|
||||
const { wallets } = useStorage();
|
||||
const { isPrivacyBlurEnabled } = useSettings();
|
||||
const wallet: TWallet | undefined = wallets.find(w => w.getID() === walletID);
|
||||
const dynamicQRCode = useRef<any>(null);
|
||||
const dynamicQRCode = useRef<DynamicQRCode>(null);
|
||||
const { colors } = useTheme();
|
||||
const { enableScreenProtect, disableScreenProtect } = useScreenProtect();
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@ import { useTheme } from '../../components/themes';
|
||||
import loc from '../../loc';
|
||||
import { Chain } from '../../models/bitcoinUnits';
|
||||
import { useStorage } from '../../hooks/context/useStorage';
|
||||
import WalletsCarousel from '../../components/WalletsCarousel';
|
||||
import WalletsCarousel, { CarouselListRefType } from '../../components/WalletsCarousel';
|
||||
import { useExtendedNavigation } from '../../hooks/useExtendedNavigation';
|
||||
import { TWallet } from '../../class/wallets/types';
|
||||
import { pop } from '../../NavigationService';
|
||||
@ -35,7 +35,7 @@ const SelectWallet: React.FC = () => {
|
||||
const { wallets } = useStorage();
|
||||
const { colors } = useTheme();
|
||||
const isModal = useNavigationState(state => state.routes.length > 1);
|
||||
const walletsCarousel = useRef<any>(null);
|
||||
const walletsCarousel = useRef<CarouselListRefType>(null);
|
||||
const previousRouteName = useNavigationState(state => state.routes[state.routes.length - 2]?.name);
|
||||
const [filteredWallets, setFilteredWallets] = useState<TWallet[]>([]);
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }: { rout
|
||||
const [displayUnit, setDisplayUnit] = useState(wallet.preferredBalanceUnit);
|
||||
const [isUnitSwitching, setIsUnitSwitching] = useState(false);
|
||||
const [isWatchOnlyWarningVisible, setIsWatchOnlyWarningVisible] = useState<boolean>(() => {
|
||||
return wallet.type === WatchOnlyWallet.type && (wallet as any).isWatchOnlyWarningVisible;
|
||||
return wallet.type === WatchOnlyWallet.type && (wallet as WatchOnlyWallet).isWatchOnlyWarningVisible;
|
||||
});
|
||||
const MAX_FAILURES = 3;
|
||||
const flatListRef = useRef<FlatList<Transaction>>(null);
|
||||
@ -172,7 +172,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }: { rout
|
||||
}, [wallet, walletID]);
|
||||
|
||||
useEffect(() => {
|
||||
setIsWatchOnlyWarningVisible(wallet.type === WatchOnlyWallet.type && (wallet as any).isWatchOnlyWarningVisible);
|
||||
setIsWatchOnlyWarningVisible(wallet.type === WatchOnlyWallet.type && (wallet as WatchOnlyWallet).isWatchOnlyWarningVisible);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [walletID]);
|
||||
|
||||
@ -547,7 +547,7 @@ const WalletTransactions: React.FC<WalletTransactionsProps> = ({ route }: { rout
|
||||
if ('setPreferredBalanceUnit' in wallet) {
|
||||
wallet.setPreferredBalanceUnit(selectedUnit);
|
||||
} else {
|
||||
(wallet as any).preferredBalanceUnit = selectedUnit;
|
||||
(wallet as TWallet).preferredBalanceUnit = selectedUnit;
|
||||
}
|
||||
await saveToDisk();
|
||||
console.debug('[UnitSwitch] persisted preferred unit', { walletID, unit: selectedUnit });
|
||||
|
||||
@ -11,7 +11,7 @@ import presentAlert from '../../components/Alert';
|
||||
import { FButton, FContainer, FloatButtonsBottomFade } from '../../components/FloatButtons';
|
||||
import { useTheme } from '../../components/themes';
|
||||
import { TransactionListItem } from '../../components/TransactionListItem';
|
||||
import WalletsCarousel, { getWalletCarouselItemWidth } from '../../components/WalletsCarousel';
|
||||
import WalletsCarousel, { getWalletCarouselItemWidth, CarouselListRefType } from '../../components/WalletsCarousel';
|
||||
import { useSizeClass, SizeClass } from '../../blue_modules/sizeClass';
|
||||
import loc from '../../loc';
|
||||
import ActionSheet from '../ActionSheet';
|
||||
@ -101,7 +101,7 @@ const WalletsList: React.FC = () => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const { isLoading } = state;
|
||||
const { sizeClass, isLarge } = useSizeClass();
|
||||
const walletsCarousel = useRef<any>(null);
|
||||
const walletsCarousel = useRef<CarouselListRefType>(null);
|
||||
const connectionPoll = useContext(ConnectionPollContext);
|
||||
const currentWalletIndex = useRef<number>(0);
|
||||
const { registerTransactionsHandler, unregisterTransactionsHandler } = useMenuElements();
|
||||
|
||||
@ -173,7 +173,7 @@ export async function helperDeleteWallet(label, remainingBalanceSat = false) {
|
||||
await waitForId('WalletDetails');
|
||||
await element(by.id('WalletDetails')).tap();
|
||||
await element(by.id('WalletDetailsScroll')).swipe('up', 'fast', 1);
|
||||
await sleep(200);
|
||||
await sleep(1000);
|
||||
await element(by.id('DeleteWallet')).tap();
|
||||
await waitForText('Yes, delete');
|
||||
await element(by.text('Yes, delete')).tap();
|
||||
@ -368,19 +368,37 @@ export async function goBack() {
|
||||
// Try each back/close affordance in order; retry the full set up to 10 times.
|
||||
const candidates = [by.id('BackButton'), by.id('NavigationCloseButton'), by.label('Back'), by.text('Close')];
|
||||
|
||||
// A matcher can hit several elements across stacked screens: each nav back
|
||||
// button exists twice (_UIButtonBarButton wrapper + UIAccessibilityBackButtonElement),
|
||||
// and when a modal covers a stack that also has a back button, the covered
|
||||
// one can precede the visible one in match order (seen with Reduce Motion on).
|
||||
// Probe attributes and only tap an element detox reports as visible & hittable.
|
||||
let lastErr;
|
||||
for (let attempt = 0; attempt < 10; attempt++) {
|
||||
for (const matcher of candidates) {
|
||||
try {
|
||||
await element(matcher).atIndex(0).tap();
|
||||
return;
|
||||
} catch (_) {
|
||||
/* try next */
|
||||
for (let idx = 0; idx < 6; idx++) {
|
||||
let attrs;
|
||||
try {
|
||||
attrs = await element(matcher).atIndex(idx).getAttributes();
|
||||
} catch (err) {
|
||||
lastErr = err;
|
||||
break; // no element at this index — try next candidate
|
||||
}
|
||||
if (!attrs.visible || attrs.hittable === false) continue;
|
||||
try {
|
||||
await element(matcher).atIndex(idx).tap();
|
||||
return;
|
||||
} catch (err) {
|
||||
lastErr = err;
|
||||
}
|
||||
}
|
||||
}
|
||||
await sleep(500);
|
||||
}
|
||||
|
||||
rethrowWithCallsite(new Error('goBack: no back/close affordance tappable after 10 attempts.'), callsite);
|
||||
const wrapped = new Error('goBack: no back/close affordance tappable after 10 attempts.');
|
||||
if (lastErr) wrapped.cause = lastErr;
|
||||
rethrowWithCallsite(wrapped, callsite);
|
||||
}
|
||||
|
||||
export async function typeTextIntoAlertInput(text) {
|
||||
@ -405,7 +423,7 @@ export async function scrollUpOnHomeScreen() {
|
||||
// if no wallets there will be just one scroll
|
||||
await element(by.type('RCTEnhancedScrollView')).swipe('down', 'slow', 0.5);
|
||||
}
|
||||
await sleep(200); // bounce animation
|
||||
await sleep(1000); // bounce animation
|
||||
}
|
||||
|
||||
// We really only need this function when running tests locally.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user