chantools: sweepremoteclosed
This commit is contained in:
@@ -168,6 +168,10 @@ import LSPS1Order from './views/LSPS1/Order';
|
||||
import LSPS7 from './views/LSPS7/index';
|
||||
import LSPS7Order from './views/LSPS7/Order';
|
||||
|
||||
// Chantools
|
||||
import Chantools from './views/Settings/EmbeddedNode/Chantools';
|
||||
import Sweepremoteclosed from './views/Settings/EmbeddedNode/Chantools/Sweepremoteclosed';
|
||||
|
||||
import RawTxHex from './views/RawTxHex';
|
||||
|
||||
import CustodialWalletWarning from './views/Settings/CustodialWalletWarning';
|
||||
@@ -924,6 +928,16 @@ export default class App extends React.PureComponent {
|
||||
DeveloperTools
|
||||
}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Chantools" // @ts-ignore:next-line
|
||||
component={Chantools}
|
||||
/>
|
||||
<Stack.Screen
|
||||
name="Sweepremoteclosed" // @ts-ignore:next-line
|
||||
component={
|
||||
Sweepremoteclosed
|
||||
}
|
||||
/>
|
||||
</Stack.Navigator>
|
||||
</NavigationContainer>
|
||||
</>
|
||||
|
||||
@@ -145,4 +145,16 @@ class LncModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaMod
|
||||
gocb.setCallback(::sendEvent)
|
||||
Lndmobile.invokeRPC(namespace, eventName, request, gocb)
|
||||
}
|
||||
|
||||
// chantools
|
||||
|
||||
@ReactMethod
|
||||
fun sweepRemoteClosed(seedPhrase: String, apiURL: String, sweepAddr: String, recoveryWindow: Int, feeRate: Int, sleepSeconds: Int, publish: Boolean = false, isTestnet: Boolean = false, promise: Promise) {
|
||||
try {
|
||||
var response = Lndmobile.sweepRemoteClosed(seedPhrase, apiURL, sweepAddr, recoveryWindow, feeRate, sleepSeconds, publish, isTestnet)
|
||||
promise.resolve(response);
|
||||
} catch(e: Throwable) {
|
||||
promise.reject("request Error", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,10 +1,10 @@
|
||||
VERSION=v0.18.4-beta-zeus
|
||||
VERSION=v0.18.4-beta-zeus.chantools-alpha1
|
||||
|
||||
ANDROID_FILE=Lndmobile.aar
|
||||
IOS_FILE=Lndmobile.xcframework
|
||||
|
||||
ANDROID_SHA256='8f3f569fd603fb101d7de08a7f9e017cb7267fd24da549908b7733b40e54393f'
|
||||
IOS_SHA256='159e63de8b4a14a402f885adb88c9b34a66c7f6c8a15cbb3c5cc2ba44a5c1bd6'
|
||||
ANDROID_SHA256='db6a1953ed993ef13a843c22040560631c5870f294ec2256031fb5e73b113542'
|
||||
IOS_SHA256='ceb9956853bad47391d068718364fd786767100e45d41b1660a0e421a19c4182'
|
||||
|
||||
FILE_PATH=https://github.com/ZeusLN/lnd/releases/download/$VERSION/
|
||||
|
||||
|
||||
@@ -216,6 +216,32 @@ RCT_EXPORT_METHOD(initListener:(NSString *)nameSpace
|
||||
];
|
||||
}
|
||||
|
||||
// chantools
|
||||
|
||||
RCT_EXPORT_METHOD(sweepRemoteClosed:(NSString *)seedPhrase
|
||||
apiURL:(NSString *)apiURL
|
||||
sweepAddr:(NSString *)sweepAddr
|
||||
recoveryWindow:(NSInteger)recoveryWindow
|
||||
feeRate:(NSInteger)feeRate
|
||||
sleepSeconds:(NSInteger)sleepSeconds
|
||||
publish:(BOOL)publish
|
||||
isTestnet:(BOOL)isTestnet
|
||||
resolver:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject)
|
||||
{
|
||||
NSError *error;
|
||||
NSString *response = LndmobileSweepRemoteClosed(seedPhrase, apiURL, sweepAddr, recoveryWindow, feeRate, sleepSeconds, publish, isTestnet, &error);
|
||||
if (error) {
|
||||
// Create a string representation of the error
|
||||
NSString *errorString = [NSString stringWithFormat:@"%@",
|
||||
error.localizedDescription];
|
||||
|
||||
reject(@"sweepRemoteClosed_failure", errorString, error);
|
||||
} else {
|
||||
resolve(response);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't compile this code when we build for the old architecture.
|
||||
#ifdef RCT_NEW_ARCH_ENABLED
|
||||
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
||||
|
||||
@@ -1267,6 +1267,15 @@
|
||||
"view.Settings.LSPServicesList.title": "LSP Services",
|
||||
"view.Settings.LSPServicesList.flow2": "Just-in-time channels",
|
||||
"view.Settings.LSPServicesList.lsps1": "Request channels in advance",
|
||||
"views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.seed": "Seed phrase",
|
||||
"views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.recoveryWindow": "Recovery window",
|
||||
"views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.recoveryWindow.explainer": "The number of keys to scan per derivation path.",
|
||||
"views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.sleepSeconds": "Seconds to wait between queries",
|
||||
"views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.sleepSeconds.explainer": "Use this to add a pause between queries if you get rate limited by the API.",
|
||||
"views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.sweepAddr": "Sweep address",
|
||||
"views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.apiUrl": "API URL",
|
||||
"views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.customApiUrl": "Custom API URL",
|
||||
"views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.start": "Start sweep",
|
||||
"views.LspExplanation.text1": "Zeus is a self-custodial lightning wallet. In order to send or receive a lightning payment, you must open a lightning payment channel, which has a setup fee.",
|
||||
"views.LspExplanation.text2": "Once the channel is set up, you'll only have to pay normal network fees until your channel exhausts its capacity.",
|
||||
"views.LspExplanation.buttonText": "Learn more about liquidity",
|
||||
|
||||
@@ -457,6 +457,29 @@ export default class EmbeddedNodeAdvancedSettings extends React.Component<
|
||||
</Text>
|
||||
</View>
|
||||
</>
|
||||
<>
|
||||
<ListItem
|
||||
containerStyle={{
|
||||
backgroundColor: 'transparent'
|
||||
}}
|
||||
onPress={() => navigation.navigate('Chantools')}
|
||||
>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title
|
||||
style={{
|
||||
color: themeColor('text'),
|
||||
fontFamily: 'PPNeueMontreal-Book'
|
||||
}}
|
||||
>
|
||||
chantools
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
<Icon
|
||||
name="keyboard-arrow-right"
|
||||
color={themeColor('secondaryText')}
|
||||
/>
|
||||
</ListItem>
|
||||
</>
|
||||
<>
|
||||
<View style={{ marginTop: 20 }}>
|
||||
<Button
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
import * as React from 'react';
|
||||
import {
|
||||
NativeModules,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
import { inject, observer } from 'mobx-react';
|
||||
|
||||
import Button from '../../../../components/Button';
|
||||
import DropdownSetting from '../../../../components/DropdownSetting';
|
||||
import Header from '../../../../components/Header';
|
||||
import KeyValue from '../../../../components/KeyValue';
|
||||
import LoadingIndicator from '../../../../components/LoadingIndicator';
|
||||
import OnchainFeeInput from '../../../../components/OnchainFeeInput';
|
||||
import { Row } from '../../../../components/layout/Row';
|
||||
import Screen from '../../../../components/Screen';
|
||||
import { ErrorMessage } from '../../../../components/SuccessErrorMessage';
|
||||
import Text from '../../../../components/Text';
|
||||
import TextInput from '../../../../components/TextInput';
|
||||
|
||||
import { localeString } from '../../../../utils/LocaleUtils';
|
||||
import { themeColor } from '../../../../utils/ThemeUtils';
|
||||
|
||||
import NodeInfoStore from '../../../../stores/NodeInfoStore';
|
||||
|
||||
import CaretDown from '../../../../assets/images/SVG/Caret Down.svg';
|
||||
import CaretRight from '../../../../assets/images/SVG/Caret Right.svg';
|
||||
|
||||
export const API_URL_KEYS = [
|
||||
{
|
||||
key: 'https://api.node-recovery.com',
|
||||
value: 'https://api.node-recovery.com'
|
||||
},
|
||||
{
|
||||
key: 'https://blockstream.info/api',
|
||||
value: 'https://blockstream.info/api'
|
||||
},
|
||||
{ key: 'https://mempool.space/api', value: 'https://mempool.space/api' },
|
||||
{ key: 'Custom', value: 'Custom' }
|
||||
];
|
||||
|
||||
interface SweepremoteclosedProps {
|
||||
navigation: StackNavigationProp<any, any>;
|
||||
NodeInfoStore: NodeInfoStore;
|
||||
}
|
||||
|
||||
interface SweepremoteclosedState {
|
||||
seed: string;
|
||||
sweepAddr: string;
|
||||
apiUrl: string;
|
||||
customApiUrl: string;
|
||||
feeRate: string;
|
||||
sleepSeconds: string;
|
||||
recoveryWindow: string;
|
||||
loading: boolean;
|
||||
settingsToggle: boolean;
|
||||
error: string;
|
||||
}
|
||||
|
||||
@inject('NodeInfoStore')
|
||||
@observer
|
||||
export default class Sweepremoteclosed extends React.Component<
|
||||
SweepremoteclosedProps,
|
||||
SweepremoteclosedState
|
||||
> {
|
||||
state = {
|
||||
seed: '',
|
||||
sweepAddr: '',
|
||||
apiUrl: 'https://api.node-recovery.com',
|
||||
customApiUrl: '',
|
||||
feeRate: '21',
|
||||
recoveryWindow: '200',
|
||||
sleepSeconds: '0',
|
||||
loading: false,
|
||||
settingsToggle: false,
|
||||
error: ''
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
const {
|
||||
seed,
|
||||
sweepAddr,
|
||||
apiUrl,
|
||||
customApiUrl,
|
||||
feeRate,
|
||||
recoveryWindow,
|
||||
sleepSeconds,
|
||||
loading,
|
||||
settingsToggle,
|
||||
error
|
||||
} = this.state;
|
||||
return (
|
||||
<Screen>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Header
|
||||
leftComponent="Back"
|
||||
centerComponent={{
|
||||
text: 'sweepremoteclosed',
|
||||
style: {
|
||||
color: themeColor('text'),
|
||||
fontFamily: 'PPNeueMontreal-Book'
|
||||
}
|
||||
}}
|
||||
navigation={navigation}
|
||||
/>
|
||||
{error && <ErrorMessage message={error} dismissable />}
|
||||
{loading && <LoadingIndicator />}
|
||||
<ScrollView style={{ margin: 10 }}>
|
||||
<>
|
||||
<Text
|
||||
style={{
|
||||
...styles.text,
|
||||
color: themeColor('secondaryText')
|
||||
}}
|
||||
>
|
||||
{localeString(
|
||||
'views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.seed'
|
||||
)}
|
||||
</Text>
|
||||
<TextInput
|
||||
placeholder={
|
||||
'cherry truth mask employ box silver mass bunker fiscal vote'
|
||||
}
|
||||
value={seed}
|
||||
onChangeText={(text: string) =>
|
||||
this.setState({
|
||||
seed: text
|
||||
})
|
||||
}
|
||||
locked={loading}
|
||||
/>
|
||||
</>
|
||||
<>
|
||||
<Text
|
||||
style={{
|
||||
...styles.text,
|
||||
color: themeColor('secondaryText')
|
||||
}}
|
||||
>
|
||||
{localeString(
|
||||
'views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.sweepAddr'
|
||||
)}
|
||||
</Text>
|
||||
<TextInput
|
||||
value={sweepAddr}
|
||||
onChangeText={(text: string) =>
|
||||
this.setState({
|
||||
sweepAddr: text
|
||||
})
|
||||
}
|
||||
locked={loading}
|
||||
/>
|
||||
</>
|
||||
<>
|
||||
<Text
|
||||
style={{
|
||||
...styles.text,
|
||||
color: themeColor('secondaryText')
|
||||
}}
|
||||
>
|
||||
{localeString('views.Send.feeSatsVbyte')}
|
||||
</Text>
|
||||
<OnchainFeeInput
|
||||
fee={feeRate}
|
||||
onChangeFee={(text: string) => {
|
||||
this.setState({
|
||||
feeRate: text
|
||||
});
|
||||
}}
|
||||
navigation={navigation}
|
||||
/>
|
||||
</>
|
||||
<TouchableOpacity
|
||||
onPress={() => {
|
||||
this.setState({
|
||||
settingsToggle: !settingsToggle
|
||||
});
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
marginBottom: 10
|
||||
}}
|
||||
>
|
||||
<Row justify="space-between">
|
||||
<View style={{ width: '95%' }}>
|
||||
<KeyValue
|
||||
keyValue={localeString(
|
||||
'general.advancedSettings'
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
{settingsToggle ? (
|
||||
<CaretDown
|
||||
fill={themeColor('text')}
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
) : (
|
||||
<CaretRight
|
||||
fill={themeColor('text')}
|
||||
width="20"
|
||||
height="20"
|
||||
/>
|
||||
)}
|
||||
</Row>
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
{settingsToggle && (
|
||||
<>
|
||||
<>
|
||||
<Text
|
||||
style={{
|
||||
...styles.text,
|
||||
color: themeColor('secondaryText')
|
||||
}}
|
||||
infoModalText={localeString(
|
||||
'views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.recoveryWindow.explainer'
|
||||
)}
|
||||
>
|
||||
{localeString(
|
||||
'views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.recoveryWindow'
|
||||
)}
|
||||
</Text>
|
||||
<TextInput
|
||||
placeholder={'200'}
|
||||
value={recoveryWindow}
|
||||
onChangeText={(text: string) =>
|
||||
this.setState({
|
||||
recoveryWindow: text
|
||||
})
|
||||
}
|
||||
locked={loading}
|
||||
keyboardType="numeric"
|
||||
/>
|
||||
</>
|
||||
<>
|
||||
<Text
|
||||
style={{
|
||||
...styles.text,
|
||||
color: themeColor('secondaryText')
|
||||
}}
|
||||
infoModalText={localeString(
|
||||
'views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.sleepSeconds.explainer'
|
||||
)}
|
||||
>
|
||||
{localeString(
|
||||
'views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.sleepSeconds'
|
||||
)}
|
||||
</Text>
|
||||
<TextInput
|
||||
placeholder={'0'}
|
||||
value={sleepSeconds}
|
||||
onChangeText={(text: string) =>
|
||||
this.setState({
|
||||
sleepSeconds: text
|
||||
})
|
||||
}
|
||||
locked={loading}
|
||||
keyboardType="numeric"
|
||||
/>
|
||||
</>
|
||||
<View style={{ marginTop: 10 }}>
|
||||
<DropdownSetting
|
||||
title={localeString(
|
||||
'views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.apiUrl'
|
||||
)}
|
||||
selectedValue={apiUrl}
|
||||
onValueChange={(value: string) => {
|
||||
this.setState({
|
||||
apiUrl: value
|
||||
});
|
||||
}}
|
||||
values={API_URL_KEYS}
|
||||
/>
|
||||
</View>
|
||||
{apiUrl === 'Custom' && (
|
||||
<>
|
||||
<Text
|
||||
style={{
|
||||
...styles.text,
|
||||
color: themeColor(
|
||||
'secondaryText'
|
||||
)
|
||||
}}
|
||||
>
|
||||
{localeString(
|
||||
'views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.customApiUrl'
|
||||
)}
|
||||
</Text>
|
||||
<TextInput
|
||||
value={customApiUrl}
|
||||
onChangeText={(text: string) =>
|
||||
this.setState({
|
||||
sweepAddr: text
|
||||
})
|
||||
}
|
||||
locked={!!customApiUrl}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</ScrollView>
|
||||
<View style={{ bottom: 10 }}>
|
||||
<View
|
||||
style={{
|
||||
paddingTop: 30,
|
||||
paddingBottom: 15,
|
||||
paddingLeft: 10,
|
||||
paddingRight: 10
|
||||
}}
|
||||
>
|
||||
<Button
|
||||
title={localeString(
|
||||
'views.Settings.EmbeddedNode.Chantools.Sweepremoteclosed.start'
|
||||
)}
|
||||
onPress={async () => {
|
||||
this.setState({
|
||||
error: '',
|
||||
loading: true
|
||||
});
|
||||
console.log('start sweepremoteclosed', {
|
||||
seed,
|
||||
apiUrl,
|
||||
customApiUrl,
|
||||
recoveryWindow,
|
||||
feeRate,
|
||||
sleepSeconds
|
||||
});
|
||||
try {
|
||||
const response =
|
||||
await NativeModules.LncModule.sweepRemoteClosed(
|
||||
seed,
|
||||
apiUrl === 'Custom'
|
||||
? customApiUrl
|
||||
: apiUrl,
|
||||
sweepAddr,
|
||||
Number(recoveryWindow || 200),
|
||||
Number(feeRate || 2),
|
||||
Number(sleepSeconds || 0),
|
||||
false, // publish
|
||||
this.props.NodeInfoStore
|
||||
?.nodeInfo?.isTestNet // isTestNet
|
||||
);
|
||||
navigation.navigate('TxHex', {
|
||||
txHex: response,
|
||||
hideWarning: true
|
||||
});
|
||||
} catch (e: any) {
|
||||
this.setState({
|
||||
error: e.toString(),
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Screen>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
text: {
|
||||
fontFamily: 'PPNeueMontreal-Book'
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,63 @@
|
||||
import * as React from 'react';
|
||||
import { ScrollView, View } from 'react-native';
|
||||
import { Icon, ListItem } from 'react-native-elements';
|
||||
import { StackNavigationProp } from '@react-navigation/stack';
|
||||
|
||||
import Header from '../../../../components/Header';
|
||||
import Screen from '../../../../components/Screen';
|
||||
|
||||
import { themeColor } from '../../../../utils/ThemeUtils';
|
||||
|
||||
interface ChantoolsProps {
|
||||
navigation: StackNavigationProp<any, any>;
|
||||
}
|
||||
|
||||
export default class Chantools extends React.Component<ChantoolsProps, {}> {
|
||||
render() {
|
||||
const { navigation } = this.props;
|
||||
return (
|
||||
<Screen>
|
||||
<View style={{ flex: 1 }}>
|
||||
<Header
|
||||
leftComponent="Back"
|
||||
centerComponent={{
|
||||
text: 'chantools',
|
||||
style: {
|
||||
color: themeColor('text'),
|
||||
fontFamily: 'PPNeueMontreal-Book'
|
||||
}
|
||||
}}
|
||||
navigation={navigation}
|
||||
/>
|
||||
<ScrollView>
|
||||
<>
|
||||
<ListItem
|
||||
containerStyle={{
|
||||
backgroundColor: 'transparent'
|
||||
}}
|
||||
onPress={() =>
|
||||
navigation.navigate('Sweepremoteclosed')
|
||||
}
|
||||
>
|
||||
<ListItem.Content>
|
||||
<ListItem.Title
|
||||
style={{
|
||||
color: themeColor('text'),
|
||||
fontFamily: 'PPNeueMontreal-Book'
|
||||
}}
|
||||
>
|
||||
sweepremoteclosed
|
||||
</ListItem.Title>
|
||||
</ListItem.Content>
|
||||
<Icon
|
||||
name="keyboard-arrow-right"
|
||||
color={themeColor('secondaryText')}
|
||||
/>
|
||||
</ListItem>
|
||||
</>
|
||||
</ScrollView>
|
||||
</View>
|
||||
</Screen>
|
||||
);
|
||||
}
|
||||
}
|
||||
+11
-7
@@ -40,7 +40,7 @@ interface TxHexProps {
|
||||
ChannelsStore: ChannelsStore;
|
||||
NodeInfoStore: NodeInfoStore;
|
||||
TransactionsStore: TransactionsStore;
|
||||
route: Route<'TxHex', { txHex: string }>;
|
||||
route: Route<'TxHex', { txHex: string; hideWarning?: boolean }>;
|
||||
}
|
||||
|
||||
interface TxHexState {
|
||||
@@ -301,12 +301,16 @@ export default class TxHex extends React.Component<TxHexProps, TxHexState> {
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
{!loading && pending_chan_ids.length === 0 && (
|
||||
<WarningMessage
|
||||
message={localeString('views.TxHex.channelWarning')}
|
||||
fontSize={13}
|
||||
/>
|
||||
)}
|
||||
{!loading &&
|
||||
pending_chan_ids.length === 0 &&
|
||||
!this.props.route.params?.hideWarning && (
|
||||
<WarningMessage
|
||||
message={localeString(
|
||||
'views.TxHex.channelWarning'
|
||||
)}
|
||||
fontSize={13}
|
||||
/>
|
||||
)}
|
||||
{loading && (
|
||||
<View style={{ margin: 15 }}>
|
||||
<LoadingIndicator />
|
||||
|
||||
Reference in New Issue
Block a user