AlphaWallet / alpha-wallet-android

An advanced Ethereum mobile wallet
https://www.alphawallet.com
MIT License
585 stars 529 forks source link

support for Non EVM chain. #2950

Open theultrastarter opened 1 year ago

theultrastarter commented 1 year ago

H @seabornlee , @JamesSmartCell and all. I tout i could pull this off on my own but coudnt, lol. I want to include a non evm chain to the wallet. Vite chain to be precise. This is the idea, i want to use the already generated passphrase to generate a vite address for vite transactions.

JamesSmartCell commented 1 year ago

H @seabornlee , @JamesSmartCell and all. I tout i could pull this off on my own but coudnt, lol. I want to include a non evm chain to the wallet. Vite chain to be precise. This is the idea, i want to use the already generated passphrase to generate a vite address for vite transactions.

This is going to be tricky but is a direction we will probably go in. You'd need to abstract both the key handing/signing and address classes. Which is quite a lot of work.

I'm assuming the non EVM chain uses a different format for addresses, and possibly a different EC key format like eddsa?

theultrastarter commented 1 year ago

Yh it uses a different format. It begins with "vite_" and follows it up with a 50 alpha numeric string. This is an example vite_73bb34c904639cdc410cd20ee893908b9bfc55bfd27534d6f5 So I want to make the wallet generation happen in the background just like the ether address.

On Wed, Nov 16, 2022, 10:53 PM James Brown @.***> wrote:

H @seabornlee https://github.com/seabornlee , @JamesSmartCell https://github.com/JamesSmartCell and all. I tout i could pull this off on my own but coudnt, lol. I want to include a non evm chain to the wallet. Vite chain to be precise. This is the idea, i want to use the already generated passphrase to generate a vite address for vite transactions.

This is going to be tricky but is a direction we will probably go in. You'd need to abstract both the key handing/signing and address classes. Which is quite a lot of work.

I'm assuming the non EVM chain uses a different format for addresses, and possibly a different EC key format like eddsa?

— Reply to this email directly, view it on GitHub https://github.com/AlphaWallet/alpha-wallet-android/issues/2950#issuecomment-1317782375, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMS7FV3NUXGM4X52G6XKGP3WIVQV7ANCNFSM6AAAAAASCQERGU . You are receiving this because you modified the open/close state.Message ID: @.***>

JamesSmartCell commented 1 year ago

Yh it uses a different format. It begins with "vite_" and follows it up with a 50 alpha numeric string. This is an example vite_73bb34c904639cdc410cd20ee893908b9bfc55bfd27534d6f5 So I want to make the wallet generation happen in the background just like the ether address.

On Wed, Nov 16, 2022, 10:53 PM James Brown @.***> wrote:

H @seabornlee https://github.com/seabornlee , @JamesSmartCell https://github.com/JamesSmartCell and all. I tout i could pull this off on my own but coudnt, lol. I want to include a non evm chain to the wallet. Vite chain to be precise. This is the idea, i want to use the already generated passphrase to generate a vite address for vite transactions.

This is going to be tricky but is a direction we will probably go in. You'd need to abstract both the key handing/signing and address classes. Which is quite a lot of work.

I'm assuming the non EVM chain uses a different format for addresses, and possibly a different EC key format like eddsa?

— Reply to this email directly, view it on GitHub https://github.com/AlphaWallet/alpha-wallet-android/issues/2950#issuecomment-1317782375, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMS7FV3NUXGM4X52G6XKGP3WIVQV7ANCNFSM6AAAAAASCQERGU . You are receiving this because you modified the open/close state.Message ID: @.***>

Yep that's what I figured, yes we'll be heading down that path but it isn't a high priority at the moment. It touches a lot of critical components so it'll require some careful auditing.

theultrastarter commented 1 year ago

Ok that was my biggest fear too.lol I will try something on my own and give my feedback. Buh what file generate the ether address,

On Wed, Nov 16, 2022, 11:41 PM James Brown @.***> wrote:

Yh it uses a different format. It begins with "vite_" and follows it up with a 50 alpha numeric string. This is an example vite_73bb34c904639cdc410cd20ee893908b9bfc55bfd27534d6f5 So I want to make the wallet generation happen in the background just like the ether address.

On Wed, Nov 16, 2022, 10:53 PM James Brown @.***> wrote:

H @seabornlee https://github.com/seabornlee https://github.com/seabornlee , @JamesSmartCell https://github.com/JamesSmartCell https://github.com/JamesSmartCell and all. I tout i could pull this off on my own but coudnt, lol. I want to include a non evm chain to the wallet. Vite chain to be precise. This is the idea, i want to use the already generated passphrase to generate a vite address for vite transactions.

This is going to be tricky but is a direction we will probably go in. You'd need to abstract both the key handing/signing and address classes. Which is quite a lot of work.

I'm assuming the non EVM chain uses a different format for addresses, and possibly a different EC key format like eddsa?

