Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
93dd1ff
Copy bitcoin to litecoin
hectorchu Sep 9, 2025
aba259a
Add cw_mweb
hectorchu Sep 9, 2025
7f2d4ba
Build fixes
hectorchu Sep 9, 2025
0107963
Remove cw_core dep
hectorchu Sep 9, 2025
8ff7ab3
Add rpcs
hectorchu Sep 9, 2025
4335125
More stuff
hectorchu Sep 9, 2025
58950ab
update
hectorchu Sep 9, 2025
eaf0b5e
more stuff
hectorchu Sep 9, 2025
9bd7673
fix more build
hectorchu Sep 9, 2025
9baabae
fix build
hectorchu Sep 9, 2025
4d4fa15
oops
hectorchu Sep 9, 2025
858df23
Update proto
hectorchu Sep 9, 2025
516953d
more changes
hectorchu Sep 9, 2025
1b6088c
Update proto
hectorchu Sep 10, 2025
05e60d6
Add pubkey to index map
hectorchu Sep 10, 2025
0e434b4
Sign non mweb inputs
hectorchu Sep 10, 2025
3ef30af
small fix
hectorchu Sep 10, 2025
53e4456
Bump mwebd
hectorchu Sep 10, 2025
c39b021
update publicuri
hectorchu Sep 10, 2025
0b1e066
fix xpub
hectorchu Sep 10, 2025
c3a925e
Bump mwebd
hectorchu Sep 11, 2025
2011271
fixes
hectorchu Sep 12, 2025
db3c566
Show error from mwebd start
hectorchu Sep 12, 2025
7012a28
Bump mwebd
hectorchu Sep 12, 2025
cf8c3e4
Use unix socket for mwebd
hectorchu Sep 12, 2025
71e0984
Start mwebd early
hectorchu Sep 13, 2025
68b82c1
Remove artificial delay
hectorchu Sep 13, 2025
21e6135
Fixed unconfirmed transaction view mounting issues
hectorchu Sep 13, 2025
8ed1352
Bump mwebd
hectorchu Sep 13, 2025
289dded
switch to new rpc
hectorchu Sep 13, 2025
0a0af19
silly fix
hectorchu Sep 13, 2025
0477770
Bump mwebd
hectorchu Sep 14, 2025
0fb9be6
Don't eat psbt rpc errors
hectorchu Sep 14, 2025
efdda33
fix long line
hectorchu Sep 14, 2025
359f085
fix: don't estabilish connections
MrCyjaneK Oct 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions .github/workflows/build_release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ on: [push]
jobs:
app_android:
runs-on: ubuntu-latest
env:
ANDROID_NDK_VERSION: 28.2.13676358
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -20,14 +22,17 @@ jobs:
with:
distribution: 'zulu'
java-version: '17'
- name: Flutter pub get
- name: Git submodule update
run: |
flutter pub get
- name: Prepare dev
run: ./.tooling/prepare_dev.sh
git submodule update --init --recursive
- name: Build monero_c
run: |
make libs_android_download
- name: Flutter pub get
run: |
flutter pub get
- name: Prepare dev
run: make prepare_dev
- name: Build apk
run: |
flutter build apk --profile
Expand Down
11 changes: 10 additions & 1 deletion .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ on: [push]

jobs:
format:
runs-on: ubuntu-22.04
runs-on: ubuntu-latest
env:
ANDROID_NDK_VERSION: 28.2.13676358
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -20,6 +22,13 @@ jobs:
with:
distribution: 'zulu'
java-version: '17'
- name: Git submodule update
run: |
git submodule update --init --recursive
- name: Build monero_c
run: |
make libs_android_download

- name: Flutter pub get
run: |
flutter pub get
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "external/cake_wallet"]
path = external/cake_wallet
url = https://github.com/cake-tech/cake_wallet
4 changes: 2 additions & 2 deletions .tooling/format.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pushd lib/l10n
popd

dart run build_runner build --delete-conflicting-outputs
dart fix --apply .
dart format .
dart fix --apply lib/
dart format lib/

