Compare commits

...

10 Commits

Author SHA1 Message Date
dsc fd50aa9db5 Such Wow, Many Cake. Om nom
4 months ago
Omar Hatem d756b367d3
Make the exchange receive field always editable and can be taken from QR or Address book (#1230)
5 months ago
Matthew Fosse 2ff81df9e7
CW-512 wallet sort (#1195)
5 months ago
Serhii 049e4def27
fix accessibility issues (#1224)
5 months ago
Serhii faf151a4dc
CW-531-Bitcoin-Fees-issue (#1218)
5 months ago
Adegoke David ef7762eaca
Polygon-Wallet-fixes (#1222)
5 months ago
Matthew Fosse 7ce387c130
fix dot indicator color (#1228)
5 months ago
Konstantin Ullrich 72777fbf2c
Cw 534 monero wallet generic enhancements (#1225)
5 months ago
Serhii 2138c35e38
CW-532-DFX-buy-provider (#1209)
5 months ago
Matthew Fosse d370c754c5
allow manual builds on any branch (#1219)
5 months ago

@ -3,6 +3,12 @@ name: PR Test Build
on:
pull_request:
branches: [main]
workflow_dispatch:
inputs:
branch:
description: 'Branch name to build'
required: true
default: 'main'
jobs:
PR_test_build:
@ -12,6 +18,14 @@ jobs:
KEY_PASS: test@cake_wallet
steps:
- name: is pr
if: github.event_name == 'pull_request'
run: echo "BRANCH_NAME=${GITHUB_HEAD_REF}" >> $GITHUB_ENV
- name: is not pr
if: github.event_name != 'pull_request'
run: echo "BRANCH_NAME=${{ github.event.inputs.branch }}" >> $GITHUB_ENV
- name: Free Up GitHub Actions Ubuntu Runner Disk Space
run: |
sudo rm -rf /usr/share/dotnet
@ -40,7 +54,7 @@ jobs:
cd /opt/android
-y curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install cargo-ndk
git clone https://github.com/cake-tech/cake_wallet.git --branch $GITHUB_HEAD_REF
git clone https://github.com/cake-tech/cake_wallet.git --branch ${{ env.BRANCH_NAME }}
cd cake_wallet/scripts/android/
./install_ndk.sh
source ./app_env.sh cakewallet
@ -105,6 +119,7 @@ jobs:
cd /opt/android/cake_wallet
touch lib/.secrets.g.dart
touch cw_ethereum/lib/.secrets.g.dart
touch cw_polygon/lib/.secrets.g.dart
echo "const salt = '${{ secrets.SALT }}';" > lib/.secrets.g.dart
echo "const keychainSalt = '${{ secrets.KEY_CHAIN_SALT }}';" >> lib/.secrets.g.dart
echo "const key = '${{ secrets.KEY }}';" >> lib/.secrets.g.dart
@ -132,16 +147,16 @@ jobs:
echo "const fiatApiKey = '${{ secrets.FIAT_API_KEY }}';" >> lib/.secrets.g.dart
echo "const payfuraApiKey = '${{ secrets.PAYFURA_API_KEY }}';" >> lib/.secrets.g.dart
echo "const etherScanApiKey = '${{ secrets.ETHER_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
echo "const chatwootWebsiteToken = '${{ secrets.CHATWOOT_WEBSITE_TOKEN }}';" >> lib/.secrets.g.dart
echo "const exolixApiKey = '${{ secrets.EXOLIX_API_KEY }}';" >> lib/.secrets.g.dart
echo "const robinhoodApplicationId = '${{ secrets.ROBINHOOD_APPLICATION_ID }}';" >> lib/.secrets.g.dart
echo "const robinhoodCIdApiSecret = '${{ secrets.ROBINHOOD_CID_CLIENT_SECRET }}';" >> lib/.secrets.g.dart
echo "const walletConnectProjectId = '${{ secrets.WALLET_CONNECT_PROJECT_ID }}';" >> lib/.secrets.g.dart
echo "const moralisApiKey = '${{ secrets.MORALIS_API_KEY }}';" >> lib/.secrets.g.dart
echo "const polygonScanApiKey = '${{ secrets.POLYGON_SCAN_API_KEY }}';" >> cw_ethereum/lib/.secrets.g.dart
- name: Rename app
run: echo -e "id=com.cakewallet.test\nname=$GITHUB_HEAD_REF" > /opt/android/cake_wallet/android/app.properties
run: echo -e "id=com.cakewallet.test\nname=${{ env.BRANCH_NAME }}" > /opt/android/cake_wallet/android/app.properties
- name: Build
run: |
@ -156,7 +171,7 @@ jobs:
# appcenter distribute release \
# --group "Testers" \
# --file "/opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk" \
# --release-notes ${GITHUB_HEAD_REF} \
# --release-notes ${{ env.BRANCH_NAME }} \
# --app Cake-Labs/Cake-Wallet \
# --token ${{ secrets.APP_CENTER_TOKEN }} \
# --quiet
@ -165,7 +180,7 @@ jobs:
run: |
cd /opt/android/cake_wallet/build/app/outputs/apk/release
mkdir test-apk
cp app-release.apk test-apk/$GITHUB_HEAD_REF.apk
cp app-release.apk test-apk/${{env.BRANCH_NAME}}.apk
- name: Upload Artifact
uses: kittaakos/upload-artifact-as-is@v0
@ -179,6 +194,6 @@ jobs:
token: ${{ secrets.SLACK_APP_TOKEN }}
path: /opt/android/cake_wallet/build/app/outputs/apk/release/app-release.apk
channel: ${{ secrets.SLACK_APK_CHANNEL }}
title: "${{github.head_ref}}.apk"
filename: ${{github.head_ref}}.apk
title: "${{ env.BRANCH_NAME }}.apk"
filename: ${{ env.BRANCH_NAME }}.apk
initial_comment: ${{ github.event.head_commit.message }}

5
.gitignore vendored

@ -119,10 +119,15 @@ cw_shared_external/ios/External/
cw_haven/ios/External/
cw_haven/android/.externalNativeBuild/
cw_haven/android/.cxx/
# cw_wownero/**
cw_wownero/ios/External/
cw_wownero/android/.externalNativeBuild/
cw_wownero/android/.cxx/
lib/bitcoin/bitcoin.dart
lib/monero/monero.dart
lib/haven/haven.dart
lib/wownero/wownero.dart
lib/ethereum/ethereum.dart
lib/bitcoin_cash/bitcoin_cash.dart
lib/nano/nano.dart

@ -6,6 +6,7 @@ analyzer:
lib/**.g.dart,
cw_core/lib/**.g.dart,
cw_haven/lib/**.g.dart,
cw_wownero/lib/**.g.dart,
cw_monero/lib/**.g.dart,
lib/generated/*.dart,
cw_monero/ios/External/**,

@ -0,0 +1,11 @@
package com.cakewallet.wownero;
import io.flutter.app.FlutterApplication;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.PluginRegistrantCallback;
import io.flutter.plugins.GeneratedPluginRegistrant;
public class Application extends FlutterApplication implements PluginRegistrantCallback {
@Override
public void registerWith(PluginRegistry registry) {}
}

@ -0,0 +1,90 @@
package com.cakewallet.wownero;
import androidx.annotation.NonNull;
import io.flutter.embedding.android.FlutterFragmentActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.view.WindowManager;
import com.unstoppabledomains.resolution.DomainResolution;
import com.unstoppabledomains.resolution.Resolution;
import java.security.SecureRandom;
public class MainActivity extends FlutterFragmentActivity {
final String UTILS_CHANNEL = "com.cake_wallet/native_utils";
final int UNSTOPPABLE_DOMAIN_MIN_VERSION_SDK = 24;
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
MethodChannel utilsChannel =
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(),
UTILS_CHANNEL);
utilsChannel.setMethodCallHandler(this::handle);
}
private void handle(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
Handler handler = new Handler(Looper.getMainLooper());
try {
switch (call.method) {
case "enableWakeScreen":
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
handler.post(() -> result.success(true));
break;
case "disableWakeScreen":
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
handler.post(() -> result.success(true));
break;
case "sec_random":
int count = call.argument("count");
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[count];
random.nextBytes(bytes);
handler.post(() -> result.success(bytes));
break;
case "getUnstoppableDomainAddress":
int version = Build.VERSION.SDK_INT;
if (version >= UNSTOPPABLE_DOMAIN_MIN_VERSION_SDK) {
getUnstoppableDomainAddress(call, result);
} else {
handler.post(() -> result.success(""));
}
break;
default:
handler.post(() -> result.notImplemented());
}
} catch (Exception e) {
handler.post(() -> result.error("UNCAUGHT_ERROR", e.getMessage(), null));
}
}
private void getUnstoppableDomainAddress(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
DomainResolution resolution = new Resolution();
Handler handler = new Handler(Looper.getMainLooper());
String domain = call.argument("domain");
String ticker = call.argument("ticker");
AsyncTask.execute(() -> {
try {
String address = resolution.getAddress(domain, ticker);
handler.post(() -> result.success(address));
} catch (Exception e) {
System.out.println("Expected Address, but got " + e.getMessage());
handler.post(() -> result.success(""));
}
});
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

@ -1,6 +1,6 @@
-
uri: polygon-rpc.com
-
uri: polygon-bor.publicnode.com
-
uri: polygon-rpc.com
-
uri: polygon.llamarpc.com

@ -0,0 +1,16 @@
-
uri: nyc.muchwow.lol:34568
is_default: true
useSSL: false
-
uri: amsterdam.muchwow.lol:34568
is_default: false
useSSL: false
-
uri: singapore.muchwow.lol:34568
is_default: false
useSSL: false
-
uri: suchwow.xyz:34568
is_default: false
useSSL: false

@ -7,6 +7,7 @@ cd cw_core && flutter pub get && flutter packages pub run build_runner build --d
cd cw_monero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_bitcoin && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_haven && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_wownero && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_ethereum && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_nano && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..
cd cw_bitcoin_cash && flutter pub get && flutter packages pub run build_runner build --delete-conflicting-outputs && cd ..

@ -4,7 +4,10 @@ import 'package:cw_bitcoin/bitcoin_amount_format.dart';
import 'package:cw_core/balance.dart';
class ElectrumBalance extends Balance {
const ElectrumBalance({required this.confirmed, required this.unconfirmed, required this.frozen})
const ElectrumBalance(
{required this.confirmed,
required this.unconfirmed,
required this.frozen})
: super(confirmed, unconfirmed);
static ElectrumBalance? fromJSON(String? jsonSource) {
@ -25,16 +28,19 @@ class ElectrumBalance extends Balance {
final int frozen;
@override
String get formattedAvailableBalance => bitcoinAmountToString(amount: confirmed - frozen);
String get formattedAvailableBalance =>
bitcoinAmountToString(amount: confirmed - unconfirmed.abs() - frozen);
@override
String get formattedAdditionalBalance => bitcoinAmountToString(amount: unconfirmed);
String get formattedAdditionalBalance =>
bitcoinAmountToString(amount: unconfirmed);
String get formattedFrozenBalance {
@override
String get formattedUnAvailableBalance {
final frozenFormatted = bitcoinAmountToString(amount: frozen);
return frozenFormatted == '0.0' ? '' : frozenFormatted;
}
String toJSON() =>
json.encode({'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen});
String toJSON() => json.encode(
{'confirmed': confirmed, 'unconfirmed': unconfirmed, 'frozen': frozen});
}

@ -82,7 +82,7 @@ abstract class ElectrumWalletBase
bitcoin.HDWallet.fromSeed(seedBytes).derivePath("m/44'/145'/0'/0");
static int estimatedTransactionSize(int inputsCount, int outputsCounts) =>
inputsCount * 146 + outputsCounts * 33 + 8;
inputsCount * 68 + outputsCounts * 34 + 10;
final bitcoin.HDWallet hd;
final String mnemonic;
@ -725,8 +725,7 @@ abstract class ElectrumWalletBase
final index = address != null
? walletAddresses.addresses.firstWhere((element) => element.address == address).index
: null;
return index == null
? base64Encode(hd.sign(message))
: base64Encode(hd.derive(index).sign(message));
final HD = index == null ? hd : hd.derive(index);
return base64Encode(HD.signMessage(message));
}
}

@ -79,11 +79,11 @@ packages:
dependency: "direct main"
description:
path: "."
ref: cake-update-v3
resolved-ref: df9204144011ed9419eff7d9ef3143102a40252d
ref: cake-update-v4
resolved-ref: e19ffb7e7977278a75b27e0479b3c6f4034223b3
url: "https://github.com/cake-tech/bitcoin_flutter.git"
source: git
version: "2.0.2"
version: "2.1.0"
boolean_selector:
dependency: transitive
description:
@ -244,7 +244,7 @@ packages:
source: hosted
version: "2.2.4"
encrypt:
dependency: "direct main"
dependency: transitive
description:
name: encrypt
sha256: "4fd4e4fdc21b9d7d4141823e1e6515cd94e7b8d84749504c232999fba25d9bbb"
@ -698,15 +698,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
tor:
dependency: transitive
description:
path: "."
ref: main
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
url: "https://github.com/cake-tech/tor.git"
source: git
version: "0.0.1"
typed_data:
dependency: transitive
description:
@ -735,10 +726,10 @@ packages:
dependency: transitive
description:
name: watcher
sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.0"
web_socket_channel:
dependency: transitive
description:

@ -22,7 +22,7 @@ dependencies:
bitcoin_flutter:
git:
url: https://github.com/cake-tech/bitcoin_flutter.git
ref: cake-update-v3
ref: cake-update-v4
bitbox:
git:
url: https://github.com/cake-tech/bitbox-flutter.git

@ -302,10 +302,8 @@ abstract class BitcoinCashWalletBase extends ElectrumWallet with Store {
final index = address != null
? walletAddresses.addresses
.firstWhere((element) => element.address == AddressUtils.toLegacyAddress(address))
.index
: null;
return index == null
? base64Encode(hd.sign(message))
: base64Encode(hd.derive(index).sign(message));
.index : null;
final HD = index == null ? hd : hd.derive(index);
return base64Encode(HD.signMessage(message));
}
}

@ -24,7 +24,7 @@ dependencies:
bitcoin_flutter:
git:
url: https://github.com/cake-tech/bitcoin_flutter.git
ref: cake-update-v3
ref: cake-update-v4
bitbox:
git:
url: https://github.com/cake-tech/bitbox-flutter.git

@ -4,6 +4,8 @@ import 'package:cw_core/crypto_currency.dart';
class AmountConverter {
static const _moneroAmountLength = 12;
static const _moneroAmountDivider = 1000000000000;
static const _wowneroAmountLength = 11;
static const _wowneroAmountDivider = 100000000000;
static const _litecoinAmountDivider = 100000000;
static const _ethereumAmountDivider = 1000000000000000000;
static const _dashAmountDivider = 100000000;
@ -16,6 +18,9 @@ class AmountConverter {
static final _moneroAmountFormat = NumberFormat()
..maximumFractionDigits = _moneroAmountLength
..minimumFractionDigits = 1;
static final _wowneroAmountFormat = NumberFormat()
..maximumFractionDigits = _wowneroAmountLength
..minimumFractionDigits = 1;
static double amountIntToDouble(CryptoCurrency cryptoCurrency, int amount) {
switch (cryptoCurrency) {
@ -23,6 +28,8 @@ class AmountConverter {
return _moneroAmountToDouble(amount);
case CryptoCurrency.btc:
return _bitcoinAmountToDouble(amount);
case CryptoCurrency.wow:
return _wowneroAmountToDouble(amount);
case CryptoCurrency.bch:
return _bitcoinCashAmountToDouble(amount);
case CryptoCurrency.dash:
@ -55,6 +62,8 @@ class AmountConverter {
switch (cryptoCurrency) {
case CryptoCurrency.xmr:
return _moneroParseAmount(amount);
case CryptoCurrency.wow:
return _wowneroParseAmount(amount);
case CryptoCurrency.xhv:
case CryptoCurrency.xag:
case CryptoCurrency.xau:
@ -82,6 +91,8 @@ class AmountConverter {
case CryptoCurrency.btc:
case CryptoCurrency.bch:
return _bitcoinAmountToString(amount);
case CryptoCurrency.wow:
return _wowneroAmountToString(amount);
case CryptoCurrency.xhv:
case CryptoCurrency.xag:
case CryptoCurrency.xau:
@ -114,6 +125,15 @@ class AmountConverter {
static int _moneroParseAmount(String amount) =>
_moneroAmountFormat.parse(amount).toInt();
static String _wowneroAmountToString(int amount) => _wowneroAmountFormat.format(
cryptoAmountToDouble(amount: amount, divider: _wowneroAmountDivider));
static double _wowneroAmountToDouble(int amount) =>
cryptoAmountToDouble(amount: amount, divider: _wowneroAmountDivider);
static int _wowneroParseAmount(String amount) =>
_wowneroAmountFormat.parse(amount).toInt();
static String _bitcoinAmountToString(int amount) =>
_bitcoinAmountFormat.format(
cryptoAmountToDouble(amount: amount, divider: _bitcoinAmountDivider));

@ -36,6 +36,7 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
CryptoCurrency.xlm,
CryptoCurrency.xrp,
CryptoCurrency.xhv,
CryptoCurrency.wow,
CryptoCurrency.ape,
CryptoCurrency.avaxc,
CryptoCurrency.btt,
@ -93,6 +94,8 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
CryptoCurrency.dydx,
CryptoCurrency.steth,
CryptoCurrency.banano,
CryptoCurrency.usdtPoly,
CryptoCurrency.usdcEPoly,
];
static const havenCurrencies = [
@ -202,7 +205,9 @@ class CryptoCurrency extends EnumerableItem<int> with Serializable<int> implemen
static const dydx = CryptoCurrency(title: 'DYDX', tag: 'ETH', fullName: 'dYdX', raw: 84, name: 'dydx', iconPath: 'assets/images/dydx_icon.png', decimals: 18);
static const steth = CryptoCurrency(title: 'STETH', tag: 'ETH', fullName: 'Lido Staked Ethereum', raw: 85, name: 'steth', iconPath: 'assets/images/steth_icon.png', decimals: 18);
static const banano = CryptoCurrency(title: 'BAN', fullName: 'Banano', raw: 86, name: 'banano', iconPath: 'assets/images/nano_icon.png', decimals: 29);
static const usdtPoly = CryptoCurrency(title: 'USDT', tag: 'POLY', fullName: 'Tether USD (PoS)', raw: 87, name: 'usdtpoly', iconPath: 'assets/images/usdt_icon.png', decimals: 6);
static const usdcEPoly = CryptoCurrency(title: 'USDC.E', tag: 'POLY', fullName: 'USD Coin (PoS)', raw: 88, name: 'usdcepoly', iconPath: 'assets/images/usdc_icon.png', decimals: 6);
static const wow = CryptoCurrency(title: 'WOW', fullName: 'Wownero', raw: 89, name: 'wow', iconPath: 'assets/images/wownero_icon.png', decimals: 12);
static final Map<int, CryptoCurrency> _rawCurrencyMap =
[...all, ...havenCurrencies].fold<Map<int, CryptoCurrency>>(<int, CryptoCurrency>{}, (acc, item) {

@ -11,6 +11,8 @@ CryptoCurrency currencyForWalletType(WalletType type) {
return CryptoCurrency.ltc;
case WalletType.haven:
return CryptoCurrency.xhv;
case WalletType.wownero:
return CryptoCurrency.wow;
case WalletType.ethereum:
return CryptoCurrency.eth;
case WalletType.bitcoinCash:

@ -18,6 +18,8 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
bool _enabled;
@HiveField(5)
final String? iconPath;
@HiveField(6)
final String? tag;
bool get enabled => _enabled;
@ -30,30 +32,31 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
required this.decimal,
bool enabled = true,
this.iconPath,
this.tag,
}) : _enabled = enabled,
super(
name: symbol.toLowerCase(),
title: symbol.toUpperCase(),
fullName: name,
tag: "ETH",
iconPath: iconPath,
decimals: decimal
);
name: symbol.toLowerCase(),
title: symbol.toUpperCase(),
fullName: name,
tag: tag,
iconPath: iconPath,
decimals: decimal);
Erc20Token.copyWith(Erc20Token other, String? icon)
Erc20Token.copyWith(Erc20Token other, String? icon, String? tag)
: this.name = other.name,
this.symbol = other.symbol,
this.contractAddress = other.contractAddress,
this.decimal = other.decimal,
this._enabled = other.enabled,
this.tag = tag,
this.iconPath = icon,
super(
name: other.name,
title: other.symbol.toUpperCase(),
fullName: other.name,
tag: "ETH",
tag: tag,
iconPath: icon,
decimals: other.decimal
decimals: other.decimal,
);
static const typeId = ERC20_TOKEN_TYPE_ID;
@ -61,7 +64,8 @@ class Erc20Token extends CryptoCurrency with HiveObjectMixin {
static const polygonBoxName = ' PolygonErc20Tokens';
@override
bool operator ==(other) => (other is Erc20Token && other.contractAddress == contractAddress) ||
bool operator ==(other) =>
(other is Erc20Token && other.contractAddress == contractAddress) ||
(other is CryptoCurrency && other.title == title);
@override

@ -223,6 +223,76 @@ const havenDates = {
"2018-03": 8500
};
const wowDates = {
"2023-12": 583048,
"2023-11": 575048,
"2023-10": 566048,
"2023-09": 558048,
"2023-08": 549048,
"2023-07": 540048,
"2023-06": 532048,
"2023-05": 523048,
"2023-04": 514048,
"2023-03": 505048,
"2023-02": 497048,
"2023-01": 488048,
"2022-12": 479048,
"2022-11": 471048,
"2022-10": 462048,
"2022-09": 453048,
"2022-08": 444048,
"2022-07": 435048,
"2022-06": 427048,
"2022-05": 418048,
"2022-04": 410048,
"2022-03": 401048,
"2022-02": 393048,
"2022-01": 384048,
"2021-12": 375048,
"2021-11": 367048,
"2021-10": 358048,
"2021-09": 349048,
"2021-08": 340048,
"2021-07": 331048,
"2021-06": 322048,
"2021-05": 313048,
"2021-04": 305048,
"2021-03": 295048,
"2021-02": 287048,
"2021-01": 279148,
"2020-10": 252000,
"2020-09": 243000,
"2020-08": 234000,
"2020-07": 225000,
"2020-06": 217500,
"2020-05": 208500,
"2020-04": 199500,
"2020-03": 190500,
"2020-02": 183000,
"2020-01": 174000,
"2019-12": 165000,
"2019-11": 156000,
"2019-10": 147000,
"2019-09": 138000,
"2019-08": 129000,
"2019-07": 120000,
"2019-06": 112500,
"2019-05": 103500,
"2019-04": 94500,
"2019-03": 85500,
"2019-02": 79500,
"2019-01": 73500,
"2018-12": 67500,
"2018-11": 61500,
"2018-10": 52500,
"2018-09": 45000,
"2018-08": 36000,
"2018-07": 27000,
"2018-06": 18000,
"2018-05": 9000,
"2018-04": 1
};
DateTime formatMapKey(String key) => dateFormat.parse(key);
int getHavenHeightByDate({required DateTime date}) {
@ -232,6 +302,13 @@ int getHavenHeightByDate({required DateTime date}) {
return havenDates[closestKey] ?? 0;
}
int getWowneroHeightByDate({required DateTime date}) {
String closestKey =
wowDates.keys.firstWhere((key) => formatMapKey(key).isBefore(date), orElse: () => '');
return wowDates[closestKey] ?? 0;
}
Future<int> getHavenCurrentHeight() async {
final response = await http.get(Uri.parse('https://explorer.havenprotocol.org/api/networkinfo'));

@ -77,6 +77,8 @@ class Node extends HiveObject with Keyable {
return createUriFromElectrumAddress(uriRaw);
case WalletType.haven:
return Uri.http(uriRaw, '');
case WalletType.wownero:
return Uri.http(uriRaw, '');
case WalletType.ethereum:
return Uri.https(uriRaw, '');
case WalletType.bitcoinCash:
@ -134,6 +136,7 @@ class Node extends HiveObject with Keyable {
try {
switch (type) {
case WalletType.monero:
case WalletType.wownero:
return requestMoneroNode();
case WalletType.bitcoin:
return requestElectrumServer();
@ -214,7 +217,7 @@ class Node extends HiveObject with Keyable {
}
Future<bool> requestNodeWithProxy() async {
if (!isValidProxyAddress/* && !Tor.instance.enabled*/) {
if (!isValidProxyAddress /* && !Tor.instance.enabled*/) {
return false;
}

@ -9,6 +9,7 @@ const walletTypes = [
WalletType.bitcoin,
WalletType.litecoin,
WalletType.haven,
WalletType.wownero,
WalletType.ethereum,
WalletType.bitcoinCash,
WalletType.nano,
@ -46,7 +47,10 @@ enum WalletType {
bitcoinCash,
@HiveField(9)
polygon
polygon,
@HiveField(10)
wownero
}
int serializeToInt(WalletType type) {
@ -69,6 +73,8 @@ int serializeToInt(WalletType type) {
return 7;
case WalletType.polygon:
return 8;
case WalletType.wownero:
return 9;
default:
return -1;
}
@ -94,6 +100,8 @@ WalletType deserializeFromInt(int raw) {
return WalletType.bitcoinCash;
case 8:
return WalletType.polygon;
case 9:
return WalletType.wownero;
default:
throw Exception('Unexpected token: $raw for WalletType deserializeFromInt');
}
@ -119,6 +127,8 @@ String walletTypeToString(WalletType type) {
return 'Banano';
case WalletType.polygon:
return 'Polygon';
case WalletType.wownero:
return 'Wownero';
default:
return '';
}
@ -144,6 +154,8 @@ String walletTypeToDisplayName(WalletType type) {
return 'Banano (BAN)';
case WalletType.polygon:
return 'Polygon (MATIC)';
case WalletType.wownero:
return 'Wownero (WOW)';
default:
return '';
}
@ -169,6 +181,8 @@ CryptoCurrency walletTypeToCryptoCurrency(WalletType type) {
return CryptoCurrency.banano;
case WalletType.polygon:
return CryptoCurrency.maticpoly;
case WalletType.wownero:
return CryptoCurrency.wow;
default:
throw Exception(
'Unexpected wallet type: ${type.toString()} for CryptoCurrency walletTypeToCryptoCurrency');

@ -0,0 +1,18 @@
import 'package:intl/intl.dart';
import 'package:cw_core/crypto_amount_format.dart';
const wowneroAmountLength = 12;
const wowneroAmountDivider = 100000000000;
final wowneroAmountFormat = NumberFormat()
..maximumFractionDigits = wowneroAmountLength
..minimumFractionDigits = 1;
String wowneroAmountToString({required int amount}) => wowneroAmountFormat
.format(cryptoAmountToDouble(amount: amount, divider: wowneroAmountDivider))
.replaceAll(',', '');
double wowneroAmountToDouble({required int amount}) =>
cryptoAmountToDouble(amount: amount, divider: wowneroAmountDivider);
int wowneroParseAmount({required String amount}) =>
(double.parse(amount) * wowneroAmountDivider).round();

@ -0,0 +1,38 @@
import 'package:cw_core/balance.dart';
import 'package:cw_core/wownero_amount_format.dart';
class WowneroBalance extends Balance {
WowneroBalance({required this.fullBalance, required this.unlockedBalance, this.frozenBalance = 0})
: formattedFullBalance = wowneroAmountToString(amount: fullBalance),
formattedUnlockedBalance = wowneroAmountToString(amount: unlockedBalance - frozenBalance),
formattedLockedBalance =
wowneroAmountToString(amount: frozenBalance + fullBalance - unlockedBalance),
super(unlockedBalance, fullBalance);
WowneroBalance.fromString(
{required this.formattedFullBalance,
required this.formattedUnlockedBalance,
this.formattedLockedBalance = '0.0'})
: fullBalance = wowneroParseAmount(amount: formattedFullBalance),
unlockedBalance = wowneroParseAmount(amount: formattedUnlockedBalance),
frozenBalance = wowneroParseAmount(amount: formattedLockedBalance),
super(wowneroParseAmount(amount: formattedUnlockedBalance),
wowneroParseAmount(amount: formattedFullBalance));
final int fullBalance;
final int unlockedBalance;
final int frozenBalance;
final String formattedFullBalance;
final String formattedUnlockedBalance;
final String formattedLockedBalance;
@override
String get formattedUnAvailableBalance =>
formattedLockedBalance == '0.0' ? '' : formattedLockedBalance;
@override
String get formattedAvailableBalance => formattedUnlockedBalance;
@override
String get formattedAdditionalBalance => formattedFullBalance;
}

@ -0,0 +1,12 @@
class WowneroWalletKeys {
const WowneroWalletKeys(
{required this.privateSpendKey,
required this.privateViewKey,
required this.publicSpendKey,
required this.publicViewKey});
final String publicViewKey;
final String privateViewKey;
final String publicSpendKey;
final String privateSpendKey;
}

@ -0,0 +1,88 @@
import 'dart:io';
import 'package:cw_core/pathForWallet.dart';
import 'package:cw_core/wallet_type.dart';
String backupFileName(String originalPath) {
final pathParts = originalPath.split('/');
final newName = '#_${pathParts.last}';
pathParts.removeLast();
pathParts.add(newName);
return pathParts.join('/');
}
Future<void> backupWalletFiles(String name) async {
final path = await pathForWallet(name: name, type: WalletType.wownero);
final cacheFile = File(path);
final keysFile = File('$path.keys');
final addressListFile = File('$path.address.txt');
final newCacheFilePath = backupFileName(cacheFile.path);
final newKeysFilePath = backupFileName(keysFile.path);
final newAddressListFilePath = backupFileName(addressListFile.path);
if (cacheFile.existsSync()) {
await cacheFile.copy(newCacheFilePath);
}
if (keysFile.existsSync()) {
await keysFile.copy(newKeysFilePath);
}
if (addressListFile.existsSync()) {
await addressListFile.copy(newAddressListFilePath);
}
}
Future<void> restoreWalletFiles(String name) async {
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.wownero);
final cacheFilePath = '$walletDirPath/$name';
final keysFilePath = '$walletDirPath/$name.keys';
final addressListFilePath = '$walletDirPath/$name.address.txt';
final backupCacheFile = File(backupFileName(cacheFilePath));
final backupKeysFile = File(backupFileName(keysFilePath));
final backupAddressListFile = File(backupFileName(addressListFilePath));
if (backupCacheFile.existsSync()) {
await backupCacheFile.copy(cacheFilePath);
}
if (backupKeysFile.existsSync()) {
await backupKeysFile.copy(keysFilePath);
}
if (backupAddressListFile.existsSync()) {
await backupAddressListFile.copy(addressListFilePath);
}
}
Future<bool> backupWalletFilesExists(String name) async {
final walletDirPath = await pathForWalletDir(name: name, type: WalletType.wownero);
final cacheFilePath = '$walletDirPath/$name';
final keysFilePath = '$walletDirPath/$name.keys';
final addressListFilePath = '$walletDirPath/$name.address.txt';
final backupCacheFile = File(backupFileName(cacheFilePath));
final backupKeysFile = File(backupFileName(keysFilePath));
final backupAddressListFile = File(backupFileName(addressListFilePath));
return backupCacheFile.existsSync()
&& backupKeysFile.existsSync()
&& backupAddressListFile.existsSync();
}
Future<void> removeCache(String name) async {
final path = await pathForWallet(name: name, type: WalletType.wownero);
final cacheFile = File(path);
if (cacheFile.existsSync()) {
cacheFile.deleteSync();
}
}
Future<void> restoreOrResetWalletFiles(String name) async {
final backupsExists = await backupWalletFilesExists(name);
if (backupsExists) {
await restoreWalletFiles(name);
}
removeCache(name);
}

@ -616,15 +616,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
tor:
dependency: "direct main"
description:
path: "."
ref: main
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
url: "https://github.com/cake-tech/tor.git"
source: git
version: "0.0.1"
typed_data:
dependency: transitive
description:
@ -645,10 +636,10 @@ packages:
dependency: transitive
description:
name: watcher
sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.0"
web_socket_channel:
dependency: transitive
description:

@ -39,33 +39,33 @@ dev_dependencies:
# The following section is specific to Flutter.
flutter:
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.dev/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.dev/assets-and-images/#resolution-aware.
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.dev/custom-fonts/#from-packages

@ -293,17 +293,13 @@ class DefaultErc20Tokens {
];
List<Erc20Token> get initialErc20Tokens => _defaultTokens.map((token) {
String? iconPath;
try {
iconPath = CryptoCurrency.all
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath;
} catch (_) {}
String? iconPath;
try {
iconPath = CryptoCurrency.all
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath;
} catch (_) {}
if (iconPath != null) {
return Erc20Token.copyWith(token, iconPath);
}
return token;
}).toList();
return Erc20Token.copyWith(token, iconPath, 'ETH');
}).toList();
}

@ -78,19 +78,18 @@ class EthereumClient {
currency == CryptoCurrency.maticpoly ||
contractAddress != null);
bool _isEVMCompatibleChain = currency == CryptoCurrency.eth || currency == CryptoCurrency.maticpoly;
bool _isEVMCompatibleChain =
currency == CryptoCurrency.eth || currency == CryptoCurrency.maticpoly;
final price = _client!.getGasPrice();
final Transaction transaction = Transaction(
final Transaction transaction = createTransaction(
from: privateKey.address,
to: EthereumAddress.fromHex(toAddress),
maxPriorityFeePerGas: EtherAmount.fromInt(EtherUnit.gwei, priority.tip),
value: _isEVMCompatibleChain ? EtherAmount.inWei(BigInt.parse(amount)) : EtherAmount.zero(),
amount: _isEVMCompatibleChain ? EtherAmount.inWei(BigInt.parse(amount)) : EtherAmount.zero(),
);
final chainId = _getChainIdForCurrency(currency);
final signedTransaction =
await _client!.signTransaction(privateKey, transaction, chainId: chainId);
@ -124,18 +123,27 @@ class EthereumClient {
);
}
int _getChainIdForCurrency(CryptoCurrency currency) {
switch (currency) {
case CryptoCurrency.maticpoly:
return 137;
case CryptoCurrency.eth:
default:
return 1;
}
int get chainId => 1;
Transaction createTransaction({
required EthereumAddress from,
required EthereumAddress to,
required EtherAmount amount,
EtherAmount? maxPriorityFeePerGas,
}) {
return Transaction(
from: from,
to: to,
maxPriorityFeePerGas: maxPriorityFeePerGas,
value: amount,
);
}
Future<String> sendTransaction(Uint8List signedTransaction) async =>
await _client!.sendRawTransaction(prependTransactionType(0x02, signedTransaction));
await _client!.sendRawTransaction(prepareSignedTransactionForSending(signedTransaction));
Uint8List prepareSignedTransactionForSending(Uint8List signedTransaction) =>
prependTransactionType(0x02, signedTransaction);
Future getTransactionDetails(String transactionHash) async {
// Wait for the transaction receipt to become available

@ -14,7 +14,7 @@ import 'package:cw_core/transaction_priority.dart';
import 'package:cw_core/wallet_addresses.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_ethereum/default_erc20_tokens.dart';
import 'package:cw_ethereum/default_ethereum_erc20_tokens.dart';
import 'package:cw_ethereum/erc20_balance.dart';
import 'package:cw_ethereum/ethereum_client.dart';
import 'package:cw_ethereum/ethereum_exceptions.dart';
@ -429,6 +429,7 @@ abstract class EthereumWalletBase
contractAddress: token.contractAddress,
decimal: token.decimal,
enabled: token.enabled,
tag: token.tag ?? "ETH",
iconPath: iconPath,
);
@ -492,7 +493,7 @@ abstract class EthereumWalletBase
_transactionsUpdateTimer!.cancel();
}
_transactionsUpdateTimer = Timer.periodic(Duration(seconds: 10), (_) {
_transactionsUpdateTimer = Timer.periodic(const Duration(seconds: 10), (_) {
_updateTransactions();
_updateBalance();
});
@ -508,7 +509,7 @@ abstract class EthereumWalletBase
}
@override
String signMessage(String message, {String? address = null}) =>
String signMessage(String message, {String? address}) =>
bytesToHex(_ethPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
Web3Client? getWeb3Client() => _client.getWeb3Client();

@ -623,15 +623,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
tor:
dependency: transitive
description:
path: "."
ref: main
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
url: "https://github.com/cake-tech/tor.git"
source: git
version: "0.0.1"
typed_data:
dependency: transitive
description:
@ -652,10 +643,10 @@ packages:
dependency: transitive
description:
name: watcher
sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.0"
web_socket_channel:
dependency: transitive
description:

@ -153,6 +153,22 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
hashlib:
dependency: transitive
description:
name: hashlib
sha256: "71bf102329ddb8e50c8a995ee4645ae7f1728bb65e575c17196b4d8262121a96"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
hashlib_codecs:
dependency: transitive
description:
name: hashlib_codecs
sha256: "49e2a471f74b15f1854263e58c2ac11f2b631b5b12c836f9708a35397d36d626"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
http:
dependency: transitive
description:
@ -308,12 +324,11 @@ packages:
polyseed:
dependency: transitive
description:
path: "."
ref: HEAD
resolved-ref: "504d58a5b147fccd3bc85a25f2e72fb32771ddd7"
url: "https://github.com/cake-tech/polyseed_dart.git"
source: git
version: "0.0.1"
name: polyseed
sha256: "9b48ec535b10863f78f6354ec983b4cc0c88ca69ff48fee469d0fd1954b01d4f"
url: "https://pub.dev"
source: hosted
version: "0.0.2"
process:
dependency: transitive
description:
@ -383,15 +398,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.5.1"
tor:
dependency: transitive
description:
path: "."
ref: main
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
url: "https://github.com/cake-tech/tor.git"
source: git
version: "0.0.1"
typed_data:
dependency: transitive
description:

@ -926,6 +926,8 @@ extern "C"
return m_wallet->trustedDaemon();
}
// Coin Control //
CoinsInfoRow* coin(int index)
{
if (index >= 0 && index < m_coins_info.size()) {
@ -1020,6 +1022,13 @@ extern "C"
m_coins->thaw(index);
}
// Sign Messages //
char *sign_message(char *message, char *address = "")
{
return strdup(get_current_wallet()->signMessage(std::string(message), std::string(address)).c_str());
}
#ifdef __cplusplus
}
#endif

@ -32,7 +32,8 @@ void store(char *path);
void set_trusted_daemon(bool arg);
bool trusted_daemon();
char *sign_message(char *message, char *address);
#ifdef __cplusplus
}
#endif
#endif

@ -149,3 +149,5 @@ typedef coin = Pointer<CoinsInfoRow> Function(Int32 index);
typedef freeze_coin = Void Function(Int32 index);
typedef thaw_coin = Void Function(Int32 index);
typedef sign_message = Pointer<Utf8> Function(Pointer<Utf8> message, Pointer<Utf8> address);

@ -149,3 +149,5 @@ typedef GetCoin = Pointer<CoinsInfoRow> Function(int);
typedef FreezeCoin = void Function(int);
typedef ThawCoin = void Function(int);
typedef SignMessage = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>);

@ -8,7 +8,6 @@ import 'package:cw_monero/api/types.dart';
import 'package:cw_monero/api/monero_api.dart';
import 'package:cw_monero/api/exceptions/setup_wallet_exception.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
int _boolToInt(bool value) => value ? 1 : 0;
@ -128,6 +127,10 @@ final trustedDaemonNative = moneroApi
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
.asFunction<TrustedDaemon>();
final signMessageNative = moneroApi
.lookup<NativeFunction<sign_message>>('sign_message')
.asFunction<SignMessage>();
int getSyncingHeight() => getSyncingHeightNative();
bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
@ -296,7 +299,7 @@ class SyncListener {
final bchHeight = await getNodeHeightOrUpdate(syncHeight);
if (_lastKnownBlockHeight == syncHeight || syncHeight == null) {
if (_lastKnownBlockHeight == syncHeight) {
return;
}
@ -311,7 +314,7 @@ class SyncListener {
}
// 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
onNewBlock?.call(syncHeight, left, ptc);
onNewBlock.call(syncHeight, left, ptc);
});
}
@ -382,4 +385,15 @@ String getSubaddressLabel(int accountIndex, int addressIndex) {
Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;
String signMessage(String message, {String address = ""}) {
final messagePointer = message.toNativeUtf8();
final addressPointer = address.toNativeUtf8();
final signature = convertUTF8ToString(pointer: signMessageNative(messagePointer, addressPointer));
calloc.free(messagePointer);
calloc.free(addressPointer);
return signature;
}

@ -651,4 +651,10 @@ abstract class MoneroWalletBase
@override
void setExceptionHandler(void Function(FlutterErrorDetails) onError) => _onError = onError;
@override
String signMessage(String message, {String? address}) {
final useAddress = address ?? "";
return monero_wallet.signMessage(message, address: useAddress);
}
}

@ -13,7 +13,6 @@ import 'package:cw_monero/api/wallet_manager.dart' as monero_wallet_manager;
import 'package:cw_monero/monero_wallet.dart';
import 'package:hive/hive.dart';
import 'package:polyseed/polyseed.dart';
import 'package:polyseed/src/utils/key_utils.dart';
class MoneroNewWalletCredentials extends WalletCredentials {
MoneroNewWalletCredentials({required String name, required this.language, required this.isPolyseed, String? password})
@ -275,7 +274,7 @@ class MoneroWalletService extends WalletService<
{PolyseedCoin coin = PolyseedCoin.POLYSEED_MONERO, int? overrideHeight}) async {
final height = overrideHeight ?? getMoneroHeigthByDate(
date: DateTime.fromMillisecondsSinceEpoch(polyseed.birthday * 1000));
final spendKey = keyToHexString(polyseed.generateKey(coin, 32));
final spendKey = polyseed.generateKey(coin, 32).toHexString();
final seed = polyseed.encode(lang, coin);
walletInfo.isRecovery = true;

@ -1020,6 +1020,13 @@ extern "C"
m_coins->thaw(index);
}
// Sign Messages //
char *sign_message(char *message, char *address = "")
{
return strdup(get_current_wallet()->signMessage(std::string(message), std::string(address)).c_str());
}
#ifdef __cplusplus
}
#endif

@ -32,7 +32,8 @@ void store(char *path);
void set_trusted_daemon(bool arg);
bool trusted_daemon();
char *sign_message(char *message, char *address);
#ifdef __cplusplus
}
#endif
#endif

@ -266,6 +266,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "2.2.0"
hashlib:
dependency: transitive
description:
name: hashlib
sha256: "71bf102329ddb8e50c8a995ee4645ae7f1728bb65e575c17196b4d8262121a96"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
hashlib_codecs:
dependency: transitive
description:
name: hashlib_codecs
sha256: "49e2a471f74b15f1854263e58c2ac11f2b631b5b12c836f9708a35397d36d626"
url: "https://pub.dev"
source: hosted
version: "2.2.0"
hive:
dependency: transitive
description:
@ -485,12 +501,11 @@ packages:
polyseed:
dependency: "direct main"
description:
path: "."
ref: HEAD
resolved-ref: "504d58a5b147fccd3bc85a25f2e72fb32771ddd7"
url: "https://github.com/cake-tech/polyseed_dart.git"
source: git
version: "0.0.1"
name: polyseed
sha256: "9b48ec535b10863f78f6354ec983b4cc0c88ca69ff48fee469d0fd1954b01d4f"
url: "https://pub.dev"
source: hosted
version: "0.0.2"
pool:
dependency: transitive
description:
@ -632,15 +647,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
tor:
dependency: transitive
description:
path: "."
ref: main
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
url: "https://github.com/cake-tech/tor.git"
source: git
version: "0.0.1"
typed_data:
dependency: transitive
description:
@ -661,10 +667,10 @@ packages:
dependency: transitive
description:
name: watcher
sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.0"
web_socket_channel:
dependency: transitive
description:

@ -19,9 +19,7 @@ dependencies:
flutter_mobx: ^2.0.6+1
intl: ^0.18.0
encrypt: ^5.0.1
polyseed:
git:
url: https://github.com/cake-tech/polyseed_dart.git
polyseed: ^0.0.2
cw_core:
path: ../cw_core

@ -173,10 +173,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c"
sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a
url: "https://pub.dev"
source: hosted
version: "1.17.1"
version: "1.18.0"
convert:
dependency: transitive
description:
@ -419,26 +419,26 @@ packages:
dependency: transitive
description:
name: matcher
sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb"
sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e"
url: "https://pub.dev"
source: hosted
version: "0.12.15"
version: "0.12.16"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724
sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41"
url: "https://pub.dev"
source: hosted
version: "0.2.0"
version: "0.5.0"
meta:
dependency: transitive
description:
name: meta
sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3"
sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.10.0"
mime:
dependency: transitive
description:
@ -704,26 +704,26 @@ packages:
dependency: transitive
description:
name: source_span
sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
version: "1.10.0"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5
sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b"
url: "https://pub.dev"
source: hosted
version: "1.11.0"
version: "1.11.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8"
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
stream_transform:
dependency: transitive
description:
@ -752,10 +752,10 @@ packages:
dependency: transitive
description:
name: test_api
sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb
sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b"
url: "https://pub.dev"
source: hosted
version: "0.5.1"
version: "0.6.1"
timing:
dependency: transitive
description:
@ -764,15 +764,6 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
tor:
dependency: transitive
description:
path: "."
ref: main
resolved-ref: "09ba92cb11d4e3cacf97256e57863b805f79f2e5"
url: "https://github.com/cake-tech/tor.git"
source: git
version: "0.0.1"
typed_data:
dependency: transitive
description:
@ -793,10 +784,18 @@ packages:
dependency: transitive
description:
name: watcher
sha256: "6a7f46926b01ce81bfc339da6a7f20afbe7733eff9846f6d6a5466aa4c6667c0"
sha256: "3d2ad6751b3c16cf07c7fca317a1413b3f26530319181b37e3b9039b84fc01d8"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
version: "1.1.0"
web:
dependency: transitive
description:
name: web
sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152
url: "https://pub.dev"
source: hosted
version: "0.3.0"
web_socket_channel:
dependency: transitive
description:
@ -830,5 +829,5 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.0.0 <4.0.0"
dart: ">=3.2.0-194.0.dev <4.0.0"
flutter: ">=3.7.0"

@ -29,7 +29,7 @@ class DefaultPolygonErc20Tokens {
symbol: "USDC.e",
contractAddress: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
decimal: 6,
enabled: false,
enabled: true,
),
Erc20Token(
name: "Avalanche Token",
@ -73,14 +73,10 @@ class DefaultPolygonErc20Tokens {
try {
iconPath = CryptoCurrency.all
.firstWhere((element) =>
element.title.toUpperCase() == token.symbol.toUpperCase())
element.title.toUpperCase() == token.symbol.split(".").first.toUpperCase())
.iconPath;
} catch (_) {}
if (iconPath != null) {
return Erc20Token.copyWith(token, iconPath);
}
return token;
return Erc20Token.copyWith(token, iconPath, 'POLY');
}).toList();
}

@ -3,8 +3,30 @@ import 'dart:convert';
import 'package:cw_ethereum/ethereum_client.dart';
import 'package:cw_polygon/polygon_transaction_model.dart';
import 'package:cw_ethereum/.secrets.g.dart' as secrets;
import 'package:flutter/foundation.dart';
import 'package:web3dart/web3dart.dart';
class PolygonClient extends EthereumClient {
@override
Transaction createTransaction({
required EthereumAddress from,
required EthereumAddress to,
required EtherAmount amount,
EtherAmount? maxPriorityFeePerGas,
}) {
return Transaction(
from: from,
to: to,
value: amount,
);
}
@override
Uint8List prepareSignedTransactionForSending(Uint8List signedTransaction) => signedTransaction;
@override
int get chainId => 137;
@override
Future<List<PolygonTransactionModel>> fetchTransactions(String address,
{String? contractAddress}) async {
@ -27,7 +49,6 @@ class PolygonClient extends EthereumClient {
return [];
} catch (e) {
print(e);
return [];
}
}

@ -16,10 +16,9 @@ import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_ethereum/erc20_balance.dart';
import 'package:cw_ethereum/ethereum_formatter.dart';
import 'package:cw_ethereum/ethereum_transaction_model.dart';
import 'package:cw_ethereum/file.dart';
import 'package:cw_core/erc20_token.dart';
import 'package:cw_polygon/default_erc20_tokens.dart';
import 'package:cw_polygon/default_polygon_erc20_tokens.dart';
import 'package:cw_polygon/polygon_client.dart';
import 'package:cw_polygon/polygon_exceptions.dart';
import 'package:cw_polygon/polygon_formatter.dart';
@ -42,28 +41,26 @@ part 'polygon_wallet.g.dart';
class PolygonWallet = PolygonWalletBase with _$PolygonWallet;
abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
PolygonTransactionHistory, PolygonTransactionInfo> with Store {
abstract class PolygonWalletBase
extends WalletBase<ERC20Balance, PolygonTransactionHistory, PolygonTransactionInfo> with Store {
PolygonWalletBase({
required WalletInfo walletInfo,
String? mnemonic,
String? privateKey,
required String password,
ERC20Balance? initialBalance,
}) : syncStatus = NotConnectedSyncStatus(),
}) : syncStatus = const NotConnectedSyncStatus(),
_password = password,
_mnemonic = mnemonic,
_hexPrivateKey = privateKey,
_isTransactionUpdating = false,
_client = PolygonClient(),
walletAddresses = PolygonWalletAddresses(walletInfo),
balance = ObservableMap<CryptoCurrency, ERC20Balance>.of({
CryptoCurrency.maticpoly: initialBalance ?? ERC20Balance(BigInt.zero)
}),
balance = ObservableMap<CryptoCurrency, ERC20Balance>.of(
{CryptoCurrency.maticpoly: initialBalance ?? ERC20Balance(BigInt.zero)}),
super(walletInfo) {
this.walletInfo = walletInfo;
transactionHistory =
PolygonTransactionHistory(walletInfo: walletInfo, password: password);
transactionHistory = PolygonTransactionHistory(walletInfo: walletInfo, password: password);
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
CakeHive.registerAdapter(Erc20TokenAdapter());
@ -80,9 +77,9 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
late final EthPrivateKey _polygonPrivateKey;
EthPrivateKey get polygonPrivateKey => _polygonPrivateKey;
late final PolygonClient _client;
late PolygonClient _client;
EthPrivateKey get polygonPrivateKey => _polygonPrivateKey;
int? _gasPrice;
int? _estimatedGas;
@ -102,11 +99,11 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
@observable
late ObservableMap<CryptoCurrency, ERC20Balance> balance;
Completer<SharedPreferences> _sharedPrefs = Completer();
final Completer<SharedPreferences> _sharedPrefs = Completer();
Future<void> init() async {
polygonErc20TokensBox =
await CakeHive.openBox<Erc20Token>(Erc20Token.polygonBoxName);
polygonErc20TokensBox = await CakeHive.openBox<Erc20Token>(
"${walletInfo.name.replaceAll(" ", "_")}_${Erc20Token.polygonBoxName}");
await walletAddresses.init();
await transactionHistory.init();
_polygonPrivateKey = await getPrivateKey(
@ -122,8 +119,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
int calculateEstimatedFee(TransactionPriority priority, int? amount) {
try {
if (priority is PolygonTransactionPriority) {
final priorityFee =
EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
final priorityFee = EtherAmount.fromInt(EtherUnit.gwei, priority.tip).getInWei.toInt();
return (_gasPrice! + priorityFee) * (_estimatedGas ?? 0);
}
@ -168,33 +164,29 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
@override
Future<PendingTransaction> createTransaction(Object credentials) async {
final _credentials = credentials as PolygonTransactionCredentials;
final outputs = _credentials.outputs;
final credentials0 = credentials as PolygonTransactionCredentials;
final outputs = credentials0.outputs;
final hasMultiDestination = outputs.length > 1;
final CryptoCurrency transactionCurrency = balance.keys
.firstWhere((element) => element.title == _credentials.currency.title);
final CryptoCurrency transactionCurrency =
balance.keys.firstWhere((element) => element.title == credentials0.currency.title);
final _erc20Balance = balance[transactionCurrency]!;
final erc20Balance = balance[transactionCurrency]!;
BigInt totalAmount = BigInt.zero;
int exponent =
transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
int exponent = transactionCurrency is Erc20Token ? transactionCurrency.decimal : 18;
num amountToPolygonMultiplier = pow(10, exponent);
// so far this can not be made with Polygon as Polygon does not support multiple recipients
if (hasMultiDestination) {
if (outputs.any(
(item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
if (outputs.any((item) => item.sendAll || (item.formattedCryptoAmount ?? 0) <= 0)) {
throw PolygonTransactionCreationException(transactionCurrency);
}
final totalOriginalAmount = PolygonFormatter.parsePolygonAmountToDouble(
outputs.fold(
0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)));
totalAmount =
BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
outputs.fold(0, (acc, value) => acc + (value.formattedCryptoAmount ?? 0)));
totalAmount = BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
if (_erc20Balance.balance < totalAmount) {
if (erc20Balance.balance < totalAmount) {
throw PolygonTransactionCreationException(transactionCurrency);
}
} else {
@ -203,35 +195,33 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
// then no need to subtract the fees from the amount if send all
final BigInt allAmount;
if (transactionCurrency is Erc20Token) {
allAmount = _erc20Balance.balance;
allAmount = erc20Balance.balance;
} else {
allAmount = _erc20Balance.balance -
BigInt.from(calculateEstimatedFee(_credentials.priority!, null));
allAmount =
erc20Balance.balance - BigInt.from(calculateEstimatedFee(credentials0.priority!, null));
}
final totalOriginalAmount = EthereumFormatter.parseEthereumAmountToDouble(
output.formattedCryptoAmount ?? 0);
totalAmount = output.sendAll
? allAmount
: BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
final totalOriginalAmount =
EthereumFormatter.parseEthereumAmountToDouble(output.formattedCryptoAmount ?? 0);
totalAmount =
output.sendAll ? allAmount : BigInt.from(totalOriginalAmount * amountToPolygonMultiplier);
if (_erc20Balance.balance < totalAmount) {
if (erc20Balance.balance < totalAmount) {
throw PolygonTransactionCreationException(transactionCurrency);
}
}
final pendingPolygonTransaction = await _client.signTransaction(
privateKey: _polygonPrivateKey,
toAddress: _credentials.outputs.first.isParsedAddress
? _credentials.outputs.first.extractedAddress!
: _credentials.outputs.first.address,
toAddress: credentials0.outputs.first.isParsedAddress
? credentials0.outputs.first.extractedAddress!
: credentials0.outputs.first.address,
amount: totalAmount.toString(),
gas: _estimatedGas!,
priority: _credentials.priority!,
priority: credentials0.priority!,
currency: transactionCurrency,
exponent: exponent,
contractAddress: transactionCurrency is Erc20Token
? transactionCurrency.contractAddress
: null,
contractAddress:
transactionCurrency is Erc20Token ? transactionCurrency.contractAddress : null,
);
return pendingPolygonTransaction;
@ -262,15 +252,16 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
final address = _polygonPrivateKey.address.hex;
final transactions = await _client.fetchTransactions(address);
final List<Future<List<PolygonTransactionModel>>> polygonErc20TokensTransactions =
[];
final List<Future<List<PolygonTransactionModel>>> polygonErc20TokensTransactions = [];
for (var token in balance.keys) {
if (token is Erc20Token) {
polygonErc20TokensTransactions.add(_client.fetchTransactions(
address,
contractAddress: token.contractAddress,
) as Future<List<PolygonTransactionModel>>);
polygonErc20TokensTransactions.add(
_client.fetchTransactions(
address,
contractAddress: token.contractAddress,
),
);
}
}
@ -294,8 +285,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
isPending: false,
date: transactionModel.date,
confirmations: transactionModel.confirmations,
ethFee:
BigInt.from(transactionModel.gasUsed) * transactionModel.gasPrice,
ethFee: BigInt.from(transactionModel.gasUsed) * transactionModel.gasPrice,
exponent: transactionModel.tokenDecimal ?? 18,
tokenSymbol: transactionModel.tokenSymbol ?? "MATIC",
to: transactionModel.to,
@ -337,8 +327,8 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
_gasPrice = await _client.getGasUnitPrice();
_estimatedGas = await _client.getEstimatedGas();
Timer.periodic(const Duration(minutes: 1),
(timer) async => _gasPrice = await _client.getGasUnitPrice());
Timer.periodic(
const Duration(minutes: 1), (timer) async => _gasPrice = await _client.getGasUnitPrice());
Timer.periodic(const Duration(seconds: 10),
(timer) async => _estimatedGas = await _client.getEstimatedGas());
@ -348,8 +338,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
}
}
Future<String> makePath() async =>
pathForWallet(name: walletInfo.name, type: walletInfo.type);
Future<String> makePath() async => pathForWallet(name: walletInfo.name, type: walletInfo.type);
String toJSON() => json.encode({
'mnemonic': _mnemonic,
@ -367,8 +356,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
final data = json.decode(jsonSource) as Map;
final mnemonic = data['mnemonic'] as String?;
final privateKey = data['private_key'] as String?;
final balance = ERC20Balance.fromJSON(data['balance'] as String) ??
ERC20Balance(BigInt.zero);
final balance = ERC20Balance.fromJSON(data['balance'] as String) ?? ERC20Balance(BigInt.zero);
return PolygonWallet(
walletInfo: walletInfo,
@ -418,14 +406,14 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
final root = bip32.BIP32.fromSeed(seed);
const _hdPathPolygon = "m/44'/60'/0'/0";
const hdPathPolygon = "m/44'/60'/0'/0";
const index = 0;
final addressAtIndex = root.derivePath("$_hdPathPolygon/$index");
final addressAtIndex = root.derivePath("$hdPathPolygon/$index");
return EthPrivateKey.fromHex(
HEX.encode(addressAtIndex.privateKey as List<int>));
return EthPrivateKey.fromHex(HEX.encode(addressAtIndex.privateKey as List<int>));
}
@override
Future<void>? updateBalance() async => await _updateBalance();
List<Erc20Token> get erc20Currencies => polygonErc20TokensBox.values.toList();
@ -434,29 +422,29 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
String? iconPath;
try {
iconPath = CryptoCurrency.all
.firstWhere((element) =>
element.title.toUpperCase() == token.symbol.toUpperCase())
.firstWhere((element) => element.title.toUpperCase() == token.symbol.toUpperCase())
.iconPath;
} catch (_) {}
final _token = Erc20Token(
final token0 = Erc20Token(
name: token.name,
symbol: token.symbol,
contractAddress: token.contractAddress,
decimal: token.decimal,
enabled: token.enabled,
tag: token.tag ?? "POLY",
iconPath: iconPath,
);
await polygonErc20TokensBox.put(_token.contractAddress, _token);
await polygonErc20TokensBox.put(token0.contractAddress, token0);
if (_token.enabled) {
balance[_token] = await _client.fetchERC20Balances(
if (token0.enabled) {
balance[token0] = await _client.fetchERC20Balances(
_polygonPrivateKey.address,
_token.contractAddress,
token0.contractAddress,
);
} else {
balance.remove(_token);
balance.remove(token0);
}
}
@ -476,8 +464,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
}
void addInitialTokens() {
final initialErc20Tokens =
DefaultPolygonErc20Tokens().initialPolygonErc20Tokens;
final initialErc20Tokens = DefaultPolygonErc20Tokens().initialPolygonErc20Tokens;
for (var token in initialErc20Tokens) {
polygonErc20TokensBox.put(token.contractAddress, token);
@ -486,26 +473,20 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
@override
Future<void> renameWalletFiles(String newWalletName) async {
final currentWalletPath =
await pathForWallet(name: walletInfo.name, type: type);
final currentWalletPath = await pathForWallet(name: walletInfo.name, type: type);
final currentWalletFile = File(currentWalletPath);
final currentDirPath =
await pathForWalletDir(name: walletInfo.name, type: type);
final currentTransactionsFile =
File('$currentDirPath/$transactionsHistoryFileName');
final currentDirPath = await pathForWalletDir(name: walletInfo.name, type: type);
final currentTransactionsFile = File('$currentDirPath/$transactionsHistoryFileName');
// Copies current wallet files into new wallet name's dir and files
if (currentWalletFile.existsSync()) {
final newWalletPath =
await pathForWallet(name: newWalletName, type: type);
final newWalletPath = await pathForWallet(name: newWalletName, type: type);
await currentWalletFile.copy(newWalletPath);
}
if (currentTransactionsFile.existsSync()) {
final newDirPath =
await pathForWalletDir(name: newWalletName, type: type);
await currentTransactionsFile
.copy('$newDirPath/$transactionsHistoryFileName');
final newDirPath = await pathForWalletDir(name: newWalletName, type: type);
await currentTransactionsFile.copy('$newDirPath/$transactionsHistoryFileName');
}
// Delete old name's dir and files
@ -517,7 +498,7 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
_transactionsUpdateTimer!.cancel();
}
_transactionsUpdateTimer = Timer.periodic(Duration(seconds: 10), (_) {
_transactionsUpdateTimer = Timer.periodic(const Duration(seconds: 10), (_) {
_updateTransactions();
_updateBalance();
});
@ -533,8 +514,8 @@ abstract class PolygonWalletBase extends WalletBase<ERC20Balance,
}
@override
String signMessage(String message, {String? address = null}) => bytesToHex(
_polygonPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
String signMessage(String message, {String? address}) =>
bytesToHex(_polygonPrivateKey.signPersonalMessageToUint8List(ascii.encode(message)));
Web3Client? getWeb3Client() => _client.getWeb3Client();
}

@ -0,0 +1,11 @@
.DS_Store
.dart_tool/
.packages
.pub/
build/
ios/External/
android/.externalNativeBuild/
android/.cxx/

@ -0,0 +1,10 @@
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: 398e4272a2e43d7daab75f225a13422e384ee0cd
channel: dev
project_type: plugin

@ -0,0 +1,3 @@
## 0.0.1
* TODO: wow.

@ -0,0 +1 @@
TODO: Add your license here.

@ -0,0 +1,5 @@
# cw_wownero
This project is part of Cake Wallet app.
Copyright (c) 2022 Cake Technologies LLC.

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

@ -0,0 +1,8 @@
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>cw_wownero</name>
<comment>Project android created by Buildship.</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

@ -0,0 +1,13 @@
arguments=
auto.sync=false
build.scans.enabled=false
connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(6.0-20191016123526+0000))
connection.project.dir=../../android
eclipse.preferences.version=1
gradle.user.home=
java.home=
jvm.arguments=
offline.mode=false
override.workspace.settings=true
show.console.view=true
show.executions.view=true

@ -0,0 +1,232 @@
cmake_minimum_required(VERSION 3.4.1)
add_library( cw_wownero
SHARED
./jni/wownero_jni.cpp
../ios/Classes/wownero_api.cpp)
find_library( log-lib log )
set(EXTERNAL_LIBS_DIR ${CMAKE_SOURCE_DIR}/../../cw_shared_external/ios/External/android)
############
# libsodium
############
add_library(sodium STATIC IMPORTED)
set_target_properties(sodium PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libsodium.a)
############
# OpenSSL
############
add_library(crypto STATIC IMPORTED)
set_target_properties(crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libcrypto.a)
add_library(ssl STATIC IMPORTED)
set_target_properties(ssl PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libssl.a)
############
# Boost
############
add_library(boost_chrono STATIC IMPORTED)
set_target_properties(boost_chrono PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_chrono.a)
add_library(boost_date_time STATIC IMPORTED)
set_target_properties(boost_date_time PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_date_time.a)
add_library(boost_filesystem STATIC IMPORTED)
set_target_properties(boost_filesystem PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_filesystem.a)
add_library(boost_program_options STATIC IMPORTED)
set_target_properties(boost_program_options PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_program_options.a)
add_library(boost_regex STATIC IMPORTED)
set_target_properties(boost_regex PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_regex.a)
add_library(boost_serialization STATIC IMPORTED)
set_target_properties(boost_serialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_serialization.a)
add_library(boost_system STATIC IMPORTED)
set_target_properties(boost_system PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_system.a)
add_library(boost_thread STATIC IMPORTED)
set_target_properties(boost_thread PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_thread.a)
add_library(boost_wserialization STATIC IMPORTED)
set_target_properties(boost_wserialization PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/libboost_wserialization.a)
#############
# Wownero
#############
add_library(wallet_api STATIC IMPORTED)
set_target_properties(wallet_api PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libwallet_api.a)
add_library(wallet STATIC IMPORTED)
set_target_properties(wallet PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libwallet.a)
add_library(cryptonote_core STATIC IMPORTED)
set_target_properties(cryptonote_core PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcryptonote_core.a)
add_library(cryptonote_basic STATIC IMPORTED)
set_target_properties(cryptonote_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcryptonote_basic.a)
add_library(cryptonote_format_utils_basic STATIC IMPORTED)
set_target_properties(cryptonote_format_utils_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcryptonote_format_utils_basic.a)
add_library(mnemonics STATIC IMPORTED)
set_target_properties(mnemonics PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libmnemonics.a)
add_library(common STATIC IMPORTED)
set_target_properties(common PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcommon.a)
add_library(cncrypto STATIC IMPORTED)
set_target_properties(cncrypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcncrypto.a)
add_library(ringct STATIC IMPORTED)
set_target_properties(ringct PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libringct.a)
add_library(ringct_basic STATIC IMPORTED)
set_target_properties(ringct_basic PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libringct_basic.a)
add_library(blockchain_db STATIC IMPORTED)
set_target_properties(blockchain_db PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libblockchain_db.a)
add_library(lmdb STATIC IMPORTED)
set_target_properties(lmdb PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/liblmdb.a)
add_library(easylogging STATIC IMPORTED)
set_target_properties(easylogging PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libeasylogging.a)
add_library(unbound STATIC IMPORTED)
set_target_properties(unbound PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libunbound.a)
add_library(epee STATIC IMPORTED)
set_target_properties(epee PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libepee.a)
add_library(blocks STATIC IMPORTED)
set_target_properties(blocks PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libblocks.a)
add_library(checkpoints STATIC IMPORTED)
set_target_properties(checkpoints PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libcheckpoints.a)
add_library(device STATIC IMPORTED)
set_target_properties(device PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libdevice.a)
add_library(device_trezor STATIC IMPORTED)
set_target_properties(device_trezor PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libdevice_trezor.a)
add_library(multisig STATIC IMPORTED)
set_target_properties(multisig PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libmultisig.a)
add_library(version STATIC IMPORTED)
set_target_properties(version PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libversion.a)
add_library(net STATIC IMPORTED)
set_target_properties(net PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libnet.a)
add_library(hardforks STATIC IMPORTED)
set_target_properties(hardforks PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libhardforks.a)
add_library(randomx STATIC IMPORTED)
set_target_properties(randomx PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/librandomx.a)
add_library(rpc_base STATIC IMPORTED)
set_target_properties(rpc_base PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/librpc_base.a)
add_library(wallet-crypto STATIC IMPORTED)
set_target_properties(wallet-crypto PROPERTIES IMPORTED_LOCATION
${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/lib/wownero/libwallet-crypto.a)
set(WALLET_CRYPTO "")
if(${ANDROID_ABI} STREQUAL "x86_64")
set(WALLET_CRYPTO "wallet-crypto")
endif()
include_directories( ${EXTERNAL_LIBS_DIR}/${ANDROID_ABI}/include )
target_link_libraries( cw_wownero
wallet_api
wallet
cryptonote_core
cryptonote_basic
cryptonote_format_utils_basic
mnemonics
ringct
ringct_basic
net
common
cncrypto
blockchain_db
lmdb
easylogging
unbound
epee
blocks
checkpoints
device
device_trezor
multisig
version
randomx
hardforks
rpc_base
${WALLET_CRYPTO}
boost_chrono
boost_date_time
boost_filesystem
boost_program_options
boost_regex
boost_serialization
boost_system
boost_thread
boost_wserialization
ssl
crypto
sodium
${log-lib} )

@ -0,0 +1,49 @@
group 'com.cakewallet.wownero'
version '1.0-SNAPSHOT'
buildscript {
ext.kotlin_version = '1.7.10'
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:7.3.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
rootProject.allprojects {
repositories {
google()
jcenter()
}
}
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 28
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
defaultConfig {
minSdkVersion 21
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

@ -0,0 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
android.useAndroidX=true
android.enableJetifier=true

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip

@ -0,0 +1,74 @@
#include <string.h>
#include <jni.h>
#include "../../ios/Classes/wownero_api.h"
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT void JNICALL
Java_com_cakewallet_wownero_WowneroApi_setNodeAddressJNI(
JNIEnv *env,
jobject inst,
jstring uri,
jstring login,
jstring password,
jboolean use_ssl,
jboolean is_light_wallet) {
const char *_uri = env->GetStringUTFChars(uri, 0);
const char *_login = "";
const char *_password = "";
char *error;
if (login != NULL) {
_login = env->GetStringUTFChars(login, 0);
}
if (password != NULL) {
_password = env->GetStringUTFChars(password, 0);
}
char *__uri = (char*) _uri;
char *__login = (char*) _login;
char *__password = (char*) _password;
bool inited = setup_node(__uri, __login, __password, false, false, error);
if (!inited) {
env->ThrowNew(env->FindClass("java/lang/Exception"), error);
}
}
JNIEXPORT void JNICALL
Java_com_cakewallet_wownero_WowneroApi_connectToNodeJNI(
JNIEnv *env,
jobject inst) {
char *error;
bool is_connected = connect_to_node(error);
if (!is_connected) {
env->ThrowNew(env->FindClass("java/lang/Exception"), error);
}
}
JNIEXPORT void JNICALL
Java_com_cakewallet_wownero_WowneroApi_startSyncJNI(
JNIEnv *env,
jobject inst) {
start_refresh();
}
JNIEXPORT void JNICALL
Java_com_cakewallet_wownero_WowneroApi_loadWalletJNI(
JNIEnv *env,
jobject inst,
jstring path,
jstring password) {
char *_path = (char *) env->GetStringUTFChars(path, 0);
char *_password = (char *) env->GetStringUTFChars(password, 0);
load_wallet(_path, _password, 0);
}
#ifdef __cplusplus
}
#endif

@ -0,0 +1 @@
rootProject.name = 'cw_wownero'

@ -0,0 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.cakewallet.wownero">
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

@ -0,0 +1,74 @@
package com.cakewallet.cw_wownero
import android.app.Activity
import android.os.AsyncTask
import android.os.Looper
import android.os.Handler
import android.os.Process
import io.flutter.plugin.common.MethodCall
import io.flutter.plugin.common.MethodChannel
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
import io.flutter.plugin.common.MethodChannel.Result
import io.flutter.plugin.common.PluginRegistry.Registrar
class doAsync(val handler: () -> Unit) : AsyncTask<Void, Void, Void>() {
override fun doInBackground(vararg params: Void?): Void? {
Process.setThreadPriority(Process.THREAD_PRIORITY_AUDIO);
handler()
return null
}
}
class CwWowneroPlugin: MethodCallHandler {
companion object {
// val wowneroApi = WowneroApi()
val main = Handler(Looper.getMainLooper());
init {
System.loadLibrary("cw_wownero")
}
@JvmStatic
fun registerWith(registrar: Registrar) {
val channel = MethodChannel(registrar.messenger(), "cw_wownero")
channel.setMethodCallHandler(CwWowneroPlugin())
}
}
override fun onMethodCall(call: MethodCall, result: Result) {
if (call.method == "setupNode") {
val uri = call.argument("address") ?: ""
val login = call.argument("login") ?: ""
val password = call.argument("password") ?: ""
val useSSL = false
val isLightWallet = false
// doAsync {
// try {
// wowneroApi.setNodeAddressJNI(uri, login, password, useSSL, isLightWallet)
// main.post({
// result.success(true)
// });
// } catch(e: Throwable) {
// main.post({
// result.error("CONNECTION_ERROR", e.message, null)
// });
// }
// }.execute()
}
if (call.method == "startSync") {
// doAsync {
// wowneroApi.startSyncJNI()
// main.post({
// result.success(true)
// });
// }.execute()
}
if (call.method == "loadWallet") {
val path = call.argument("path") ?: ""
val password = call.argument("password") ?: ""
// wowneroApi.loadWalletJNI(path, password)
result.success(true)
}
}
}

@ -0,0 +1,37 @@
.idea/
.vagrant/
.sconsign.dblite
.svn/
.DS_Store
*.swp
profile
DerivedData/
build/
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m
.generated/
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
xcuserdata
*.moved-aside
*.pyc
*sync/
Icon?
.tags*
/Flutter/Generated.xcconfig
/Flutter/flutter_export_environment.sh

@ -0,0 +1,23 @@
#include <stdint.h>
struct CWWowneroWalletListener;
typedef int8_t (*on_new_block_callback)(uint64_t height);
typedef int8_t (*on_need_to_refresh_callback)();
typedef struct CWWowneroWalletListener
{
// on_money_spent_callback *on_money_spent;
// on_money_received_callback *on_money_received;
// on_unconfirmed_money_received_callback *on_unconfirmed_money_received;
// on_new_block_callback *on_new_block;
// on_updated_callback *on_updated;
// on_refreshed_callback *on_refreshed;
on_new_block_callback on_new_block;
} CWWowneroWalletListener;
struct TestListener {
// int8_t x;
on_new_block_callback on_new_block;
};

@ -0,0 +1,4 @@
#import <Flutter/Flutter.h>
@interface CwWowneroPlugin : NSObject<FlutterPlugin>
@end

@ -0,0 +1,8 @@
#import "CwWowneroPlugin.h"
#import <cw_wownero/cw_wownero-Swift.h>
@implementation CwWowneroPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
[SwiftCwWowneroPlugin registerWithRegistrar:registrar];
}
@end

@ -0,0 +1,14 @@
import Flutter
import UIKit
public class SwiftCwWowneroPlugin: NSObject, FlutterPlugin {
public static func register(with registrar: FlutterPluginRegistrar) {
let channel = FlutterMethodChannel(name: "cw_wownero", binaryMessenger: registrar.messenger())
let instance = SwiftCwWowneroPlugin()
registrar.addMethodCallDelegate(instance, channel: channel)
}
public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
result("iOS " + UIDevice.current.systemVersion)
}
}

File diff suppressed because it is too large Load Diff

@ -0,0 +1,39 @@
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include "CwWalletListener.h"
#ifdef __cplusplus
extern "C" {
#endif
bool create_wallet(char *path, char *password, char *language, int32_t networkType, char *error);
bool restore_wallet_from_seed(char *path, char *password, char *seed, int32_t networkType, uint64_t restoreHeight, char *error);
bool restore_wallet_from_keys(char *path, char *password, char *language, char *address, char *viewKey, char *spendKey, int32_t networkType, uint64_t restoreHeight, char *error);
void load_wallet(char *path, char *password, int32_t nettype);
bool is_wallet_exist(char *path);
char *get_filename();
const char *seed();
char *get_address(uint32_t account_index, uint32_t address_index);
uint64_t get_full_balance(uint32_t account_index);
uint64_t get_unlocked_balance(uint32_t account_index);
uint64_t get_current_height();
uint64_t get_node_height();
bool is_connected();
bool setup_node(char *address, char *login, char *password, bool use_ssl, bool is_light_wallet, char *error);
bool connect_to_node(char *error);
void start_refresh();
void set_refresh_from_block_height(uint64_t height);
void set_recovering_from_seed(bool is_recovery);
void store(char *path);
void set_trusted_daemon(bool arg);
bool trusted_daemon();
char *sign_message(char *message, char *address);
#ifdef __cplusplus
}
#endif

@ -0,0 +1,50 @@
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint cw_wownero.podspec' to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'cw_wownero'
s.version = '0.0.2'
s.summary = 'Cake Wallet Wownero'
s.description = 'Cake Wallet wrapper over Wownero project'
s.homepage = 'http://cakewallet.com'
s.license = { :file => '../LICENSE' }
s.author = { 'CakeWallet' => 'support@cakewallet.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h, Classes/*.h, ../shared_external/ios/libs/monero/include/src/**/*.h, ../shared_external/ios/libs/monero/include/contrib/**/*.h, ../shared_external/ios/libs/monero/include/../shared_external/ios/**/*.h'
s.dependency 'Flutter'
s.dependency 'cw_shared_external'
s.platform = :ios, '10.0'
s.swift_version = '5.0'
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS' => 'arm64', 'ENABLE_BITCODE' => 'NO' }
s.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/Classes/*.h" }
s.subspec 'OpenSSL' do |openssl|
openssl.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
openssl.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libcrypto.a', '../../../../../cw_shared_external/ios/External/ios/lib/libssl.a'
openssl.libraries = 'ssl', 'crypto'
openssl.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Sodium' do |sodium|
sodium.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h'
sodium.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libsodium.a'
sodium.libraries = 'sodium'
sodium.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Boost' do |boost|
boost.preserve_paths = '../../../../../cw_shared_external/ios/External/ios/include/**/*.h',
boost.vendored_libraries = '../../../../../cw_shared_external/ios/External/ios/lib/libboost.a',
boost.libraries = 'boost'
boost.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include/**" }
end
s.subspec 'Wownero' do |wownero|
wownero.preserve_paths = 'External/ios/include/**/*.h'
wownero.vendored_libraries = 'External/ios/lib/libwownero.a'
wownero.libraries = 'wownero'
wownero.xcconfig = { 'HEADER_SEARCH_PATHS' => "${PODS_ROOT}/#{s.name}/External/ios/include" }
end
end

@ -0,0 +1,83 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:cw_wownero/api/signatures.dart';
import 'package:cw_wownero/api/types.dart';
import 'package:cw_wownero/api/wownero_api.dart';
import 'package:cw_wownero/api/structs/account_row.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_wownero/api/wallet.dart';
final accountSizeNative = wowneroApi
.lookup<NativeFunction<account_size>>('account_size')
.asFunction<SubaddressSize>();
final accountRefreshNative = wowneroApi
.lookup<NativeFunction<account_refresh>>('account_refresh')
.asFunction<AccountRefresh>();
final accountGetAllNative = wowneroApi
.lookup<NativeFunction<account_get_all>>('account_get_all')
.asFunction<AccountGetAll>();
final accountAddNewNative = wowneroApi
.lookup<NativeFunction<account_add_new>>('account_add_row')
.asFunction<AccountAddNew>();
final accountSetLabelNative = wowneroApi
.lookup<NativeFunction<account_set_label>>('account_set_label_row')
.asFunction<AccountSetLabel>();
bool isUpdating = false;
void refreshAccounts() {
try {
isUpdating = true;
accountRefreshNative();
isUpdating = false;
} catch (e) {
isUpdating = false;
rethrow;
}
}
List<AccountRow> getAllAccount() {
final size = accountSizeNative();
final accountAddressesPointer = accountGetAllNative();
final accountAddresses = accountAddressesPointer.asTypedList(size);
return accountAddresses
.map((addr) => Pointer<AccountRow>.fromAddress(addr).ref)
.toList();
}
void addAccountSync({required String label}) {
final labelPointer = label.toNativeUtf8();
accountAddNewNative(labelPointer);
calloc.free(labelPointer);
}
void setLabelForAccountSync({required int accountIndex, required String label}) {
final labelPointer = label.toNativeUtf8();
accountSetLabelNative(accountIndex, labelPointer);
calloc.free(labelPointer);
}
void _addAccount(String label) => addAccountSync(label: label);
void _setLabelForAccount(Map<String, dynamic> args) {
final label = args['label'] as String;
final accountIndex = args['accountIndex'] as int;
setLabelForAccountSync(label: label, accountIndex: accountIndex);
}
Future<void> addAccount({required String label}) async {
await compute(_addAccount, label);
await store();
}
Future<void> setLabelForAccount({required int accountIndex, required String label}) async {
await compute(
_setLabelForAccount, {'accountIndex': accountIndex, 'label': label});
await store();
}

@ -0,0 +1,35 @@
import 'dart:ffi';
import 'package:cw_wownero/api/signatures.dart';
import 'package:cw_wownero/api/structs/coins_info_row.dart';
import 'package:cw_wownero/api/types.dart';
import 'package:cw_wownero/api/wownero_api.dart';
final refreshCoinsNative = wowneroApi
.lookup<NativeFunction<refresh_coins>>('refresh_coins')
.asFunction<RefreshCoins>();
final coinsCountNative = wowneroApi
.lookup<NativeFunction<coins_count>>('coins_count')
.asFunction<CoinsCount>();
final coinNative = wowneroApi
.lookup<NativeFunction<coin>>('coin')
.asFunction<GetCoin>();
final freezeCoinNative = wowneroApi
.lookup<NativeFunction<freeze_coin>>('freeze_coin')
.asFunction<FreezeCoin>();
final thawCoinNative = wowneroApi
.lookup<NativeFunction<thaw_coin>>('thaw_coin')
.asFunction<ThawCoin>();
void refreshCoins(int accountIndex) => refreshCoinsNative(accountIndex);
int countOfCoins() => coinsCountNative();
CoinsInfoRow getCoin(int index) => coinNative(index).ref;
void freezeCoin(int index) => freezeCoinNative(index);
void thawCoin(int index) => thawCoinNative(index);

@ -0,0 +1,8 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
String convertUTF8ToString({required Pointer<Utf8> pointer}) {
final str = pointer.toDartString();
calloc.free(pointer);
return str;
}

@ -0,0 +1,5 @@
class ConnectionToNodeException implements Exception {
ConnectionToNodeException({required this.message});
final String message;
}

@ -0,0 +1,8 @@
class CreationTransactionException implements Exception {
CreationTransactionException({required this.message});
final String message;
@override
String toString() => message;
}

@ -0,0 +1,5 @@
class SetupWalletException implements Exception {
SetupWalletException({required this.message});
final String message;
}

@ -0,0 +1,8 @@
class WalletCreationException implements Exception {
WalletCreationException({required this.message});
final String message;
@override
String toString() => message;
}

@ -0,0 +1,8 @@
class WalletOpeningException implements Exception {
WalletOpeningException({required this.message});
final String message;
@override
String toString() => message;
}

@ -0,0 +1,5 @@
class WalletRestoreFromKeysException implements Exception {
WalletRestoreFromKeysException({required this.message});
final String message;
}

@ -0,0 +1,5 @@
class WalletRestoreFromSeedException implements Exception {
WalletRestoreFromSeedException({required this.message});
final String message;
}

@ -0,0 +1,153 @@
import 'dart:ffi';
import 'package:cw_wownero/api/structs/coins_info_row.dart';
import 'package:cw_wownero/api/structs/pending_transaction.dart';
import 'package:cw_wownero/api/structs/transaction_info_row.dart';
import 'package:cw_wownero/api/structs/ut8_box.dart';
import 'package:ffi/ffi.dart';
typedef create_wallet = Int8 Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Pointer<Utf8>);
typedef restore_wallet_from_seed = Int8 Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
typedef restore_wallet_from_keys = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
typedef restore_wallet_from_spend_key = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, Int32, Int64, Pointer<Utf8>);
typedef is_wallet_exist = Int8 Function(Pointer<Utf8>);
typedef load_wallet = Int8 Function(Pointer<Utf8>, Pointer<Utf8>, Int8);
typedef error_string = Pointer<Utf8> Function();
typedef get_filename = Pointer<Utf8> Function();
typedef get_seed = Pointer<Utf8> Function();
typedef get_address = Pointer<Utf8> Function(Int32, Int32);
typedef get_full_balanace = Int64 Function(Int32);
typedef get_unlocked_balanace = Int64 Function(Int32);
typedef get_current_height = Int64 Function();
typedef get_node_height = Int64 Function();
typedef is_connected = Int8 Function();
typedef setup_node = Int8 Function(
Pointer<Utf8>, Pointer<Utf8>?, Pointer<Utf8>?, Int8, Int8, Pointer<Utf8>?, Pointer<Utf8>);
typedef start_refresh = Void Function();
typedef connect_to_node = Int8 Function();
typedef set_refresh_from_block_height = Void Function(Int64);
typedef set_recovering_from_seed = Void Function(Int8);
typedef store_c = Void Function(Pointer<Utf8>);
typedef set_password = Int8 Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
typedef set_listener = Void Function();
typedef get_syncing_height = Int64 Function();
typedef is_needed_to_refresh = Int8 Function();
typedef is_new_transaction_exist = Int8 Function();
typedef subaddrress_size = Int32 Function();
typedef subaddrress_refresh = Void Function(Int32);
typedef subaddress_get_all = Pointer<Int64> Function();
typedef subaddress_add_new = Void Function(Int32 accountIndex, Pointer<Utf8> label);
typedef subaddress_set_label = Void Function(
Int32 accountIndex, Int32 addressIndex, Pointer<Utf8> label);
typedef account_size = Int32 Function();
typedef account_refresh = Void Function();
typedef account_get_all = Pointer<Int64> Function();
typedef account_add_new = Void Function(Pointer<Utf8> label);
typedef account_set_label = Void Function(Int32 accountIndex, Pointer<Utf8> label);
typedef transactions_refresh = Void Function();
typedef get_transaction = Pointer<TransactionInfoRow> Function(Pointer<Utf8> txId);
typedef get_tx_key = Pointer<Utf8>? Function(Pointer<Utf8> txId);
typedef transactions_count = Int64 Function();
typedef transactions_get_all = Pointer<Int64> Function();
typedef transaction_create = Int8 Function(
Pointer<Utf8> address,
Pointer<Utf8> paymentId,
Pointer<Utf8> amount,
Int8 priorityRaw,
Int32 subaddrAccount,
Pointer<Pointer<Utf8>> preferredInputs,
Int32 preferredInputsSize,
Pointer<Utf8Box> error,
Pointer<PendingTransactionRaw> pendingTransaction);
typedef transaction_create_mult_dest = Int8 Function(
Pointer<Pointer<Utf8>> addresses,
Pointer<Utf8> paymentId,
Pointer<Pointer<Utf8>> amounts,
Int32 size,
Int8 priorityRaw,
Int32 subaddrAccount,
Pointer<Pointer<Utf8>> preferredInputs,
Int32 preferredInputsSize,
Pointer<Utf8Box> error,
Pointer<PendingTransactionRaw> pendingTransaction);
typedef transaction_commit = Int8 Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
typedef secret_view_key = Pointer<Utf8> Function();
typedef public_view_key = Pointer<Utf8> Function();
typedef secret_spend_key = Pointer<Utf8> Function();
typedef public_spend_key = Pointer<Utf8> Function();
typedef close_current_wallet = Void Function();
typedef on_startup = Void Function();
typedef rescan_blockchain = Void Function();
typedef get_subaddress_label = Pointer<Utf8> Function(Int32 accountIndex, Int32 addressIndex);
typedef set_trusted_daemon = Void Function(Int8 trusted);
typedef trusted_daemon = Int8 Function();
typedef refresh_coins = Void Function(Int32 accountIndex);
typedef coins_count = Int64 Function();
// typedef coins_from_txid = Pointer<CoinsInfoRow> Function(Pointer<Utf8> txid);
typedef coin = Pointer<CoinsInfoRow> Function(Int32 index);
typedef freeze_coin = Void Function(Int32 index);
typedef thaw_coin = Void Function(Int32 index);
typedef sign_message = Pointer<Utf8> Function(Pointer<Utf8> message, Pointer<Utf8> address);

@ -0,0 +1,11 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class AccountRow extends Struct {
@Int64()
external int id;
external Pointer<Utf8> label;
String getLabel() => label.toDartString();
int getId() => id;
}

@ -0,0 +1,73 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class CoinsInfoRow extends Struct {
@Int64()
external int blockHeight;
external Pointer<Utf8> hash;
@Uint64()
external int internalOutputIndex;
@Uint64()
external int globalOutputIndex;
@Int8()
external int spent;
@Int8()
external int frozen;
@Uint64()
external int spentHeight;
@Uint64()
external int amount;
@Int8()
external int rct;
@Int8()
external int keyImageKnown;
@Uint64()
external int pkIndex;
@Uint32()
external int subaddrIndex;
@Uint32()
external int subaddrAccount;
external Pointer<Utf8> address;
external Pointer<Utf8> addressLabel;
external Pointer<Utf8> keyImage;
@Uint64()
external int unlockTime;
@Int8()
external int unlocked;
external Pointer<Utf8> pubKey;
@Int8()
external int coinbase;
external Pointer<Utf8> description;
String getHash() => hash.toDartString();
String getAddress() => address.toDartString();
String getAddressLabel() => addressLabel.toDartString();
String getKeyImage() => keyImage.toDartString();
String getPubKey() => pubKey.toDartString();
String getDescription() => description.toDartString();
}

@ -0,0 +1,39 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class PendingTransactionRaw extends Struct {
@Int64()
external int amount;
@Int64()
external int fee;
external Pointer<Utf8> hash;
external Pointer<Utf8> hex;
external Pointer<Utf8> txKey;
String getHash() => hash.toDartString();
String getHex() => hex.toDartString();
String getKey() => txKey.toDartString();
}
class PendingTransactionDescription {
PendingTransactionDescription({
required this.amount,
required this.fee,
required this.hash,
required this.hex,
required this.txKey,
required this.pointerAddress});
final int amount;
final int fee;
final String hash;
final String hex;
final String txKey;
final int pointerAddress;
}

@ -0,0 +1,13 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class SubaddressRow extends Struct {
@Int64()
external int id;
external Pointer<Utf8> address;
external Pointer<Utf8> label;
String getLabel() => label.toDartString();
String getAddress() => address.toDartString();
int getId() => id;
}

@ -0,0 +1,41 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class TransactionInfoRow extends Struct {
@Uint64()
external int amount;
@Uint64()
external int fee;
@Uint64()
external int blockHeight;
@Uint64()
external int confirmations;
@Uint32()
external int subaddrAccount;
@Int8()
external int direction;
@Int8()
external int isPending;
@Uint32()
external int subaddrIndex;
external Pointer<Utf8> hash;
external Pointer<Utf8> paymentId;
@Int64()
external int datetime;
int getDatetime() => datetime;
int getAmount() => amount >= 0 ? amount : amount * -1;
bool getIsPending() => isPending != 0;
String getHash() => hash.toDartString();
String getPaymentId() => paymentId.toDartString();
}

@ -0,0 +1,8 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
class Utf8Box extends Struct {
external Pointer<Utf8> value;
String getValue() => value.toDartString();
}

@ -0,0 +1,96 @@
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
import 'package:cw_wownero/api/signatures.dart';
import 'package:cw_wownero/api/types.dart';
import 'package:cw_wownero/api/wownero_api.dart';
import 'package:cw_wownero/api/structs/subaddress_row.dart';
import 'package:cw_wownero/api/wallet.dart';
final subaddressSizeNative = wowneroApi
.lookup<NativeFunction<subaddrress_size>>('subaddrress_size')
.asFunction<SubaddressSize>();
final subaddressRefreshNative = wowneroApi
.lookup<NativeFunction<subaddrress_refresh>>('subaddress_refresh')
.asFunction<SubaddressRefresh>();
final subaddrressGetAllNative = wowneroApi
.lookup<NativeFunction<subaddress_get_all>>('subaddrress_get_all')
.asFunction<SubaddressGetAll>();
final subaddrressAddNewNative = wowneroApi
.lookup<NativeFunction<subaddress_add_new>>('subaddress_add_row')
.asFunction<SubaddressAddNew>();
final subaddrressSetLabelNative = wowneroApi
.lookup<NativeFunction<subaddress_set_label>>('subaddress_set_label')
.asFunction<SubaddressSetLabel>();
bool isUpdating = false;
void refreshSubaddresses({required int accountIndex}) {
try {
isUpdating = true;
subaddressRefreshNative(accountIndex);
isUpdating = false;
} catch (e) {
isUpdating = false;
rethrow;
}
}
List<SubaddressRow> getAllSubaddresses() {
final size = subaddressSizeNative();
final subaddressAddressesPointer = subaddrressGetAllNative();
final subaddressAddresses = subaddressAddressesPointer.asTypedList(size);
return subaddressAddresses
.map((addr) => Pointer<SubaddressRow>.fromAddress(addr).ref)
.toList();
}
void addSubaddressSync({required int accountIndex, required String label}) {
final labelPointer = label.toNativeUtf8();
subaddrressAddNewNative(accountIndex, labelPointer);
calloc.free(labelPointer);
}
void setLabelForSubaddressSync(
{required int accountIndex, required int addressIndex, required String label}) {
final labelPointer = label.toNativeUtf8();
subaddrressSetLabelNative(accountIndex, addressIndex, labelPointer);
calloc.free(labelPointer);
}
void _addSubaddress(Map<String, dynamic> args) {
final label = args['label'] as String;
final accountIndex = args['accountIndex'] as int;
addSubaddressSync(accountIndex: accountIndex, label: label);
}
void _setLabelForSubaddress(Map<String, dynamic> args) {
final label = args['label'] as String;
final accountIndex = args['accountIndex'] as int;
final addressIndex = args['addressIndex'] as int;
setLabelForSubaddressSync(
accountIndex: accountIndex, addressIndex: addressIndex, label: label);
}
Future addSubaddress({required int accountIndex, required String label}) async {
await compute<Map<String, Object>, void>(
_addSubaddress, {'accountIndex': accountIndex, 'label': label});
await store();
}
Future setLabelForSubaddress(
{required int accountIndex, required int addressIndex, required String label}) async {
await compute<Map<String, Object>, void>(_setLabelForSubaddress, {
'accountIndex': accountIndex,
'addressIndex': addressIndex,
'label': label
});
await store();
}

@ -0,0 +1,281 @@
import 'dart:ffi';
import 'package:cw_wownero/api/convert_utf8_to_string.dart';
import 'package:cw_wownero/api/exceptions/creation_transaction_exception.dart';
import 'package:cw_wownero/api/wownero_api.dart';
import 'package:cw_wownero/api/wownero_output.dart';
import 'package:cw_wownero/api/signatures.dart';
import 'package:cw_wownero/api/structs/pending_transaction.dart';
import 'package:cw_wownero/api/structs/transaction_info_row.dart';
import 'package:cw_wownero/api/structs/ut8_box.dart';
import 'package:cw_wownero/api/types.dart';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
final transactionsRefreshNative = wowneroApi
.lookup<NativeFunction<transactions_refresh>>('transactions_refresh')
.asFunction<TransactionsRefresh>();
final transactionsCountNative = wowneroApi
.lookup<NativeFunction<transactions_count>>('transactions_count')
.asFunction<TransactionsCount>();
final transactionsGetAllNative = wowneroApi
.lookup<NativeFunction<transactions_get_all>>('transactions_get_all')
.asFunction<TransactionsGetAll>();
final transactionCreateNative = wowneroApi
.lookup<NativeFunction<transaction_create>>('transaction_create')
.asFunction<TransactionCreate>();
final transactionCreateMultDestNative = wowneroApi
.lookup<NativeFunction<transaction_create_mult_dest>>('transaction_create_mult_dest')
.asFunction<TransactionCreateMultDest>();
final transactionCommitNative = wowneroApi
.lookup<NativeFunction<transaction_commit>>('transaction_commit')
.asFunction<TransactionCommit>();
final getTxKeyNative =
wowneroApi.lookup<NativeFunction<get_tx_key>>('get_tx_key').asFunction<GetTxKey>();
final getTransactionNative = wowneroApi
.lookup<NativeFunction<get_transaction>>('get_transaction')
.asFunction<GetTransaction>();
String getTxKey(String txId) {
final txIdPointer = txId.toNativeUtf8();
final keyPointer = getTxKeyNative(txIdPointer);
calloc.free(txIdPointer);
if (keyPointer != null) {
return convertUTF8ToString(pointer: keyPointer);
}
return '';
}
void refreshTransactions() => transactionsRefreshNative();
int countOfTransactions() => transactionsCountNative();
List<TransactionInfoRow> getAllTransactions() {
final size = transactionsCountNative();
final transactionsPointer = transactionsGetAllNative();
final transactionsAddresses = transactionsPointer.asTypedList(size);
return transactionsAddresses
.map((addr) => Pointer<TransactionInfoRow>.fromAddress(addr).ref)
.toList();
}
TransactionInfoRow getTransaction(String txId) {
final txIdPointer = txId.toNativeUtf8();
return getTransactionNative(txIdPointer).ref;
}
PendingTransactionDescription createTransactionSync(
{required String address,
required String paymentId,
required int priorityRaw,
String? amount,
int accountIndex = 0,
List<String> preferredInputs = const []}) {
final addressPointer = address.toNativeUtf8();
final paymentIdPointer = paymentId.toNativeUtf8();
final amountPointer = amount != null ? amount.toNativeUtf8() : nullptr;
final int preferredInputsSize = preferredInputs.length;
final List<Pointer<Utf8>> preferredInputsPointers =
preferredInputs.map((output) => output.toNativeUtf8()).toList();
final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
for (int i = 0; i < preferredInputsSize; i++) {
preferredInputsPointerPointer[i] = preferredInputsPointers[i];
}
final errorMessagePointer = calloc<Utf8Box>();
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
final created = transactionCreateNative(
addressPointer,
paymentIdPointer,
amountPointer,
priorityRaw,
accountIndex,
preferredInputsPointerPointer,
preferredInputsSize,
errorMessagePointer,
pendingTransactionRawPointer) !=
0;
calloc.free(preferredInputsPointerPointer);
preferredInputsPointers.forEach((element) => calloc.free(element));
calloc.free(addressPointer);
calloc.free(paymentIdPointer);
if (amountPointer != nullptr) {
calloc.free(amountPointer);
}
if (!created) {
final message = errorMessagePointer.ref.getValue();
calloc.free(errorMessagePointer);
throw CreationTransactionException(message: message);
}
return PendingTransactionDescription(
amount: pendingTransactionRawPointer.ref.amount,
fee: pendingTransactionRawPointer.ref.fee,
hash: pendingTransactionRawPointer.ref.getHash(),
hex: pendingTransactionRawPointer.ref.getHex(),
txKey: pendingTransactionRawPointer.ref.getKey(),
pointerAddress: pendingTransactionRawPointer.address);
}
PendingTransactionDescription createTransactionMultDestSync(
{required List<MoneroOutput> outputs,
required String paymentId,
required int priorityRaw,
int accountIndex = 0,
List<String> preferredInputs = const []}) {
final int size = outputs.length;
final List<Pointer<Utf8>> addressesPointers =
outputs.map((output) => output.address.toNativeUtf8()).toList();
final Pointer<Pointer<Utf8>> addressesPointerPointer = calloc(size);
final List<Pointer<Utf8>> amountsPointers =
outputs.map((output) => output.amount.toNativeUtf8()).toList();
final Pointer<Pointer<Utf8>> amountsPointerPointer = calloc(size);
for (int i = 0; i < size; i++) {
addressesPointerPointer[i] = addressesPointers[i];
amountsPointerPointer[i] = amountsPointers[i];
}
final int preferredInputsSize = preferredInputs.length;
final List<Pointer<Utf8>> preferredInputsPointers =
preferredInputs.map((output) => output.toNativeUtf8()).toList();
final Pointer<Pointer<Utf8>> preferredInputsPointerPointer = calloc(preferredInputsSize);
for (int i = 0; i < preferredInputsSize; i++) {
preferredInputsPointerPointer[i] = preferredInputsPointers[i];
}
final paymentIdPointer = paymentId.toNativeUtf8();
final errorMessagePointer = calloc<Utf8Box>();
final pendingTransactionRawPointer = calloc<PendingTransactionRaw>();
final created = transactionCreateMultDestNative(
addressesPointerPointer,
paymentIdPointer,
amountsPointerPointer,
size,
priorityRaw,
accountIndex,
preferredInputsPointerPointer,
preferredInputsSize,
errorMessagePointer,
pendingTransactionRawPointer) !=
0;
calloc.free(addressesPointerPointer);
calloc.free(amountsPointerPointer);
calloc.free(preferredInputsPointerPointer);
addressesPointers.forEach((element) => calloc.free(element));
amountsPointers.forEach((element) => calloc.free(element));
preferredInputsPointers.forEach((element) => calloc.free(element));
calloc.free(paymentIdPointer);
if (!created) {
final message = errorMessagePointer.ref.getValue();
calloc.free(errorMessagePointer);
throw CreationTransactionException(message: message);
}
return PendingTransactionDescription(
amount: pendingTransactionRawPointer.ref.amount,
fee: pendingTransactionRawPointer.ref.fee,
hash: pendingTransactionRawPointer.ref.getHash(),
hex: pendingTransactionRawPointer.ref.getHex(),
txKey: pendingTransactionRawPointer.ref.getKey(),
pointerAddress: pendingTransactionRawPointer.address);
}
void commitTransactionFromPointerAddress({required int address}) =>
commitTransaction(transactionPointer: Pointer<PendingTransactionRaw>.fromAddress(address));
void commitTransaction({required Pointer<PendingTransactionRaw> transactionPointer}) {
final errorMessagePointer = calloc<Utf8Box>();
final isCommited = transactionCommitNative(transactionPointer, errorMessagePointer) != 0;
if (!isCommited) {
final message = errorMessagePointer.ref.getValue();
calloc.free(errorMessagePointer);
throw CreationTransactionException(message: message);
}
}
PendingTransactionDescription _createTransactionSync(Map args) {
final address = args['address'] as String;
final paymentId = args['paymentId'] as String;
final amount = args['amount'] as String?;
final priorityRaw = args['priorityRaw'] as int;
final accountIndex = args['accountIndex'] as int;
final preferredInputs = args['preferredInputs'] as List<String>;
return createTransactionSync(
address: address,
paymentId: paymentId,
amount: amount,
priorityRaw: priorityRaw,
accountIndex: accountIndex,
preferredInputs: preferredInputs);
}
PendingTransactionDescription _createTransactionMultDestSync(Map args) {
final outputs = args['outputs'] as List<MoneroOutput>;
final paymentId = args['paymentId'] as String;
final priorityRaw = args['priorityRaw'] as int;
final accountIndex = args['accountIndex'] as int;
final preferredInputs = args['preferredInputs'] as List<String>;
return createTransactionMultDestSync(
outputs: outputs,
paymentId: paymentId,
priorityRaw: priorityRaw,
accountIndex: accountIndex,
preferredInputs: preferredInputs);
}
Future<PendingTransactionDescription> createTransaction(
{required String address,
required int priorityRaw,
String? amount,
String paymentId = '',
int accountIndex = 0,
List<String> preferredInputs = const []}) =>
compute(_createTransactionSync, {
'address': address,
'paymentId': paymentId,
'amount': amount,
'priorityRaw': priorityRaw,
'accountIndex': accountIndex,
'preferredInputs': preferredInputs
});
Future<PendingTransactionDescription> createTransactionMultDest(
{required List<MoneroOutput> outputs,
required int priorityRaw,
String paymentId = '',
int accountIndex = 0,
List<String> preferredInputs = const []}) =>
compute(_createTransactionMultDestSync, {
'outputs': outputs,
'paymentId': paymentId,
'priorityRaw': priorityRaw,
'accountIndex': accountIndex,
'preferredInputs': preferredInputs
});

@ -0,0 +1,153 @@
import 'dart:ffi';
import 'package:cw_wownero/api/structs/coins_info_row.dart';
import 'package:cw_wownero/api/structs/pending_transaction.dart';
import 'package:cw_wownero/api/structs/transaction_info_row.dart';
import 'package:cw_wownero/api/structs/ut8_box.dart';
import 'package:ffi/ffi.dart';
typedef CreateWallet = int Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, Pointer<Utf8>);
typedef RestoreWalletFromSeed = int Function(
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
typedef RestoreWalletFromKeys = int Function(Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
typedef RestoreWalletFromSpendKey = int Function(Pointer<Utf8>, Pointer<Utf8>, Pointer<Utf8>,
Pointer<Utf8>, Pointer<Utf8>, int, int, Pointer<Utf8>);
typedef IsWalletExist = int Function(Pointer<Utf8>);
typedef LoadWallet = int Function(Pointer<Utf8>, Pointer<Utf8>, int);
typedef ErrorString = Pointer<Utf8> Function();
typedef GetFilename = Pointer<Utf8> Function();
typedef GetSeed = Pointer<Utf8> Function();
typedef GetAddress = Pointer<Utf8> Function(int, int);
typedef GetFullBalance = int Function(int);
typedef GetUnlockedBalance = int Function(int);
typedef GetCurrentHeight = int Function();
typedef GetNodeHeight = int Function();
typedef IsConnected = int Function();
typedef SetupNode = int Function(
Pointer<Utf8>, Pointer<Utf8>?, Pointer<Utf8>?, int, int, Pointer<Utf8>?, Pointer<Utf8>);
typedef StartRefresh = void Function();
typedef ConnectToNode = int Function();
typedef SetRefreshFromBlockHeight = void Function(int);
typedef SetRecoveringFromSeed = void Function(int);
typedef Store = void Function(Pointer<Utf8>);
typedef SetPassword = int Function(Pointer<Utf8> password, Pointer<Utf8Box> error);
typedef SetListener = void Function();
typedef GetSyncingHeight = int Function();
typedef IsNeededToRefresh = int Function();
typedef IsNewTransactionExist = int Function();
typedef SubaddressSize = int Function();
typedef SubaddressRefresh = void Function(int);
typedef SubaddressGetAll = Pointer<Int64> Function();
typedef SubaddressAddNew = void Function(int accountIndex, Pointer<Utf8> label);
typedef SubaddressSetLabel = void Function(
int accountIndex, int addressIndex, Pointer<Utf8> label);
typedef AccountSize = int Function();
typedef AccountRefresh = void Function();
typedef AccountGetAll = Pointer<Int64> Function();
typedef AccountAddNew = void Function(Pointer<Utf8> label);
typedef AccountSetLabel = void Function(int accountIndex, Pointer<Utf8> label);
typedef TransactionsRefresh = void Function();
typedef GetTransaction = Pointer<TransactionInfoRow> Function(Pointer<Utf8> txId);
typedef GetTxKey = Pointer<Utf8>? Function(Pointer<Utf8> txId);
typedef TransactionsCount = int Function();
typedef TransactionsGetAll = Pointer<Int64> Function();
typedef TransactionCreate = int Function(
Pointer<Utf8> address,
Pointer<Utf8> paymentId,
Pointer<Utf8> amount,
int priorityRaw,
int subaddrAccount,
Pointer<Pointer<Utf8>> preferredInputs,
int preferredInputsSize,
Pointer<Utf8Box> error,
Pointer<PendingTransactionRaw> pendingTransaction);
typedef TransactionCreateMultDest = int Function(
Pointer<Pointer<Utf8>> addresses,
Pointer<Utf8> paymentId,
Pointer<Pointer<Utf8>> amounts,
int size,
int priorityRaw,
int subaddrAccount,
Pointer<Pointer<Utf8>> preferredInputs,
int preferredInputsSize,
Pointer<Utf8Box> error,
Pointer<PendingTransactionRaw> pendingTransaction);
typedef TransactionCommit = int Function(Pointer<PendingTransactionRaw>, Pointer<Utf8Box>);
typedef SecretViewKey = Pointer<Utf8> Function();
typedef PublicViewKey = Pointer<Utf8> Function();
typedef SecretSpendKey = Pointer<Utf8> Function();
typedef PublicSpendKey = Pointer<Utf8> Function();
typedef CloseCurrentWallet = void Function();
typedef OnStartup = void Function();
typedef RescanBlockchainAsync = void Function();
typedef GetSubaddressLabel = Pointer<Utf8> Function(
int accountIndex,
int addressIndex);
typedef SetTrustedDaemon = void Function(int);
typedef TrustedDaemon = int Function();
typedef RefreshCoins = void Function(int);
typedef CoinsCount = int Function();
typedef GetCoin = Pointer<CoinsInfoRow> Function(int);
typedef FreezeCoin = void Function(int);
typedef ThawCoin = void Function(int);
typedef SignMessage = Pointer<Utf8> Function(Pointer<Utf8>, Pointer<Utf8>);

@ -0,0 +1,399 @@
import 'dart:async';
import 'dart:ffi';
import 'package:ffi/ffi.dart';
import 'package:cw_wownero/api/structs/ut8_box.dart';
import 'package:cw_wownero/api/convert_utf8_to_string.dart';
import 'package:cw_wownero/api/signatures.dart';
import 'package:cw_wownero/api/types.dart';
import 'package:cw_wownero/api/wownero_api.dart';
import 'package:cw_wownero/api/exceptions/setup_wallet_exception.dart';
import 'package:flutter/foundation.dart';
int _boolToInt(bool value) => value ? 1 : 0;
final getFileNameNative = wowneroApi
.lookup<NativeFunction<get_filename>>('get_filename')
.asFunction<GetFilename>();
final getSeedNative =
wowneroApi.lookup<NativeFunction<get_seed>>('seed').asFunction<GetSeed>();
final getAddressNative = wowneroApi
.lookup<NativeFunction<get_address>>('get_address')
.asFunction<GetAddress>();
final getFullBalanceNative = wowneroApi
.lookup<NativeFunction<get_full_balanace>>('get_full_balance')
.asFunction<GetFullBalance>();
final getUnlockedBalanceNative = wowneroApi
.lookup<NativeFunction<get_unlocked_balanace>>('get_unlocked_balance')
.asFunction<GetUnlockedBalance>();
final getCurrentHeightNative = wowneroApi
.lookup<NativeFunction<get_current_height>>('get_current_height')
.asFunction<GetCurrentHeight>();
final getNodeHeightNative = wowneroApi
.lookup<NativeFunction<get_node_height>>('get_node_height')
.asFunction<GetNodeHeight>();
final isConnectedNative = wowneroApi
.lookup<NativeFunction<is_connected>>('is_connected')
.asFunction<IsConnected>();
final setupNodeNative = wowneroApi
.lookup<NativeFunction<setup_node>>('setup_node')
.asFunction<SetupNode>();
final startRefreshNative = wowneroApi
.lookup<NativeFunction<start_refresh>>('start_refresh')
.asFunction<StartRefresh>();
final connecToNodeNative = wowneroApi
.lookup<NativeFunction<connect_to_node>>('connect_to_node')
.asFunction<ConnectToNode>();
final setRefreshFromBlockHeightNative = wowneroApi
.lookup<NativeFunction<set_refresh_from_block_height>>(
'set_refresh_from_block_height')
.asFunction<SetRefreshFromBlockHeight>();
final setRecoveringFromSeedNative = wowneroApi
.lookup<NativeFunction<set_recovering_from_seed>>(
'set_recovering_from_seed')
.asFunction<SetRecoveringFromSeed>();
final storeNative =
wowneroApi.lookup<NativeFunction<store_c>>('store').asFunction<Store>();
final setPasswordNative =
wowneroApi.lookup<NativeFunction<set_password>>('set_password').asFunction<SetPassword>();
final setListenerNative = wowneroApi
.lookup<NativeFunction<set_listener>>('set_listener')
.asFunction<SetListener>();
final getSyncingHeightNative = wowneroApi
.lookup<NativeFunction<get_syncing_height>>('get_syncing_height')
.asFunction<GetSyncingHeight>();
final isNeededToRefreshNative = wowneroApi
.lookup<NativeFunction<is_needed_to_refresh>>('is_needed_to_refresh')
.asFunction<IsNeededToRefresh>();
final isNewTransactionExistNative = wowneroApi
.lookup<NativeFunction<is_new_transaction_exist>>(
'is_new_transaction_exist')
.asFunction<IsNewTransactionExist>();
final getSecretViewKeyNative = wowneroApi
.lookup<NativeFunction<secret_view_key>>('secret_view_key')
.asFunction<SecretViewKey>();
final getPublicViewKeyNative = wowneroApi
.lookup<NativeFunction<public_view_key>>('public_view_key')
.asFunction<PublicViewKey>();
final getSecretSpendKeyNative = wowneroApi
.lookup<NativeFunction<secret_spend_key>>('secret_spend_key')
.asFunction<SecretSpendKey>();
final getPublicSpendKeyNative = wowneroApi
.lookup<NativeFunction<secret_view_key>>('public_spend_key')
.asFunction<PublicSpendKey>();
final closeCurrentWalletNative = wowneroApi
.lookup<NativeFunction<close_current_wallet>>('close_current_wallet')
.asFunction<CloseCurrentWallet>();
final onStartupNative = wowneroApi
.lookup<NativeFunction<on_startup>>('on_startup')
.asFunction<OnStartup>();
final rescanBlockchainAsyncNative = wowneroApi
.lookup<NativeFunction<rescan_blockchain>>('rescan_blockchain')
.asFunction<RescanBlockchainAsync>();
final getSubaddressLabelNative = wowneroApi
.lookup<NativeFunction<get_subaddress_label>>('get_subaddress_label')
.asFunction<GetSubaddressLabel>();
final setTrustedDaemonNative = wowneroApi
.lookup<NativeFunction<set_trusted_daemon>>('set_trusted_daemon')
.asFunction<SetTrustedDaemon>();
final trustedDaemonNative = wowneroApi
.lookup<NativeFunction<trusted_daemon>>('trusted_daemon')
.asFunction<TrustedDaemon>();
final signMessageNative = wowneroApi
.lookup<NativeFunction<sign_message>>('sign_message')
.asFunction<SignMessage>();
int getSyncingHeight() => getSyncingHeightNative();
bool isNeededToRefresh() => isNeededToRefreshNative() != 0;
bool isNewTransactionExist() => isNewTransactionExistNative() != 0;
String getFilename() => convertUTF8ToString(pointer: getFileNameNative());
String getSeed() => convertUTF8ToString(pointer: getSeedNative());
String getAddress({int accountIndex = 0, int addressIndex = 0}) =>
convertUTF8ToString(pointer: getAddressNative(accountIndex, addressIndex));
int getFullBalance({int accountIndex = 0}) =>
getFullBalanceNative(accountIndex);
int getUnlockedBalance({int accountIndex = 0}) =>
getUnlockedBalanceNative(accountIndex);
int getCurrentHeight() => getCurrentHeightNative();
int getNodeHeightSync() => getNodeHeightNative();
bool isConnectedSync() => isConnectedNative() != 0;
bool setupNodeSync(
{required String address,
String? login,
String? password,
bool useSSL = false,
bool isLightWallet = false,
String? socksProxyAddress}) {
final addressPointer = address.toNativeUtf8();
Pointer<Utf8>? loginPointer;
Pointer<Utf8>? socksProxyAddressPointer;
Pointer<Utf8>? passwordPointer;
if (login != null) {
loginPointer = login.toNativeUtf8();
}
if (password != null) {
passwordPointer = password.toNativeUtf8();
}
if (socksProxyAddress != null) {
socksProxyAddressPointer = socksProxyAddress.toNativeUtf8();
}
final errorMessagePointer = ''.toNativeUtf8();
final isSetupNode = setupNodeNative(
addressPointer,
loginPointer,
passwordPointer,
_boolToInt(useSSL),
_boolToInt(isLightWallet),
socksProxyAddressPointer,
errorMessagePointer) !=
0;
calloc.free(addressPointer);
if (loginPointer != null) {
calloc.free(loginPointer);
}
if (passwordPointer != null) {
calloc.free(passwordPointer);
}
if (!isSetupNode) {
throw SetupWalletException(
message: convertUTF8ToString(pointer: errorMessagePointer));
}
return isSetupNode;
}
void startRefreshSync() => startRefreshNative();
Future<bool> connectToNode() async => connecToNodeNative() != 0;
void setRefreshFromBlockHeight({required int height}) =>
setRefreshFromBlockHeightNative(height);
void setRecoveringFromSeed({required bool isRecovery}) =>
setRecoveringFromSeedNative(_boolToInt(isRecovery));
void storeSync() {
final pathPointer = ''.toNativeUtf8();
storeNative(pathPointer);
calloc.free(pathPointer);
}
void setPasswordSync(String password) {
final passwordPointer = password.toNativeUtf8();
final errorMessagePointer = calloc<Utf8Box>();
final changed = setPasswordNative(passwordPointer, errorMessagePointer) != 0;
calloc.free(passwordPointer);
if (!changed) {
final message = errorMessagePointer.ref.getValue();
calloc.free(errorMessagePointer);
throw Exception(message);
}
calloc.free(errorMessagePointer);
}
void closeCurrentWallet() => closeCurrentWalletNative();
String getSecretViewKey() =>
convertUTF8ToString(pointer: getSecretViewKeyNative());
String getPublicViewKey() =>
convertUTF8ToString(pointer: getPublicViewKeyNative());
String getSecretSpendKey() =>
convertUTF8ToString(pointer: getSecretSpendKeyNative());
String getPublicSpendKey() =>
convertUTF8ToString(pointer: getPublicSpendKeyNative());
class SyncListener {
SyncListener(this.onNewBlock, this.onNewTransaction)
: _cachedBlockchainHeight = 0,
_lastKnownBlockHeight = 0,
_initialSyncHeight = 0;
void Function(int, int, double) onNewBlock;
void Function() onNewTransaction;
Timer? _updateSyncInfoTimer;
int _cachedBlockchainHeight;
int _lastKnownBlockHeight;
int _initialSyncHeight;
Future<int> getNodeHeightOrUpdate(int baseHeight) async {
if (_cachedBlockchainHeight < baseHeight || _cachedBlockchainHeight == 0) {
_cachedBlockchainHeight = await getNodeHeight();
}
return _cachedBlockchainHeight;
}
void start() {
_cachedBlockchainHeight = 0;
_lastKnownBlockHeight = 0;
_initialSyncHeight = 0;
_updateSyncInfoTimer ??=
Timer.periodic(Duration(milliseconds: 1200), (_) async {
if (isNewTransactionExist()) {
onNewTransaction();
}
var syncHeight = getSyncingHeight();
if (syncHeight <= 0) {
syncHeight = getCurrentHeight();
}
if (_initialSyncHeight <= 0) {
_initialSyncHeight = syncHeight;
}
final bchHeight = await getNodeHeightOrUpdate(syncHeight);
if (_lastKnownBlockHeight == syncHeight) {
return;
}
_lastKnownBlockHeight = syncHeight;
final track = bchHeight - _initialSyncHeight;
final diff = track - (bchHeight - syncHeight);
final ptc = diff <= 0 ? 0.0 : diff / track;
final left = bchHeight - syncHeight;
if (syncHeight < 0 || left < 0) {
return;
}
// 1. Actual new height; 2. Blocks left to finish; 3. Progress in percents;
onNewBlock.call(syncHeight, left, ptc);
});
}
void stop() => _updateSyncInfoTimer?.cancel();
}
SyncListener setListeners(void Function(int, int, double) onNewBlock,
void Function() onNewTransaction) {
final listener = SyncListener(onNewBlock, onNewTransaction);
setListenerNative();
return listener;
}
void onStartup() => onStartupNative();
void _storeSync(Object _) => storeSync();
bool _setupNodeSync(Map<String, Object?> args) {
final address = args['address'] as String;
final login = (args['login'] ?? '') as String;
final password = (args['password'] ?? '') as String;
final useSSL = args['useSSL'] as bool;
final isLightWallet = args['isLightWallet'] as bool;
final socksProxyAddress = (args['socksProxyAddress'] ?? '') as String;
return setupNodeSync(
address: address,
login: login,
password: password,
useSSL: useSSL,
isLightWallet: isLightWallet,
socksProxyAddress: socksProxyAddress);
}
bool _isConnected(Object _) => isConnectedSync();
int _getNodeHeight(Object _) => getNodeHeightSync();
void startRefresh() => startRefreshSync();
Future<void> setupNode(
{required String address,
String? login,
String? password,
bool useSSL = false,
String? socksProxyAddress,
bool isLightWallet = false}) =>
compute<Map<String, Object?>, void>(_setupNodeSync, {
'address': address,
'login': login ,
'password': password,
'useSSL': useSSL,
'isLightWallet': isLightWallet,
'socksProxyAddress': socksProxyAddress
});
Future<void> store() => compute<int, void>(_storeSync, 0);
Future<bool> isConnected() => compute(_isConnected, 0);
Future<int> getNodeHeight() => compute(_getNodeHeight, 0);
void rescanBlockchainAsync() => rescanBlockchainAsyncNative();
String getSubaddressLabel(int accountIndex, int addressIndex) {
return convertUTF8ToString(pointer: getSubaddressLabelNative(accountIndex, addressIndex));
}
Future setTrustedDaemon(bool trusted) async => setTrustedDaemonNative(_boolToInt(trusted));
Future<bool> trustedDaemon() async => trustedDaemonNative() != 0;
String signMessage(String message, {String address = ""}) {
final messagePointer = message.toNativeUtf8();
final addressPointer = address.toNativeUtf8();
final signature = convertUTF8ToString(pointer: signMessageNative(messagePointer, addressPointer));
calloc.free(messagePointer);
calloc.free(addressPointer);
return signature;
}

@ -0,0 +1,333 @@
import 'dart:ffi';
import 'package:cw_wownero/api/convert_utf8_to_string.dart';
import 'package:cw_wownero/api/exceptions/wallet_creation_exception.dart';
import 'package:cw_wownero/api/exceptions/wallet_opening_exception.dart';
import 'package:cw_wownero/api/exceptions/wallet_restore_from_keys_exception.dart';
import 'package:cw_wownero/api/exceptions/wallet_restore_from_seed_exception.dart';
import 'package:cw_wownero/api/wownero_api.dart';
import 'package:cw_wownero/api/signatures.dart';
import 'package:cw_wownero/api/types.dart';
import 'package:cw_wownero/api/wallet.dart';
import 'package:ffi/ffi.dart';
import 'package:flutter/foundation.dart';
final createWalletNative = wowneroApi
.lookup<NativeFunction<create_wallet>>('create_wallet')
.asFunction<CreateWallet>();
final restoreWalletFromSeedNative = wowneroApi
.lookup<NativeFunction<restore_wallet_from_seed>>(
'restore_wallet_from_seed')
.asFunction<RestoreWalletFromSeed>();
final restoreWalletFromKeysNative = wowneroApi
.lookup<NativeFunction<restore_wallet_from_keys>>(
'restore_wallet_from_keys')
.asFunction<RestoreWalletFromKeys>();
final restoreWalletFromSpendKeyNative = wowneroApi
.lookup<NativeFunction<restore_wallet_from_spend_key>>(
'restore_wallet_from_spend_key')
.asFunction<RestoreWalletFromSpendKey>();
final isWalletExistNative = wowneroApi
.lookup<NativeFunction<is_wallet_exist>>('is_wallet_exist')
.asFunction<IsWalletExist>();
final loadWalletNative = wowneroApi
.lookup<NativeFunction<load_wallet>>('load_wallet')
.asFunction<LoadWallet>();
final errorStringNative = wowneroApi
.lookup<NativeFunction<error_string>>('error_string')
.asFunction<ErrorString>();
void createWalletSync(
{required String path,
required String password,
required String language,
int nettype = 0}) {
final pathPointer = path.toNativeUtf8();
final passwordPointer = password.toNativeUtf8();
final languagePointer = language.toNativeUtf8();
final errorMessagePointer = ''.toNativeUtf8();
final isWalletCreated = createWalletNative(pathPointer, passwordPointer,
languagePointer, nettype, errorMessagePointer) !=
0;
calloc.free(pathPointer);
calloc.free(passwordPointer);
calloc.free(languagePointer);
if (!isWalletCreated) {
throw WalletCreationException(
message: convertUTF8ToString(pointer: errorMessagePointer));
}
// setupNodeSync(address: "node.wowneroworld.com:18089");
}
bool isWalletExistSync({required String path}) {
final pathPointer = path.toNativeUtf8();
final isExist = isWalletExistNative(pathPointer) != 0;
calloc.free(pathPointer);
return isExist;
}
void restoreWalletFromSeedSync(
{required String path,
required String password,
required String seed,
int nettype = 0,
int restoreHeight = 0}) {
final pathPointer = path.toNativeUtf8();
final passwordPointer = password.toNativeUtf8();
final seedPointer = seed.toNativeUtf8();
final errorMessagePointer = ''.toNativeUtf8();
final isWalletRestored = restoreWalletFromSeedNative(
pathPointer,
passwordPointer,
seedPointer,
nettype,
restoreHeight,
errorMessagePointer) !=
0;
calloc.free(pathPointer);
calloc.free(passwordPointer);
calloc.free(seedPointer);
if (!isWalletRestored) {
throw WalletRestoreFromSeedException(
message: convertUTF8ToString(pointer: errorMessagePointer));
}
}
void restoreWalletFromKeysSync(
{required String path,
required String password,
required String language,
required String address,
required String viewKey,
required String spendKey,
int nettype = 0,
int restoreHeight = 0}) {
final pathPointer = path.toNativeUtf8();
final passwordPointer = password.toNativeUtf8();
final languagePointer = language.toNativeUtf8();
final addressPointer = address.toNativeUtf8();
final viewKeyPointer = viewKey.toNativeUtf8();
final spendKeyPointer = spendKey.toNativeUtf8();
final errorMessagePointer = ''.toNativeUtf8();
final isWalletRestored = restoreWalletFromKeysNative(
pathPointer,
passwordPointer,
languagePointer,
addressPointer,
viewKeyPointer,
spendKeyPointer,
nettype,
restoreHeight,
errorMessagePointer) !=
0;
calloc.free(pathPointer);
calloc.free(passwordPointer);
calloc.free(languagePointer);
calloc.free(addressPointer);
calloc.free(viewKeyPointer);
calloc.free(spendKeyPointer);
if (!isWalletRestored) {
throw WalletRestoreFromKeysException(
message: convertUTF8ToString(pointer: errorMessagePointer));
}
}
void restoreWalletFromSpendKeySync(
{required String path,
required String password,
required String seed,
required String language,
required String spendKey,
int nettype = 0,
int restoreHeight = 0}) {
final pathPointer = path.toNativeUtf8();
final passwordPointer = password.toNativeUtf8();
final seedPointer = seed.toNativeUtf8();
final languagePointer = language.toNativeUtf8();
final spendKeyPointer = spendKey.toNativeUtf8();
final errorMessagePointer = ''.toNativeUtf8();
final isWalletRestored = restoreWalletFromSpendKeyNative(
pathPointer,
passwordPointer,
seedPointer,
languagePointer,
spendKeyPointer,
nettype,
restoreHeight,
errorMessagePointer) !=
0;
calloc.free(pathPointer);
calloc.free(passwordPointer);
calloc.free(languagePointer);
calloc.free(spendKeyPointer);
storeSync();
if (!isWalletRestored) {
throw WalletRestoreFromKeysException(
message: convertUTF8ToString(pointer: errorMessagePointer));
}
}
void loadWallet({
required String path,
required String password,
int nettype = 0}) {
final pathPointer = path.toNativeUtf8();
final passwordPointer = password.toNativeUtf8();
final loaded = loadWalletNative(pathPointer, passwordPointer, nettype) != 0;
calloc.free(pathPointer);
calloc.free(passwordPointer);
if (!loaded) {
throw WalletOpeningException(
message: convertUTF8ToString(pointer: errorStringNative()));
}
}
void _createWallet(Map<String, dynamic> args) {
final path = args['path'] as String;
final password = args['password'] as String;
final language = args['language'] as String;
createWalletSync(path: path, password: password, language: language);
}
void _restoreFromSeed(Map<String, dynamic> args) {
final path = args['path'] as String;
final password = args['password'] as String;
final seed = args['seed'] as String;
final restoreHeight = args['restoreHeight'] as int;
restoreWalletFromSeedSync(
path: path, password: password, seed: seed, restoreHeight: restoreHeight);
}
void _restoreFromKeys(Map<String, dynamic> args) {
final path = args['path'] as String;
final password = args['password'] as String;
final language = args['language'] as String;
final restoreHeight = args['restoreHeight'] as int;
final address = args['address'] as String;
final viewKey = args['viewKey'] as String;
final spendKey = args['spendKey'] as String;
restoreWalletFromKeysSync(
path: path,
password: password,
language: language,
restoreHeight: restoreHeight,
address: address,
viewKey: viewKey,
spendKey: spendKey);
}
void _restoreFromSpendKey(Map<String, dynamic> args) {
final path = args['path'] as String;
final password = args['password'] as String;
final seed = args['seed'] as String;
final language = args['language'] as String;
final spendKey = args['spendKey'] as String;
final restoreHeight = args['restoreHeight'] as int;
restoreWalletFromSpendKeySync(
path: path,
password: password,
seed: seed,
language: language,
restoreHeight: restoreHeight,
spendKey: spendKey);
}
Future<void> _openWallet(Map<String, String> args) async =>
loadWallet(path: args['path'] as String, password: args['password'] as String);
bool _isWalletExist(String path) => isWalletExistSync(path: path);
void openWallet({required String path, required String password, int nettype = 0}) async =>
loadWallet(path: path, password: password, nettype: nettype);
Future<void> openWalletAsync(Map<String, String> args) async =>
compute(_openWallet, args);
Future<void> createWallet(
{required String path,
required String password,
required String language,
int nettype = 0}) async =>
compute(_createWallet, {
'path': path,
'password': password,
'language': language,
'nettype': nettype
});
Future<void> restoreFromSeed(
{required String path,
required String password,
required String seed,
int nettype = 0,
int restoreHeight = 0}) async =>
compute<Map<String, Object>, void>(_restoreFromSeed, {
'path': path,
'password': password,
'seed': seed,
'nettype': nettype,
'restoreHeight': restoreHeight
});
Future<void> restoreFromKeys(
{required String path,
required String password,
required String language,
required String address,
required String viewKey,
required String spendKey,
int nettype = 0,
int restoreHeight = 0}) async =>
compute<Map<String, Object>, void>(_restoreFromKeys, {
'path': path,
'password': password,
'language': language,
'address': address,
'viewKey': viewKey,
'spendKey': spendKey,
'nettype': nettype,
'restoreHeight': restoreHeight
});
Future<void> restoreFromSpendKey(
{required String path,
required String password,
required String seed,
required String language,
required String spendKey,
int nettype = 0,
int restoreHeight = 0}) async =>
compute<Map<String, Object>, void>(_restoreFromSpendKey, {
'path': path,
'password': password,
'seed': seed,
'language': language,
'spendKey': spendKey,
'nettype': nettype,
'restoreHeight': restoreHeight
});
Future<bool> isWalletExist({required String path}) => compute(_isWalletExist, path);

@ -0,0 +1,6 @@
import 'dart:ffi';
import 'dart:io';
final DynamicLibrary wowneroApi = Platform.isAndroid
? DynamicLibrary.open("libcw_wownero.so")
: DynamicLibrary.open("cw_wownero.framework/cw_wownero");

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save