— Reply to this email directly, view it on GitHub

2950 (comment)

https://github.com/AlphaWallet/alpha-wallet-android/issues/2950#issuecomment-1317782375 , or unsubscribe

https://github.com/notifications/unsubscribe-auth/AMS7FV3NUXGM4X52G6XKGP3WIVQV7ANCNFSM6AAAAAASCQERGU . You are receiving this because you modified the open/close state.Message ID: @.***>

Yep that's what I figured, yes we'll be heading down that path but it isn't a high priority at the moment. It touches a lot of critical components so it'll require some careful auditing.

— Reply to this email directly, view it on GitHub https://github.com/AlphaWallet/alpha-wallet-android/issues/2950#issuecomment-1317827055, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMS7FV3OXX7HBGQUUSJEV5TWIVWMHANCNFSM6AAAAAASCQERGU . You are receiving this because you modified the open/close state.Message ID: @.***>

JamesSmartCell commented 1 year ago

It's all done in web3j. So we'd need to abstract the Keyservice and Wallet classes to begin with. Possibly you could abstract the address component of Wallet class, as then you'll get all the instances where the address is pulled from. You'd need the same class to be used in TokenInfo as token contracts would be using the same address format.

That's where I'd start on this.

Then I'd go through the signing uses and abstract those where needed. The Keyservice might not need so much work

theultrastarter commented 1 year ago

Got it. I will start working on that asap and send my feedback. Thanks for the time. Really appreciate it.

On Wed, Nov 16, 2022, 11:50 PM James Brown @.***> wrote:

It's all done in web3j. So we'd need to abstract the Keyservice and Wallet classes to begin with. Possibly you could abstract the address component of Wallet class, as then you'll get all the instances where the address is pulled from. You'd need the same class to be used in TokenInfo as token contracts would be using the same address format.

That's where I'd start on this.

Then I'd go through the signing uses and abstract those where needed. The Keyservice might not need so much work

— Reply to this email directly, view it on GitHub https://github.com/AlphaWallet/alpha-wallet-android/issues/2950#issuecomment-1317834149, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMS7FV6CQAHVIMGLJ3TZWRDWIVXLZANCNFSM6AAAAAASCQERGU . You are receiving this because you modified the open/close state.Message ID: @.***>

theultrastarter commented 1 year ago

import 'dart:math'; import 'dart:typed_data';

import 'package:decimal/decimal.dart'; import 'package:flutter/foundation.dart'; import 'package:vite/utils.dart'; import 'package:vite/vite.dart' as vite;

import '../encrypt/crypter.dart'; import '../quota/quota_stake_amounts.dart';

String getShortString(vite.ViteAddress address) { assert(vite.Address.isValid(address)); return address.substring(0, 11) + "..." + address.substring(address.length - 6); }

String getShorterString(vite.ViteAddress address) { assert(vite.Address.isValid(address)); return address.substring(0, 9) + "..." + address.substring(address.length - 4); }