flutter gen-l10n
27 changes: 16 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
include .env
UNAME := $(shell uname)

libs_android_download:
libs_android_download: mwebd_android
./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet x86_64-linux-android --location android/app/src/main/jniLibs/x86_64
./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-linux-android --location android/app/src/main/jniLibs/arm64-v8a
./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet armv7a-linux-androideabi --location android/app/src/main/jniLibs/armeabi-v7a

libs_android_build:
libs_android_build: mwebd_android
ifneq ($(UNAME), Linux)
echo Only Linux hosts can build for android, try $(MAKE) libs_android_download
exit 1
Expand All @@ -15,15 +15,15 @@ endif
./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-linux-android --location android/app/src/main/jniLibs/arm64-v8a
./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet armv7a-linux-androideabi --location android/app/src/main/jniLibs/armeabi-v7a

libs_android_build_ci:
libs_android_build_ci: mwebd_android
./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-linux-android --location android/app/src/main/jniLibs/arm64-v8a

libs_ios_download:
libs_ios_download: mwebd_ios
./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-apple-ios --location ios/native_libs/ios-arm64
./build_moneroc.sh --prebuild --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-apple-iossimulator --location ios/native_libs/ios-arm64-simulator
cd ios && ./gen_framework.sh

libs_ios_build:
libs_ios_build: mwebd_ios
ifneq ($(UNAME), Darwin)
echo Only Darwin hosts can build for iOS, try $(MAKE) libs_ios_download
exit 1
Expand All @@ -32,13 +32,18 @@ endif
./build_moneroc.sh --coin ${COIN} --tag ${MONERO_C_TAG} --triplet aarch64-apple-iossimulator --location ios/native_libs/ios-arm64-simulator
cd ios && ./gen_framework.sh

cupcake_android_monero:
dart run build_runner build --delete-conflicting-outputs
flutter build apk --dart-define=COIN_MONERO=true
cupcake_android:
flutter build apk

cupcake_ios_monero:
dart run build_runner build --delete-conflicting-outputs
flutter build ios --no-codesign --dart-define=COIN_MONERO=true
cupcake_ios:
flutter build ios --no-codesign

mwebd_android:
cd external/cake_wallet/scripts/android && bash ./build_mwebd.sh --dont-install

mwebd_ios:
cd external/cake_wallet/scripts/ios && bash ./build_mwebd.sh --dont-install

prepare_dev:
cd external/cake_wallet/scripts && bash ./prepare_torch.sh
./.tooling/prepare_dev.sh
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ To build:
```bash
$ make libs_android_build # or libs_android_download, libs_ios_build, libs_ios_download
$ make prepare_dev # load dev signing key (not required on iOS)
$ make cupcake_android_monero # or cupcake_
$ make cupcake_android # or cupcake_ios
```

### Adding other coins
Expand Down
2 changes: 2 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ analyzer:
overridden_fields: ignore
exclude:
- '**.g.dart'
- 'external/**'

include: package:flutter_lints/flutter.yaml

linter:
Expand Down
1 change: 1 addition & 0 deletions assets/coins/ltc.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions external/cake_wallet
Submodule cake_wallet added at 3baea4
2 changes: 1 addition & 1 deletion lib/coins/abstract/coin.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:cupcake/coins/abstract/wallet_info.dart';
import 'package:cupcake/l10n/app_localizations.dart';
import 'package:flutter/cupertino.dart';

enum Coins { monero, bitcoin, unknown }
enum Coins { monero, bitcoin, litecoin, unknown }

