Skip to content

Commit

Permalink
Merge pull request #484 from KeystoneHQ/feat/okx_multicoin
Browse files Browse the repository at this point in the history
Feat/okx multicoin
  • Loading branch information
ZhenQian-keystone authored May 28, 2024
2 parents 96e93f3 + 852e03f commit b7c680e
Show file tree
Hide file tree
Showing 17 changed files with 236 additions and 37 deletions.
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"java.configuration.updateBuildConfiguration": "automatic"
}
6 changes: 5 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ dependencies {
implementation 'androidx.core:core:1.6.0'
compileOnly files('libs/cvos.jar')
implementation 'co.nstant.in:cbor:0.9'
implementation 'com.github.KeystoneHQ:hummingbird:0.6.0'
implementation 'com.github.KeystoneHQ:hummingbird:0.6.2'
implementation 'androidx.appcompat:appcompat:1.3.0-beta01'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.navigation:navigation-fragment:2.2.0-rc04'
Expand Down Expand Up @@ -219,6 +219,10 @@ dependencies {

}

configurations.all {
resolutionStrategy.cacheChangingModulesFor 0, 'seconds'
}

preBuild {
doLast {
def imlFile = file(project.name + ".iml")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ public void setupWalletUI(Wallet wallet) {
R.drawable.ic_coin_btc,
R.drawable.ic_coin_eth,
R.drawable.ic_coin_okb,
R.drawable.ic_coin_dash,
R.drawable.ic_coin_bch,
R.drawable.ic_coin_trx,
R.drawable.ic_coin_ltc,
R.drawable.ic_coin_bnb,
R.drawable.ic_coin_arb,
R.drawable.ic_coin_avax,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public enum WalletConfig {
BITKEEP_ONLY_BTC(Wallet.BITKEEP.getWalletId(), new String[]{Coins.BTC.coinId()}, false, false, true, false),
KEYSTONE(Wallet.KEYSTONE.getWalletId(), new String[]{Coins.BTC.coinId(), Coins.ETH.coinId()}, false, false, true, true),
ETERNL(Wallet.ETERNL.getWalletId(), new String[]{Coins.ADA.coinId()}, false, false, true, false),
OKX(Wallet.OKX.getWalletId(), new String[]{Coins.BTC.coinId(), Coins.ETH.coinId()}, false, false, true, true),
OKX(Wallet.OKX.getWalletId(), new String[]{Coins.BTC.coinId(), Coins.ETH.coinId(),Coins.DASH.coinId(),Coins.BCH.coinId(),Coins.TRON.coinId(),Coins.LTC.coinId()}, false, false, true, true),
DEFAULT("default", new String[]{""}, false, false, true, true),
;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
import com.sparrowwallet.hummingbird.registry.solana.SolNFTItem;
import com.sparrowwallet.hummingbird.registry.solana.SolSignRequest;
import com.sparrowwallet.hummingbird.registry.sui.SuiSignRequest;
import com.sparrowwallet.hummingbird.registry.KeystoneSignRequest;


import org.json.JSONException;
import org.json.JSONObject;
Expand Down Expand Up @@ -92,7 +94,9 @@ public Destination run(ScanResult r) throws BaseException {
return new QRHardwareCallProcessor().run(r.resolve());
} else if (r.getType().equals(ScanResultTypes.UR_CARDANO_SIGN_REQUEST)) {
return new CardanoSignRequestProcessor().run(r.resolve());
} else {
} else if (r.getType().equals(ScanResultTypes.UR_KEYSTONE_SIGN_REQUEST)){
return new KeystoneSignRequestProcessor().run(r.resolve());
}else {
throw UnimplementedException.newInstance();
}
}
Expand All @@ -101,8 +105,94 @@ interface URResolver {
Destination run(Object object) throws BaseException;
}

private static class ETHSignRequestProcessor implements URResolver {
private static class KeystoneSignRequestProcessor implements URResolver {


@Override
public Destination run(Object object) throws BaseException {
KeystoneSignRequest keystoneSignRequest = (KeystoneSignRequest) object;
String origin = keystoneSignRequest.getOrigin();
String hexString = Hex.toHexString(keystoneSignRequest.getSignData());
JSONObject json = tryDecodeAsJson(hexString);

if (json == null) {
json = tryDecodeAsProtobuf(hexString);
}
if (json != null) {
Destination destination = decodeAndProcess(json);
if (destination == null) {
throw UnknownQrCodeException.newInstance();
}
return destination;
} else {
throw UnknownQrCodeException.newInstance();
}
}


private JSONObject tryDecodeAsJson(String hex) {
try {
return new JSONObject(new String(Hex.decode(hex)));
} catch (Exception ignored) {
}
return null;
}

private JSONObject tryDecodeAsProtobuf(String hex) {
JSONObject object;
hex = ZipUtil.unzip(hex);
object = new ProtoParser(Hex.decode(hex)).parseToJson();
return object;
}

private Destination decodeAndProcess(JSONObject object) throws BaseException {
Destination destination = checkWebAuth(object);
if (destination != null) return destination;
if (object.has("TransactionType")) {
Bundle bundle = new Bundle();
bundle.putString(BundleKeys.SIGN_DATA_KEY, object.toString());
return new Destination(R.id.action_to_rippleConfirmTransactionFragment, bundle);
}
if (object.optString("type").equals("TYPE_SIGN_TX")) {
return handleSign(object);
}
throw UnknownQrCodeException.newInstance();
}

private Destination checkWebAuth(JSONObject object) {
try {
JSONObject webAuth = object.optJSONObject("data");
if (webAuth != null && webAuth.optString("type").equals("webAuth")) {
String data = webAuth.getString("data");
Bundle bundle = new Bundle();
bundle.putString(BundleKeys.WEB_AUTH_DATA_KEY, data);
return new Destination(R.id.action_to_webAuthResultFragment, bundle);
}
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}

private Destination handleSign(JSONObject object)
throws BaseException {
String xfp = new GetMasterFingerprintCallable().call();
if (!object.optString("xfp").toUpperCase().equals(xfp.toUpperCase())){
throw XfpNotMatchException.newInstance();
}
try {
Bundle bundle = new Bundle();
bundle.putString(BundleKeys.SIGN_DATA_KEY, object.getJSONObject("signTx").toString());
return new Destination(R.id.action_to_keystoneConfirmTransactionFragment, bundle);
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
}


private static class ETHSignRequestProcessor implements URResolver {
@Override
public Destination run(Object object) throws BaseException {
EthSignRequest ethSignRequest = (EthSignRequest) object;
Expand Down Expand Up @@ -548,7 +638,7 @@ private Destination checkWebAuth(JSONObject object) {
private Destination handleSign(JSONObject object)
throws BaseException {
String xfp = new GetMasterFingerprintCallable().call();
if (!object.optString("xfp").equals(xfp)) {
if (!object.optString("xfp").toUpperCase().equals(xfp.toUpperCase())) {
throw XfpNotMatchException.newInstance();
}
try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ protected void setupView() {

@Override
protected void onSignSuccess() {
String signatureURString = viewModel.getSignatureUR();
String signatureURString = viewModel.getSignatureUR();
Bundle data = new Bundle();
data.putString(BundleKeys.SIGNATURE_UR_KEY, signatureURString);
data.putString(BundleKeys.COIN_CODE_KEY, viewModel.getCoinCode());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ public class OKXWalletViewModel extends AndroidViewModel {
public static final String BTCNestedSegwitPath = "M/49'/0'/0'";
public static final String BTCNativeSegwitPath = "M/84'/0'/0'";


public static final String DashPath = "M/44'/5'/0'";
public static final String BtcCashPath = "M/44'/145'/0'";
public static final String TronPath = "M/44'/195'/0'";
public static final String LitcoinPath = "M/49'/2'/0'";

private final String[] btcPaths = {BTCLegacyPath, BTCNestedSegwitPath, BTCNativeSegwitPath};

private List<String> openedCoins = new ArrayList<>();
Expand All @@ -52,6 +58,10 @@ public void setOpenedCoins(List<String> openedCoins) {
this.openedCoins.add(Coins.ETH.coinId());
this.openedCoins.add(Coins.BTC.coinId());
}
this.openedCoins.add(Coins.DASH.coinId());
this.openedCoins.add(Coins.BCH.coinId());
this.openedCoins.add(Coins.TRON.coinId());
this.openedCoins.add(Coins.LTC.coinId());
}

private CryptoMultiAccounts generateCryptoMultiAccounts() {
Expand All @@ -63,6 +73,26 @@ private CryptoMultiAccounts generateCryptoMultiAccounts() {
if (openedCoins.contains(Coins.BTC.coinId())) {
cryptoHDKeyList.addAll(generateCryptoHDKeysForBitcoin());
}

if (openedCoins.contains(Coins.DASH.coinId())) {
CryptoHDKey dash = generateCryptoHDKeyForOtherCoin(DashPath, 5);
cryptoHDKeyList.add(dash);
}

if (openedCoins.contains(Coins.BCH.coinId())) {
CryptoHDKey bch = generateCryptoHDKeyForOtherCoin(BtcCashPath, 145);
cryptoHDKeyList.add(bch);
}

if (openedCoins.contains(Coins.TRON.coinId())) {
CryptoHDKey tron = generateCryptoHDKeyForOtherCoin(TronPath,195);
cryptoHDKeyList.add(tron);
}

if (openedCoins.contains(Coins.LTC.coinId())) {
CryptoHDKey litcoin = generateCryptoHDKeyForOtherCoin(LitcoinPath,2);
cryptoHDKeyList.add(litcoin);
}
return new CryptoMultiAccounts(masterFingerprint, cryptoHDKeyList, DeviceInfoUtil.getDeviceType(), DeviceInfoUtil.getDeviceId());
}

Expand Down Expand Up @@ -98,4 +128,8 @@ private List<CryptoHDKey> generateCryptoHDKeysForBitcoin() {
private CryptoHDKey generateCryptoHDKeyForBitcoin(String path) {
return URRegistryHelper.generateCryptoHDKey(path, 0);
}

private CryptoHDKey generateCryptoHDKeyForOtherCoin(String path, int type) {
return URRegistryHelper.generateCryptoHDKey(path, type);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Stream;

import com.sparrowwallet.hummingbird.registry.KeystoneSignature;
import java.nio.ByteBuffer;
import java.util.UUID;
public class KeystoneTxViewModel extends BaseTxViewModel<TxEntity> {
private static final String TAG = "KeystoneTxViewModel";
private static final String BTC_SEGWIT_PATH = "M/49'/0'/0'/";
Expand Down Expand Up @@ -118,7 +120,6 @@ public void parseTxData(Bundle bundle) {
try {
String json = bundle.getString(BundleKeys.SIGN_DATA_KEY);
JSONObject object = new JSONObject(json);
Log.i(TAG, "object = " + object.toString(4));
transaction = AbsTx.newInstance(object);
if (transaction == null) {
observableException.postValue(new InvalidTransactionException(MainApplication.getApplication().getString(R.string.incorrect_tx_data), "invalid transaction"));
Expand Down Expand Up @@ -437,9 +438,37 @@ public void handleSignMessage() {

}



private static byte[] hexToBytes(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}

@Override
public String getSignatureUR() {
return observableTransaction.getValue().getSignResult();
KeystoneSignature keystoneSignature;
String signatureStr = observableTransaction.getValue().getSignResult();
String requestIdStr = observableTransaction.getValue().getSignId();
byte[] signature = hexToBytes(signatureStr);
if (signatureStr == null) {
keystoneSignature = new KeystoneSignature(signature);
} else {
UUID uuid = UUID.fromString(requestIdStr);
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
byteBuffer.putLong(uuid.getMostSignificantBits());
byteBuffer.putLong(uuid.getLeastSignificantBits());
byte[] requestId = byteBuffer.array();
keystoneSignature = new KeystoneSignature(signature);
}
String urString = keystoneSignature.toUR().toString();

return urString;
}

void signTransaction(Signer... signer) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -506,11 +506,13 @@ public void handleScanResult(ScanResult result) throws Exception {
handleArweaveSignRequest(result);
} else if (result.getType().equals(ScanResultTypes.UR_EVM_SIGN_REQUEST)) {
handleEvmSignRequest(result);

} else {
throw new UnknowQrCodeException("unknown transaction!");
}
}


private void handleURBytes(ScanResult result) throws JSONException, UnExpectedQRException {
JSONObject object = new JSONObject(new String((byte[]) result.resolve(), StandardCharsets.UTF_8));
JSONObject webAuth = object.optJSONObject("data");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import com.sparrowwallet.hummingbird.registry.solana.SolNFTItem;
import com.sparrowwallet.hummingbird.registry.solana.SolSignRequest;
import com.sparrowwallet.hummingbird.registry.sui.SuiSignRequest;

import com.sparrowwallet.hummingbird.registry.KeystoneSignRequest;
import org.spongycastle.util.encoders.Hex;

import java.util.List;
Expand Down Expand Up @@ -46,7 +46,9 @@ public enum ScanResultTypes {
UR_COSMOS_SIGN_REQUEST,
UR_QR_HARDWARE_CALL,
UR_CARDANO_SIGN_REQUEST,
UR_EVM_SIGN_REQUEST;
UR_EVM_SIGN_REQUEST,

UR_KEYSTONE_SIGN_REQUEST;


public boolean isType(String text) {
Expand Down Expand Up @@ -88,6 +90,8 @@ public boolean isType(UR ur) {
return decodeResult instanceof QRHardwareCall;
case UR_CARDANO_SIGN_REQUEST:
return decodeResult instanceof CardanoSignRequest;
case UR_KEYSTONE_SIGN_REQUEST:
return decodeResult instanceof KeystoneSignRequest;
default:
return false;
}
Expand Down Expand Up @@ -138,6 +142,8 @@ public Object resolveURHex(String hex) {
return QRHardwareCall.fromCbor(dataItem);
case UR_CARDANO_SIGN_REQUEST:
return CardanoSignRequest.fromCbor(dataItem);
case UR_KEYSTONE_SIGN_REQUEST:
return KeystoneSignRequest.fromCbor(dataItem);
default:
return null;
}
Expand Down Expand Up @@ -179,6 +185,8 @@ public static ScanResultTypes fromUR(UR ur) throws UnsupportedURException {
return UR_QR_HARDWARE_CALL;
case "cardano-sign-request":
return UR_CARDANO_SIGN_REQUEST;
case "keystone-sign-request":
return UR_KEYSTONE_SIGN_REQUEST;
default:
throw new UnsupportedURException(MainApplication.getApplication().getString(R.string.invalid_qr_code_hint), "unsupported ur type: " + ur.getType());
}
Expand Down
8 changes: 4 additions & 4 deletions app/src/main/res_remove_wallet_mode/values/string.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<string name="connect_wallets">Connect SoftWare Wallets</string>

<string-array name="watch_wallet_list_remove_wallet_mode">
<item>Keystone Companion App</item>
<!-- <item>Keystone Companion App</item> -->
<item>MetaMask</item>
<item>OKX Wallet</item>
<item>Keplr</item>
Expand All @@ -36,7 +36,7 @@
<item>SushiSwap</item>
</string-array>
<string-array name="watch_wallet_ids" translatable="false">
<item>keystone</item>
<!-- <item>keystone</item> -->
<item>metamask</item>
<item>okx</item>
<item>keplr</item>
Expand All @@ -61,9 +61,9 @@
<item>sushiswap</item>
</string-array>
<string-array name="watch_wallet_summury_remove_wallet_mode">
<item>9 main chains including BTC, ETH, etc</item>
<item>ETH, AVAX, BNB, and other EVM tokens</item>
<!-- <item>9 main chains including BTC, ETH, etc</item> -->
<item>ETH, AVAX, BNB, and other EVM tokens</item>
<item>BTC, ETH, TRX, BCH, LTC, DASH and EVM</item>
<item>Cosmos Eco</item>
<item>ETH, AVAX, BNB, and other EVM tokens</item>
<item>ETH, AVAX, BNB, and other EVM tokens</item>
Expand Down
4 changes: 2 additions & 2 deletions app/version.properties
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,5 @@

#Fri Feb 21 13:33:46 CST 2020
major=3
minor=12
patch=6
minor=13
patch=0
Loading

0 comments on commit b7c680e

Please sign in to comment.