class ViteUtil { const ViteUtil();

static final viteAddressRegex = RegExp(r'vite_[0-9a-h]{50}');

static const viteTokenId = vite.viteTokenId; static const viteZeroAddress = 'vite_0000000000000000000000000000000000000000a4f3a0cb58';

static String generateMnemonic({int strength = 128}) { return vite.generateMnemonic(strength: strength); }

static const seedLength = 128;

static bool isValidSeed(String seed) { return isHex(seed) && seed.length == seedLength; }

static bool isEncryptedHex(String hex) { try { final salted = bytesUtf8ToString(hexToBytes(hex.substring(0, 16))); return salted == 'Salted__'; } catch (e) { return false; } }

static vite.ViteAddress? findAddressInString(String value) { final match = viteAddressRegex.firstMatch(value); if (match != null) { final address = match.group(0); if (address != null && vite.Address.isValid(address)) { return address; } } return null; }

static bool isValidAddress(String address) { return vite.Address.isValid(address); }

static String? mnemonicFromViteAppLink(String link) { if (!link.startsWith('viteapp://backup-wallet?')) { return null; } try { final uri = Uri.parse(link); final language = uri.queryParameters['language']; if (language != 'en') { return null; } final entropy = uri.queryParameters['entropy']; final lang = uri.queryParameters['language'] ?? 'en'; if (entropy == null || lang != 'en') { return null; } final mnemonic = mnemonicWordsFromEntropyHex(entropy).join(' '); return mnemonic; } catch (e) { return null; } }

static String? walletNameFromViteAppLink(String link) { if (!link.startsWith('viteapp://backup-wallet?')) { return null; } try { final uri = Uri.parse(link); final name = uri.queryParameters['name']; return name; } catch (e) { return null; } }

static bool isValidMnemonicWord(String word) { return vite.isValidMnemonicWord(word); }

static bool isValidMnemonic( String mnemonic, { bool verifyChecksum = false, }) { return vite.isValidMnemonic(mnemonic, verifyChecksum: verifyChecksum); }

static List mnemonicWordsFromEntropyHex(String entropyHex) { return vite.entropyHexToMnemonic(entropyHex).split(' '); }

static String seedFromMnemonic(String mnemonic) { return vite.mnemonicToSeed(mnemonic).hex; }

static Uint8List decrypt(Uint8List data, String password) { return NanoCrypt.decrypt(data, password); }

static String decryptHex(String value, String password) { return bytesToHex(decrypt(hexToBytes(value), password)); }

static String decryptToText(String value, String password) { return bytesUtf8ToString(decrypt(hexToBytes(value), password)); }

static String? tryDecryptHex(String? value, String password) { if (value == null) return null; return decryptHex(value, password); }

static Uint8List encrypt(Uint8List data, String password) { return NanoCrypt.encrypt(data, password); }

static String encryptHex(String value, String password) { return bytesToHex(encrypt(hexToBytes(value), password)); }

static String? tryEncryptHex(String? value, String password) { if (value == null) return null; return encryptHex(value, password); }

static String encryptText(String value, String password) { return bytesToHex(encrypt(stringToBytesUtf8(value), password)); }

static String? tryEncryptText(String? value, String password) { if (value == null) return null; return encryptText(value, password); }

static Uint8List signData(Uint8List data, Uint8List privKey) { return vite.sign(message: data, privateKey: privKey); }

static vite.KeyPair seedToKeyPair(String seed, int index) { assert(index >= 0); final keyPair = vite.Wallet.deriveKeyPairFromSeed(hexToBytes(seed), index); return keyPair; }

static Uint8List seedToPublicKey(String seed, int index) { final keyPair = seedToKeyPair(seed, index); return keyPair.publicKey; }

static Uint8List seedToPrivateKey(String seed, int index) { final keyPair = seedToKeyPair(seed, index); return keyPair.privateKey; }

static vite.Address seedToAddress(String seed, int index) { final keyPair = vite.Wallet.deriveKeyPairFromSeed(hexToBytes(seed), index); return vite.Address.fromPublicKey(keyPair.publicKey); }

static String formatVotes(String value) { final decimal = Decimal.tryParse(value); if (decimal == null) { return '0'; } final votes = (decimal / Decimal.ten.pow(vite.viteTokenDecimals)) .toDecimal(scaleOnInfinitePrecision: 0); return votes.toStringAsFixed(0); }

static int utpeForAmount(vite.Amount amount, {required List quotaStakeList}) { int left = 0, right = quotaStakeList.length; final sValue = amount.raw + BigInt.one; while (left < right) { final mid = (left + right) ~/ 2; final value = BigInt.parse(quotaStakeAmounts[mid]); if (value < sValue) { left = mid + 1; } else { right = mid; } }

return max(1, left - 1);

}

static Future computeSignData( Uint8List data, Uint8List privateKey, ) { return compute(_computeSignData, [data, privateKey]); }

static Future computeTxHash( vite.RawTransaction transaction) async { final bytes = await compute(_computeTxHash, transaction.toJson()); return vite.Hash(bytes); } }

Uint8List _computeSignData(List params) { return ViteUtil.signData(params.first, params.last); }

Uint8List _computeTxHash(Map<String, dynamic> json) { final transaction = vite.RawTransaction.fromJson(json); return vite.computeTxHash(transaction).bytes; }

theultrastarter commented 1 year ago

this is the code use for generating the address. its in dart

JamesSmartCell commented 1 year ago

No worries. In fact I've been meaning to do a refactor to handle addresses in their own class which includes chainid (ContractAddress) where appropriate eg token contracts but didn't realise I also need to abstract address too. Perhaps we can both work on this.

Addresses aren't done all that well in AW because when we started it was before eip55 checksum addresses became popular so we just used string for them. It should be done via a custom class to at at the very least handle the checksum addresses better.

theultrastarter commented 1 year ago

Ohk. Looking forward to working on this together. I'm currently working it will hit you up with any advancements.

On Thu, Nov 17, 2022, 8:44 AM James Brown @.***> wrote:

No worries. In fact I've been meaning to do a refactor to handle addresses in their own class which includes chainid (ContractAddress) where appropriate eg token contracts but didn't realise I also need to abstract address too. Perhaps we can both work on this.

Addresses aren't done all that well in AW because when we started it was before eip55 checksum addresses became popular so we just used string for them. It should be done via a custom class to at at the very least handle the checksum addresses better.

— Reply to this email directly, view it on GitHub https://github.com/AlphaWallet/alpha-wallet-android/issues/2950#issuecomment-1318284402, or unsubscribe https://github.com/notifications/unsubscribe-auth/AMS7FV4FSXCJ23QA6ZC5K73WIXV7TANCNFSM6AAAAAASCQERGU . You are receiving this because you modified the open/close state.Message ID: @.***>

JamesSmartCell commented 1 year ago

@elishaakyaw looking forward to your updates!