abstract class Coin {
static late AppLocalizations L;
Expand Down
3 changes: 3 additions & 0 deletions lib/coins/abstract/wallet_info.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import 'package:cupcake/coins/abstract/coin.dart';
import 'package:cupcake/coins/abstract/wallet.dart';
import 'package:cupcake/coins/bitcoin/wallet_info.dart';
import 'package:cupcake/coins/litecoin/wallet_info.dart';
import 'package:cupcake/coins/monero/wallet_info.dart';
import 'package:cupcake/utils/config.dart';
import 'package:flutter/widgets.dart';
Expand Down Expand Up @@ -41,6 +42,8 @@ abstract class CoinWalletInfo {
return MoneroWalletInfo(walletName);
case Coins.bitcoin:
return BitcoinWalletInfo(walletName);
case Coins.litecoin:
return LitecoinWalletInfo(walletName);
case Coins.unknown:
throw UnimplementedError("unknown coin");
}
Expand Down
2 changes: 1 addition & 1 deletion lib/coins/bitcoin/wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ class BitcoinWallet implements CoinWallet {
currentWallet: this,
).pushReplacement(context);
},
cancelCallback: () => Navigator.of(context).pop(),
cancelCallback: (final BuildContext context) => Navigator.of(context).pop(),
).pushReplacement(context);
break;
default:
Expand Down
3 changes: 3 additions & 0 deletions lib/coins/list.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
import 'package:cupcake/coins/abstract/coin.dart';
import 'package:cupcake/coins/bitcoin/coin.dart';
import 'package:cupcake/coins/litecoin/coin.dart';
import 'package:cupcake/coins/monero/coin.dart';

const moneroEnabled = bool.fromEnvironment("COIN_MONERO", defaultValue: true);
const bitcoinEnabled = bool.fromEnvironment("COIN_BITCOIN", defaultValue: true);
const litecoinEnabled = bool.fromEnvironment("COIN_LITECOIN", defaultValue: true);

// This needs to be a global variable, I'm hoping for it to be tree-shaken, and save us some time
// on generating imports dynamically.

final List<Coin> walletCoins = [
if (moneroEnabled) Monero(),
if (bitcoinEnabled) Bitcoin(),
if (litecoinEnabled) Litecoin(),
];
8 changes: 8 additions & 0 deletions lib/coins/litecoin/address.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import 'package:cupcake/coins/abstract/address.dart';

class LitecoinAddress2 implements Address {
LitecoinAddress2(this.address);

@override
final String address;
}
10 changes: 10 additions & 0 deletions lib/coins/litecoin/amount.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import 'package:cupcake/coins/abstract/amount.dart';

class LitecoinAmount implements Amount {
LitecoinAmount(this.amount);
@override
final int amount;

@override
String toString() => (amount / 1e8).toStringAsFixed(8);
}
87 changes: 87 additions & 0 deletions lib/coins/litecoin/coin.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import 'dart:async';
import 'dart:io';

import 'package:cupcake/coins/abstract/coin.dart';
import 'package:cupcake/coins/abstract/strings.dart';
import 'package:cupcake/coins/abstract/wallet.dart';
import 'package:cupcake/coins/abstract/wallet_creation.dart';
import 'package:cupcake/coins/abstract/wallet_info.dart';
import 'package:cupcake/coins/litecoin/creation/common.dart';
import 'package:cupcake/coins/litecoin/strings.dart';
import 'package:cupcake/coins/litecoin/wallet.dart';
import 'package:cupcake/coins/litecoin/wallet_info.dart';
import 'package:cupcake/l10n/app_localizations.dart';
import 'package:cupcake/utils/encryption/default.dart';
import 'package:cupcake/utils/filesystem.dart';
import 'package:flutter/material.dart';
import 'package:path/path.dart' as p;

class Litecoin implements Coin {
Litecoin();
@override
String get uriScheme => 'litecoin';

@override
bool get isEnabled => true;

@override
CoinStrings get strings => LitecoinStrings();

static final baseDir = Directory(p.join(baseStoragePath, LitecoinStrings().symbolLowercase));

@override
Future<List<CoinWalletInfo>> get coinWallets {
if (!baseDir.existsSync()) {
baseDir.createSync(recursive: true);
}
final List<CoinWalletInfo> retWallets = [];
final list = baseDir.listSync(recursive: true, followLinks: true);
for (final element in list) {
if (!element.absolute.path.endsWith(".keys")) continue;
retWallets.add(LitecoinWalletInfo(element.absolute.path));
}
return Future.value(retWallets);
}

@override
String getPathForWallet(final String walletName) {
if (!baseDir.existsSync()) {
baseDir.createSync(recursive: true);
}

// Prevent user from slipping outside allowed directory
final String walletPath = p.join(baseDir.path, walletName);
if (!walletPath.startsWith(baseDir.path)) {
throw Exception(Coin.L.error_illegal_wallet_name(walletName));
}
return walletPath;
}

@override
Future<CoinWallet> openWallet(
final CoinWalletInfo walletInfo, {
required final String password,
}) async {
final encrypted = File("${walletInfo.walletName}.keys").readAsBytesSync();
final mnemonic = DefaultEncryption().decryptString(encrypted, password);
return LitecoinWallet(
seed: mnemonic,
walletName: walletInfo.walletName,
);
}

@override
Coins get type => Coins.litecoin;

@override
bool isSeedSomewhatLegit(final String seed) {
final length = seed.split(" ").length;
return [12, 18, 24].contains(length);
}

@override
WalletCreation creationMethod(final AppLocalizations L) => LitecoinWalletCreation(L);

@override
Map<String, Function(BuildContext context, CoinWallet wallet)> debugOptions = {};
}
83 changes: 83 additions & 0 deletions lib/coins/litecoin/creation/common.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import 'package:cupcake/coins/abstract/coin.dart';
import 'package:cupcake/coins/abstract/wallet_creation.dart';
import 'package:cupcake/coins/litecoin/coin.dart';
import 'package:cupcake/coins/litecoin/creation/new_wallet.dart';
import 'package:cupcake/coins/litecoin/creation/restore_wallet.dart';
import 'package:cupcake/l10n/app_localizations.dart';
import 'package:cupcake/utils/form/abstract_form_element.dart';
import 'package:cupcake/utils/form/string_form_element.dart';
import 'package:cupcake/utils/form/validators.dart';
import 'package:cupcake/utils/types.dart';

class LitecoinWalletCreation extends WalletCreation {
factory LitecoinWalletCreation(final AppLocalizations L) {
_instance ??= LitecoinWalletCreation._internal(L);
return _instance!;
}
LitecoinWalletCreation._internal(this.L);
static LitecoinWalletCreation? _instance;

final AppLocalizations L;

Future<void> errorHandler(final Object error) async {
print("error: $error");
return;
}

late StringFormElement seed = StringFormElement(
L.wallet_seed,
password: false,
validator: nonEmptyValidator(
L,
extra: (final input) =>
!(Litecoin().isSeedSomewhatLegit(input)) ? L.warning_seed_incorrect_length : null,
),
errorHandler: errorHandler,
canPaste: true,
);

late List<FormElement> createForm = [];
late List<FormElement> restoreForm = [seed];

@override
Future<CreationOutcome?> create(
final CreateMethod createMethod,
final String walletName,
final String walletPassword,
) async {
return switch (createMethod) {
CreateMethod.create => CreateLitecoinWalletCreationMethod(
L,
walletPath: coin.getPathForWallet(walletName),
walletPassword: walletPassword,
).create(),
CreateMethod.restore => RestoreLitecoinWalletCreationMethod(
L,
walletPath: coin.getPathForWallet(walletName),
walletPassword: walletPassword,
seed: await seed.value,
).create(),
};
}

@override
Map<String, WalletCreationForm> createMethods(
final CreateMethod createMethod,
) =>
{
if ([CreateMethod.create].contains(createMethod))
L.option_create_new_wallet: WalletCreationForm(
method: CreateMethod.create,
form: createForm,
),
if ([CreateMethod.restore].contains(createMethod)) ...{
L.option_create_seed: WalletCreationForm(method: CreateMethod.restore, form: restoreForm),
},
};

@override
void wipe() {}

@override
Coin get coin => Litecoin();
}
Loading
Loading