diff --git a/Java/Makefile b/Java/Core.Makefile similarity index 100% rename from Java/Makefile rename to Java/Core.Makefile diff --git a/Java/CoreDemo/build.gradle b/Java/CoreDemo/build.gradle index 2c7961cc9..53e804f59 100644 --- a/Java/CoreDemo/build.gradle +++ b/Java/CoreDemo/build.gradle @@ -38,4 +38,5 @@ dependencies { androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' implementation project(':Core') + implementation project(':Crypto') } diff --git a/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/CoreDemoBitcoinClient.java b/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/CoreDemoBitcoinClient.java new file mode 100644 index 000000000..0c64bad9b --- /dev/null +++ b/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/CoreDemoBitcoinClient.java @@ -0,0 +1,151 @@ +package com.breadwallet.coredemo; + +import android.util.Log; + +import com.breadwallet.crypto.api.Account; +import com.breadwallet.crypto.api.Network; +import com.breadwallet.crypto.api.Transfer; +import com.breadwallet.crypto.api.Wallet; +import com.breadwallet.crypto.api.WalletManager; +import com.breadwallet.crypto.api.WalletManager.Mode; +import com.breadwallet.crypto.api.bitcoin.BitcoinBackendClient; +import com.breadwallet.crypto.api.bitcoin.BitcoinPersistenceClient; +import com.breadwallet.crypto.api.bitcoin.BitcoinWalletManagerListener; +import com.breadwallet.crypto.api.events.transfer.CreatedTransferEvent; +import com.breadwallet.crypto.api.events.transfer.DeletedTransferEvent; +import com.breadwallet.crypto.api.events.transfer.TransferEvent; +import com.breadwallet.crypto.api.events.transfer.TransferEventVisitor; +import com.breadwallet.crypto.api.events.wallet.BalanceUpdatedWalletEvent; +import com.breadwallet.crypto.api.events.wallet.CreatedWalletEvent; +import com.breadwallet.crypto.api.events.wallet.DeletedWalletEvent; +import com.breadwallet.crypto.api.events.wallet.WalletEvent; +import com.breadwallet.crypto.api.events.wallet.WalletEventVisitor; +import com.breadwallet.crypto.api.events.walletmanager.ChangedWalletManagerEvent; +import com.breadwallet.crypto.api.events.walletmanager.SyncEndedWalletManagerEvent; +import com.breadwallet.crypto.api.events.walletmanager.SyncStartedWalletManagerEvent; +import com.breadwallet.crypto.api.events.walletmanager.WalletManagerEvent; +import com.breadwallet.crypto.api.events.walletmanager.WalletManagerEventVisitor; + +import java.util.Map; +import java.util.concurrent.Executors; + +public class CoreDemoBitcoinClient + implements BitcoinWalletManagerListener, BitcoinBackendClient, BitcoinPersistenceClient { + + private static final String TAG = "CoreDemoBitcoinClient"; + + private final WalletManager walletManager; + + public CoreDemoBitcoinClient(Network network, String storagePath, String paperKey) { + this.walletManager = WalletManager.createBitcoinWalletManager( + Account.create(paperKey), + network, + Mode.API_WITH_P2P_SUBMIT, + 1543190400, + storagePath, + this, + this, + this, + Executors.newSingleThreadExecutor()); + } + + public void connect() { + walletManager.connect(); + } + + public void disconnect() { + walletManager.disconnect(); + } + + // BitcoinWalletManagerListener + + @Override + public void handleManagerEvent(WalletManager manager, WalletManagerEvent event) { + // toy example of the visitor pattern; generic can be used to extract information + event.accept(new WalletManagerEventVisitor() { + @Override + public Void visit(ChangedWalletManagerEvent event) { + Log.d(TAG, "handleManagerEvent: " + event.toString()); + return null; + } + + @Override + public Void visit(SyncEndedWalletManagerEvent event) { + Log.d(TAG, "handleManagerEvent: " + event.toString()); + return null; + } + + @Override + public Void visit(SyncStartedWalletManagerEvent event) { + Log.d(TAG, "handleManagerEvent: " + event.toString()); + return null; + } + }); + } + + @Override + public void handleTransferEvent(WalletManager manager, Wallet wallet, Transfer transfer, TransferEvent event) { + // toy example of the visitor pattern; generic can be used to extract information + event.accept(new TransferEventVisitor() { + @Override + public Void visit(CreatedTransferEvent event) { + Log.d(TAG, "handleTransferEvent: " + event.toString()); + return null; + } + + @Override + public Void visit(DeletedTransferEvent event) { + Log.d(TAG, "handleTransferEvent: " + event.toString()); + return null; + } + }); + } + + @Override + public void handleWalletEvent(WalletManager manager, Wallet wallet, WalletEvent event) { + // toy example of the visitor pattern; generic can be used to extract information + event.accept(new WalletEventVisitor() { + @Override + public Void visit(BalanceUpdatedWalletEvent event) { + Log.d(TAG, "handleWalletEvent: " + event.toString()); + return null; + } + + @Override + public Void visit(CreatedWalletEvent event) { + Log.d(TAG, "handleWalletEvent: " + event.toString()); + return null; + } + + @Override + public Void visit(DeletedWalletEvent event) { + Log.d(TAG, "handleWalletEvent: " + event.toString()); + return null; + } + }); + } + + // BitcoinBackendClient + + @Override + public boolean isReachable() { + return true; + } + + // BitcoinPersistenceClient + + @Override + public void savePeers(WalletManager walletManager, Map data) { + + } + + @Override + public void saveBlocks(WalletManager walletManager, Map data) { + + } + + @Override + public void changeTransaction(WalletManager walletManager, ChangeType type, String hash, String data) { + + } +} diff --git a/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/CoreDemoEthereumClient.java b/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/CoreDemoEthereumClient.java index ba53833e7..b0cb01464 100644 --- a/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/CoreDemoEthereumClient.java +++ b/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/CoreDemoEthereumClient.java @@ -13,6 +13,9 @@ import java.util.Map; public class CoreDemoEthereumClient implements BREthereumEWM.Client { + + static { System.loadLibrary("core"); } + interface WalletListener { void announceWalletEvent (BREthereumEWM ewm, BREthereumWallet wallet, diff --git a/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/WalletNavigationActivity.java b/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/WalletNavigationActivity.java index 6ac10c2b3..79fc227b0 100644 --- a/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/WalletNavigationActivity.java +++ b/Java/CoreDemo/src/main/java/com/breadwallet/coredemo/WalletNavigationActivity.java @@ -4,13 +4,17 @@ import android.os.Bundle; import com.breadwallet.core.ethereum.BREthereumNetwork; +import com.breadwallet.crypto.api.CryptoApi; +import com.breadwallet.crypto.api.Bitcoin; +import com.breadwallet.crypto.core.CoreCryptoApi; import java.io.File; public class WalletNavigationActivity extends AppCompatActivity { - static { System.loadLibrary("core"); } - static CoreDemoEthereumClient client = null; + static { CryptoApi.init(new CoreCryptoApi()); } + + CoreDemoEthereumClient ethClient = null; private void deleteRecursively (File file) { if (file.isDirectory()) @@ -24,23 +28,47 @@ private void deleteRecursively (File file) { protected void onCreate(Bundle savedInstanceState) { System.out.println ("Starting"); - File storageFile = new File (getFilesDir(), "core"); - if (storageFile.exists()) deleteRecursively(storageFile); - storageFile.mkdirs(); - - client = new CoreDemoEthereumClient(BREthereumNetwork.mainnet, - storageFile.getAbsolutePath(), - "boring head harsh green empty clip fatal typical found crane dinner timber"); - - client.ewm.announceToken("0x722dd3f80bac40c951b51bdd28dd19d435762180", - "BRD", - "BRD Token", - "", - 18, - "92000", - "1000000000", - 0); - client.ewm.connect(); + // Bitcoin + + { + File storageFile = new File(getFilesDir(), "core"); + if (storageFile.exists()) deleteRecursively(storageFile); + storageFile.mkdirs(); + + CoreDemoBitcoinClient btcClient = new CoreDemoBitcoinClient( + Bitcoin.TESTNET, + storageFile.getAbsolutePath(), + "0xa9de3dbd7d561e67527bc1ecb025c59d53b9f7ef"); + + btcClient.connect(); + btcClient.disconnect(); + + System.gc(); + } + + // Ethereum + + { + File storageFile = new File(getFilesDir(), "core"); + if (storageFile.exists()) deleteRecursively(storageFile); + storageFile.mkdirs(); + + ethClient = new CoreDemoEthereumClient(BREthereumNetwork.mainnet, + storageFile.getAbsolutePath(), + "boring head harsh green empty clip fatal typical found crane dinner timber"); + + ethClient.ewm.announceToken("0x722dd3f80bac40c951b51bdd28dd19d435762180", + "BRD", + "BRD Token", + "", + 18, + "92000", + "1000000000", + 0); + ethClient.ewm.connect(); + + System.gc(); + } super.onCreate(savedInstanceState); setContentView(R.layout.activity_wallet_navigation); diff --git a/Java/Crypto.Makefile b/Java/Crypto.Makefile new file mode 100644 index 000000000..88607b8d9 --- /dev/null +++ b/Java/Crypto.Makefile @@ -0,0 +1,140 @@ +DIR=$(shell pwd) + +# +# Java +# + +JAVA_DIR=${JAVA_HOME} +JAVA_LIB= + +# JNI + +JNI_LIB=libCrypto.jnilib +JNI_SDIR=Crypto/src/main/cpp/jni +JNI_SRCS= +JNI_OBJS=$(JNI_SRCS:.c=.o) +JNI_HDRS=$(JNI_SRCS:.c=.h) + +# Crypto Api + +JAVA_API_SDIR=Crypto/src/main/java/com/breadwallet/crypto/api +JAVA_API_SRCS=\ + $(JAVA_API_SDIR)/bitcoin/BitcoinBackendClient.java \ + $(JAVA_API_SDIR)/bitcoin/BitcoinChainParams.java \ + $(JAVA_API_SDIR)/bitcoin/BitcoinMasterPubKey.java \ + $(JAVA_API_SDIR)/bitcoin/BitcoinPersistenceClient.java \ + $(JAVA_API_SDIR)/bitcoin/BitcoinWalletManagerListener.java \ + $(JAVA_API_SDIR)/events/transfer/TransferEvent.java \ + $(JAVA_API_SDIR)/events/wallet/WalletEvent.java \ + $(JAVA_API_SDIR)/events/wallet/BalanceUpdatedWalletEvent.java \ + $(JAVA_API_SDIR)/events/wallet/CreatedWalletEvent.java \ + $(JAVA_API_SDIR)/events/wallet/DeletedWalletEvent.java \ + $(JAVA_API_SDIR)/events/walletmanager/WalletManagerEvent.java \ + $(JAVA_API_SDIR)/events/walletmanager/ChangedWalletManagerEvent.java \ + $(JAVA_API_SDIR)/events/walletmanager/SyncStartedWalletManagerEvent.java \ + $(JAVA_API_SDIR)/events/walletmanager/SyncEndedWalletManagerEvent.java \ + $(JAVA_API_SDIR)/factories/AccountFactory.java \ + $(JAVA_API_SDIR)/factories/NetworkFactory.java \ + $(JAVA_API_SDIR)/factories/WalletManagerFactory.java \ + $(JAVA_API_SDIR)/walletmanager/WalletManagerBackendClient.java \ + $(JAVA_API_SDIR)/walletmanager/WalletManagerListener.java \ + $(JAVA_API_SDIR)/walletmanager/WalletManagerPersistenceClient.java \ + $(JAVA_API_SDIR)/Account.java \ + $(JAVA_API_SDIR)/Address.java \ + $(JAVA_API_SDIR)/Amount.java \ + $(JAVA_API_SDIR)/Bitcoin.java \ + $(JAVA_API_SDIR)/CryptoApi.java \ + $(JAVA_API_SDIR)/Currency.java \ + $(JAVA_API_SDIR)/Network.java \ + $(JAVA_API_SDIR)/Transfer.java \ + $(JAVA_API_SDIR)/Unit.java \ + $(JAVA_API_SDIR)/Wallet.java \ + $(JAVA_API_SDIR)/WalletManager.java +JAVA_API_OBJS=$(JAVA_API_SRCS:.java=.class) + +# Crypto Core + +JAVA_CORE_SDIR=Crypto/src/main/java/com/breadwallet/crypto/core +JAVA_CORE_SRCS=\ + $(JAVA_CORE_SDIR)/bitcoin/jni/CoreBitcoinChainParams.java \ + $(JAVA_CORE_SDIR)/bitcoin/jni/CoreBitcoinMasterPubKey.java \ + $(JAVA_CORE_SDIR)/bitcoin/jni/CoreBitcoinWallet.java \ + $(JAVA_CORE_SDIR)/bitcoin/jni/CoreBitcoinWalletManager.java \ + $(JAVA_CORE_SDIR)/bitcoin/jni/CoreBitcoinWalletManagerClient.java \ + $(JAVA_CORE_SDIR)/bitcoin/BitcoinChainParams.java \ + $(JAVA_CORE_SDIR)/bitcoin/BitcoinChainParamsAdapter.java \ + $(JAVA_CORE_SDIR)/bitcoin/BitcoinMasterPubKey.java \ + $(JAVA_CORE_SDIR)/bitcoin/BitcoinMasterPubKeyAdapter.java \ + $(JAVA_CORE_SDIR)/bitcoin/BitcoinWallet.java \ + $(JAVA_CORE_SDIR)/bitcoin/BitcoinWalletManager.java \ + $(JAVA_CORE_SDIR)/common/jni/JniReference.java \ + $(JAVA_CORE_SDIR)/jni/Bip39.java \ + $(JAVA_CORE_SDIR)/Account.java \ + $(JAVA_CORE_SDIR)/CoreCryptoApi.java +JAVA_CORE_OBJS=$(JAVA_CORE_SRCS:.java=.class) + +# +# Core +# + +# Bitcoin + +C_SDIR=Crypto/src/main/cpp/core + +CORE_SRCS= +CORE_OBJS=$(CORE_SRCS:.c=.o) + +# Ethereum + +ETH_SRCS= +ETH_OBJS=$(ETH_SRCS:.c=.o) + +# +# Targets +# + +compile: $(JNI_LIB) java_comp + +$(JNI_LIB): $(JNI_OBJS) $(CORE_OBJS) + cc -dynamiclib -o $(JNI_LIB) $(JNI_OBJS) $(CORE_OBJS) + +java_comp: FORCE + @mkdir -p build + @echo "Crypto Java" + @javac -d build $(JAVA_API_SRCS) $(JAVA_CORE_SRCS) + +jni_hdr_crypto: FORCE + @echo Crypto JNI Headers + @(cd build/com/breadwallet/crypto/core/bitcoin/jni; \ + for class in *.class; do \ + javah -jni -d $(DIR)/$(JNI_SDIR) -classpath $(DIR)/build com.breadwallet.crypto.core.bitcoin.jni.$${class%%.class}; \ + done) + @(cd build/com/breadwallet/crypto/core/common/jni; \ + for class in *.class; do \ + javah -jni -d $(DIR)/$(JNI_SDIR) -classpath $(DIR)/build com.breadwallet.crypto.core.common.jni.$${class%%.class}; \ + done) + @(cd build/com/breadwallet/crypto/core/jni; \ + for class in *.class; do \ + javah -jni -d $(DIR)/$(JNI_SDIR) -classpath $(DIR)/build com.breadwallet.crypto.core.jni.$${class%%.class}; \ + done) + @(cd $(JNI_SDIR); \ + rm -f .h \ + com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWallet.h \ + com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManagerClient.h) + + +jni_hdr: java_comp jni_hdr_crypto + +clean: + rm -rf build $(JNI_OBJS) $(CORE_OBJS) $(JAVA_API_OBJS) $(JAVA_CORE_OBJS) $(JNI_LIB) + +FORCE: + +# test: $(JNI_LIB) java_comp +# java -Xss1m -Dwallet.test -classpath build -Djava.library.path=. \ +# com.breadwallet.core.test.BRWalletManager $(ARGS) # -D. + +# debug: $(JNI_LIB) java_comp +# java -Xss1m -Xdebug -Xrunjdwp:transport=dt_socket,address=8008,server=y,suspend=n \ +# -Dwallet.test -classpath build -Djava.library.path=. \ +# com.breadwallet.core.test.BRWalletManager $(ARGS) # -D. diff --git a/Java/Crypto/CMakeLists.txt b/Java/Crypto/CMakeLists.txt new file mode 100644 index 000000000..9a7f65647 --- /dev/null +++ b/Java/Crypto/CMakeLists.txt @@ -0,0 +1,274 @@ +# For more information about using CMake with Android Studio, read the +# documentation: https://d.android.com/studio/projects/add-native-code.html + +# Sets the minimum version of CMake required to build the native library. + +cmake_minimum_required(VERSION 3.4.1) + +# now build app's shared lib +set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -DANDROID_STL=gnustl_static -DANDROID_TOOLCHAIN=clang") + +# -Wimplicit-function-declaration +# -Wno-missing-prototypes -Werror=return-type -Wdocumentation -Wunreachable-code-aggressive -Wno-missing-braces +# -Wparentheses -Wswitch -Wno-unused-function -Wunused-label -Wno-unused-parameter -Wunused-variable -Wunused-value -Wempty-body +# -Wconditional-uninitialized -Wno-unknown-pragmas -pedantic -Wshadow -Wfour-char-constants -Wno-conversion -Wconstant-conversion +# -Wint-conversion -Wbool-conversion -Wenum-conversion -Wassign-enum -Wno-shorten-64-to-32 -Wpointer-sign -Wnewline-eof +# -Wdeprecated-declarations -Wno-sign-conversion + + +add_library( # Sets the name of the library. + crypto + + # Sets the library as a shared library. + SHARED) + +# Core +target_sources (crypto + PUBLIC + + # Core files + src/main/cpp/core/BRAddress.c + src/main/cpp/core/BRAddress.h + src/main/cpp/core/BRArray.h + src/main/cpp/core/BRBase58.c + src/main/cpp/core/BRBase58.h + src/main/cpp/core/BRBech32.c + src/main/cpp/core/BRBech32.h + src/main/cpp/core/BRBIP32Sequence.c + src/main/cpp/core/BRBIP32Sequence.h + src/main/cpp/core/BRBIP38Key.c + src/main/cpp/core/BRBIP38Key.h + src/main/cpp/core/BRBIP39Mnemonic.c + src/main/cpp/core/BRBIP39Mnemonic.h + src/main/cpp/core/BRBIP39WordsEn.h + src/main/cpp/core/BRBloomFilter.c + src/main/cpp/core/BRBloomFilter.h + src/main/cpp/core/BRCrypto.c + src/main/cpp/core/BRCrypto.h + src/main/cpp/core/BRInt.h + src/main/cpp/core/BRKey.c + src/main/cpp/core/BRKey.h + src/main/cpp/core/BRKeyECIES.c + src/main/cpp/core/BRKeyECIES.h + src/main/cpp/core/BRMerkleBlock.c + src/main/cpp/core/BRMerkleBlock.h + src/main/cpp/core/BRPaymentProtocol.c + src/main/cpp/core/BRPaymentProtocol.h + src/main/cpp/core/BRPeer.c + src/main/cpp/core/BRPeer.h + src/main/cpp/core/BRPeerManager.c + src/main/cpp/core/BRPeerManager.h + src/main/cpp/core/BRSet.c + src/main/cpp/core/BRSet.h + src/main/cpp/core/BRTransaction.c + src/main/cpp/core/BRTransaction.h + src/main/cpp/core/BRWallet.c + src/main/cpp/core/BRWallet.h + src/main/cpp/core/BRWalletManager.c + src/main/cpp/core/BRWalletManager.h + + src/main/cpp/core/support/BRFileService.c + src/main/cpp/core/support/BRFileService.h + src/main/cpp/core/support/BRAssert.c + src/main/cpp/core/support/BRAssert.h + + # BCash files + src/main/cpp/core/bcash/BRBCashAddr.c + src/main/cpp/core/bcash/BRBCashAddr.h + src/main/cpp/core/bcash/BRBCashParams.h + + # Bech32 files + src/main/cpp/core/BRBech32.c + src/main/cpp/core/BRBech32.h) + +# Core Ethereum +target_sources (crypto + PUBLIC + + # + src/main/cpp/core/ethereum/BREthereum.h + + # Util + src/main/cpp/core/ethereum/util/BRKeccak.c + src/main/cpp/core/ethereum/util/BRKeccak.h + src/main/cpp/core/ethereum/util/BRUtil.h + src/main/cpp/core/ethereum/util/BRUtilHex.c + src/main/cpp/core/ethereum/util/BRUtilHex.h + src/main/cpp/core/ethereum/util/BRUtilMath.c + src/main/cpp/core/ethereum/util/BRUtilMath.h + src/main/cpp/core/ethereum/util/BRUtilMathParse.c +# src/main/cpp/core/ethereum/util/testUtil.c + + # RLP + src/main/cpp/core/ethereum/rlp/BRRlp.h + src/main/cpp/core/ethereum/rlp/BRRlpCoder.c + src/main/cpp/core/ethereum/rlp/BRRlpCoder.h +# src/main/cpp/core/ethereum/rlp/testRlp.c + + # Event + src/main/cpp/core/ethereum/event/BREvent.c + src/main/cpp/core/ethereum/event/BREvent.h + src/main/cpp/core/ethereum/event/BREventAlarm.c + src/main/cpp/core/ethereum/event/BREventAlarm.h + src/main/cpp/core/ethereum/event/BREventQueue.c + src/main/cpp/core/ethereum/event/BREventQueue.h +# src/main/cpp/core/ethereum/event/testEvent.c + + # Base + src/main/cpp/core/ethereum/base/BREthereumAddress.c + src/main/cpp/core/ethereum/base/BREthereumAddress.h + src/main/cpp/core/ethereum/base/BREthereumBase.h + src/main/cpp/core/ethereum/base/BREthereumEther.c + src/main/cpp/core/ethereum/base/BREthereumEther.h + src/main/cpp/core/ethereum/base/BREthereumGas.c + src/main/cpp/core/ethereum/base/BREthereumGas.h + src/main/cpp/core/ethereum/base/BREthereumHash.c + src/main/cpp/core/ethereum/base/BREthereumHash.h + src/main/cpp/core/ethereum/base/BREthereumData.c + src/main/cpp/core/ethereum/base/BREthereumData.h + src/main/cpp/core/ethereum/base/BREthereumLogic.h + src/main/cpp/core/ethereum/base/BREthereumSignature.c + src/main/cpp/core/ethereum/base/BREthereumSignature.h +# src/main/cpp/core/ethereum/base/testBase.c + + # Block Chain + src/main/cpp/core/ethereum/blockchain/BREthereumAccountState.c + src/main/cpp/core/ethereum/blockchain/BREthereumAccountState.h + src/main/cpp/core/ethereum/blockchain/BREthereumBlock.c + src/main/cpp/core/ethereum/blockchain/BREthereumBlock.h + src/main/cpp/core/ethereum/blockchain/BREthereumBlockChain.h + src/main/cpp/core/ethereum/blockchain/BREthereumBloomFilter.c + src/main/cpp/core/ethereum/blockchain/BREthereumBloomFilter.h + src/main/cpp/core/ethereum/blockchain/BREthereumLog.c + src/main/cpp/core/ethereum/blockchain/BREthereumLog.h + src/main/cpp/core/ethereum/blockchain/BREthereumNetwork.c + src/main/cpp/core/ethereum/blockchain/BREthereumNetwork.h + src/main/cpp/core/ethereum/blockchain/BREthereumTransaction.c + src/main/cpp/core/ethereum/blockchain/BREthereumTransaction.h + src/main/cpp/core/ethereum/blockchain/BREthereumTransactionReceipt.c + src/main/cpp/core/ethereum/blockchain/BREthereumTransactionReceipt.h + src/main/cpp/core/ethereum/blockchain/BREthereumTransactionStatus.c + src/main/cpp/core/ethereum/blockchain/BREthereumTransactionStatus.h + src/main/cpp/core/ethereum/blockchain/BREthereumProofOfWork.c +# src/main/cpp/core/ethereum/blockchain/testBc.c + + # Contract + src/main/cpp/core/ethereum/contract/BREthereumContract.c + src/main/cpp/core/ethereum/contract/BREthereumContract.h + src/main/cpp/core/ethereum/contract/BREthereumToken.c + src/main/cpp/core/ethereum/contract/BREthereumToken.h +# src/main/cpp/core/ethereum/contract/testContract.c + + # MPT + src/main/cpp/core/ethereum/mpt/BREthereumMPT.c + src/main/cpp/core/ethereum/mpt/BREthereumMPT.h + + # LES Msg + src/main/cpp/core/ethereum/les/msg/BREthereumMessageDIS.c + src/main/cpp/core/ethereum/les/msg/BREthereumMessageDIS.h + src/main/cpp/core/ethereum/les/msg/BREthereumMessageETH.h + src/main/cpp/core/ethereum/les/msg/BREthereumMessageLES.c + src/main/cpp/core/ethereum/les/msg/BREthereumMessageLES.h + src/main/cpp/core/ethereum/les/msg/BREthereumMessageP2P.c + src/main/cpp/core/ethereum/les/msg/BREthereumMessageP2P.h + src/main/cpp/core/ethereum/les/msg/BREthereumMessagePIP.c + src/main/cpp/core/ethereum/les/msg/BREthereumMessagePIP.h + + # LES + src/main/cpp/core/ethereum/les/BREthereumLES.c + src/main/cpp/core/ethereum/les/BREthereumLES.h + src/main/cpp/core/ethereum/les/BREthereumLESBase.h + src/main/cpp/core/ethereum/les/BREthereumLESFrameCoder.c + src/main/cpp/core/ethereum/les/BREthereumLESFrameCoder.h + src/main/cpp/core/ethereum/les/BREthereumLESRandom.c + src/main/cpp/core/ethereum/les/BREthereumLESRandom.h + src/main/cpp/core/ethereum/les/BREthereumMessage.c + src/main/cpp/core/ethereum/les/BREthereumMessage.h + src/main/cpp/core/ethereum/les/BREthereumNode.c + src/main/cpp/core/ethereum/les/BREthereumNode.h + src/main/cpp/core/ethereum/les/BREthereumNodeEndpoint.c + src/main/cpp/core/ethereum/les/BREthereumNodeEndpoint.h + src/main/cpp/core/ethereum/les/BREthereumProvision.c + src/main/cpp/core/ethereum/les/BREthereumProvision.h + src/main/cpp/core/ethereum/les/msg/BREthereumMessageP2P.h + src/main/cpp/core/ethereum/les/msg/BREthereumMessageP2P.c + src/main/cpp/core/ethereum/les/msg/BREthereumMessageDIS.h + src/main/cpp/core/ethereum/les/msg/BREthereumMessageDIS.c + src/main/cpp/core/ethereum/les/msg/BREthereumMessageETH.h + src/main/cpp/core/ethereum/les/msg/BREthereumMessageLES.h + src/main/cpp/core/ethereum/les/msg/BREthereumMessageLES.c + src/main/cpp/core/ethereum/les/msg/BREthereumMessagePIP.h + src/main/cpp/core/ethereum/les/msg/BREthereumMessagePIP.c +# src/main/cpp/core/ethereum/les/test-les.c +# src/main/cpp/core/ethereum/les/test-les.h + + # BCS + src/main/cpp/core/ethereum/bcs/BREthereumBCS.c + src/main/cpp/core/ethereum/bcs/BREthereumBCS.h + src/main/cpp/core/ethereum/bcs/BREthereumBCSEvent.c + src/main/cpp/core/ethereum/bcs/BREthereumBCSPrivate.h + src/main/cpp/core/ethereum/bcs/BREthereumBCSSync.c + src/main/cpp/core/ethereum/bcs/BREthereumBlockChainSlice.h + + #EWM + src/main/cpp/core/ethereum/ewm/BREthereumBase.h + src/main/cpp/core/ethereum/ewm/BREthereumAccount.c + src/main/cpp/core/ethereum/ewm/BREthereumAccount.h + src/main/cpp/core/ethereum/ewm/BREthereumAmount.c + src/main/cpp/core/ethereum/ewm/BREthereumAmount.h + src/main/cpp/core/ethereum/ewm/BREthereumTransfer.c + src/main/cpp/core/ethereum/ewm/BREthereumTransfer.h + src/main/cpp/core/ethereum/ewm/BREthereumWallet.c + src/main/cpp/core/ethereum/ewm/BREthereumWallet.h + src/main/cpp/core/ethereum/ewm/BREthereumClient.h + src/main/cpp/core/ethereum/ewm/BREthereumEWM.c + src/main/cpp/core/ethereum/ewm/BREthereumEWM.h + src/main/cpp/core/ethereum/ewm/BREthereumEWMClient.c + src/main/cpp/core/ethereum/ewm/BREthereumEWMEvent.c + src/main/cpp/core/ethereum/ewm/BREthereumEWMPrivate.h +# src/main/cpp/core/ethereum/ewm/testEwm.c + ) + +# Crypto JNI +target_sources (crypto + PUBLIC + src/main/cpp/jni/BRCryptoJni.h + src/main/cpp/jni/BRCryptoJni.c + src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams.h + src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams.c + src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey.h + src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey.c + src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager.h + src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager.c + src/main/cpp/jni/com_breadwallet_crypto_core_common_jni_JniReference.h + src/main/cpp/jni/com_breadwallet_crypto_core_common_jni_JniReference.c + src/main/cpp/jni/com_breadwallet_crypto_core_jni_Bip39.h + src/main/cpp/jni/com_breadwallet_crypto_core_jni_Bip39.c) + +include_directories(src/main/cpp/core/) +include_directories(src/main/cpp/core/ethereum/) +include_directories(src/main/cpp/core/secp256k1/) + +# Searches for a specified prebuilt library and stores the path as a +# variable. Because CMake includes system libraries in the search path by +# default, you only need to specify the name of the public NDK library +# you want to add. CMake verifies that the library exists before +# completing its build. + +find_library( # Sets the name of the path variable. + log-lib + + # Specifies the name of the NDK library that + # you want CMake to locate. + log ) + +# Specifies libraries CMake should link to your target library. You +# can link multiple libraries, such as libraries you define in this +# build script, prebuilt third-party libraries, or system libraries. + +target_link_libraries( # Specifies the target library. + crypto + + # Links the target library to the log library + # included in the NDK. + ${log-lib} ) \ No newline at end of file diff --git a/Java/Crypto/build.gradle b/Java/Crypto/build.gradle index e185bedf5..03dca2a9d 100644 --- a/Java/Crypto/build.gradle +++ b/Java/Crypto/build.gradle @@ -7,6 +7,13 @@ android { targetCompatibility JavaVersion.VERSION_1_8 } + // Link Gradle to the CMake script + externalNativeBuild { + cmake { + path "CMakeLists.txt" //path can only be set outside (in android block) + } + } + defaultConfig { minSdkVersion 23 targetSdkVersion 28 @@ -24,11 +31,44 @@ android { missingDimensionStrategy 'network', 'onMainnet' } + flavorDimensions "network" + productFlavors { + + onMainnet { + dimension "network" + } + + onTestnet { + dimension "network" + externalNativeBuild { + cmake { + cFlags "-DBITCOIN_TESTNET" + } + } + } + } + + // http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.BaseExtension.html#com.android.build.gradle.BaseExtension:buildTypes(org.gradle.api.Action) + // "Encapsulates all build type configurations for this project" buildTypes { + + // Default: required release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + + // Default: created on demand with 'debuggable true' + debug { + debuggable true + jniDebuggable true + minifyEnabled false + externalNativeBuild { + cmake { + cFlags "-DDEBUG", "-DBITCOIN_DEBUG" + } + } + } } } @@ -38,5 +78,4 @@ dependencies { testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' - implementation project(':Core') } diff --git a/Java/Crypto/src/androidTest/java/com/breadwallet/crypto/ethereum/TransferAIT.java b/Java/Crypto/src/androidTest/java/com/breadwallet/crypto/api/ethereum/TransferAIT.java similarity index 70% rename from Java/Crypto/src/androidTest/java/com/breadwallet/crypto/ethereum/TransferAIT.java rename to Java/Crypto/src/androidTest/java/com/breadwallet/crypto/api/ethereum/TransferAIT.java index 845cd1d7b..4e0bf06ff 100644 --- a/Java/Crypto/src/androidTest/java/com/breadwallet/crypto/ethereum/TransferAIT.java +++ b/Java/Crypto/src/androidTest/java/com/breadwallet/crypto/api/ethereum/TransferAIT.java @@ -1,11 +1,9 @@ -package com.breadwallet.crypto.ethereum; +package com.breadwallet.crypto.api.ethereum; import com.breadwallet.crypto.BaseAIT; import org.junit.Test; -import static org.junit.Assert.*; - public class TransferAIT extends BaseAIT { @Test public void ethTransferOne() { diff --git a/Java/Crypto/src/main/cpp/core b/Java/Crypto/src/main/cpp/core new file mode 120000 index 000000000..3ed539a75 --- /dev/null +++ b/Java/Crypto/src/main/cpp/core @@ -0,0 +1 @@ +../../../../../. \ No newline at end of file diff --git a/Java/Crypto/src/main/cpp/jni/BRCryptoJni.c b/Java/Crypto/src/main/cpp/jni/BRCryptoJni.c new file mode 100644 index 000000000..70ea9bd39 --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/BRCryptoJni.c @@ -0,0 +1,61 @@ +// Copyright (c) 2019 breadwallet LLC. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include +#include +#include "BRCryptoJni.h" + +// TODO: Re-write using personal coding style + +static JavaVM *jvm = NULL; + +extern +JNIEnv *getEnv() { + JNIEnv *env; + + if (NULL == jvm) return NULL; + + int status = (*jvm)->GetEnv(jvm, (void **) &env, JNI_VERSION_1_6); + + if (status != JNI_OK) + status = (*jvm)->AttachCurrentThread(jvm, (JNIEnv **) &env, NULL); + + return status == JNI_OK ? env : NULL; +} + +extern +void releaseEnv () { + if (NULL != jvm) + (*jvm)->DetachCurrentThread (jvm); +} + +JNIEXPORT jint JNICALL +JNI_OnLoad (JavaVM *theJvm, void *reserved) { + JNIEnv *env = 0; + + if ((*theJvm)->GetEnv(theJvm, (void **)&env, JNI_VERSION_1_6)) { + return JNI_ERR; + } + + jvm = theJvm; + + return JNI_VERSION_1_6; +} diff --git a/Java/Crypto/src/main/cpp/jni/BRCryptoJni.h b/Java/Crypto/src/main/cpp/jni/BRCryptoJni.h new file mode 100644 index 000000000..d4d5cba6e --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/BRCryptoJni.h @@ -0,0 +1,50 @@ +// Copyright (c) 2019 breadwallet LLC. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef CRYPTOJNI_BRCRYPTOJVM_H +#define CRYPTOJNI_BRCRYPTOJVM_H + +#include +#include + +// TODO: Re-write using personal coding style + +/** + * + * @return + */ +extern JNIEnv * +getEnv(); + +extern void +releaseEnv (); + +/** + * + * @param env + * @param thisObject + * @return + */ +extern void * +getJNIReference ( + JNIEnv *env, + jobject thisObject); + +#endif //CRYPTOJNI_BRCRYPTOJVM_H diff --git a/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams.c b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams.c new file mode 100644 index 000000000..2e6da6596 --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams.c @@ -0,0 +1,35 @@ +// Copyright (c) 2019 breadwallet LLC. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include + +#include "BRChainParams.h" + +#include "com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams.h" + +JNIEXPORT jlong JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams_createTestnetChainParams ( + JNIEnv * env, + jclass thisClass) +{ + BRChainParams *result = (BRChainParams *) calloc (1, sizeof (BRChainParams)); + memcpy (result, &BRTestNetParams, sizeof (BRChainParams)); + + return (jlong) result; +} \ No newline at end of file diff --git a/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams.h b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams.h new file mode 100644 index 000000000..d835c707e --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams */ + +#ifndef _Included_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams +#define _Included_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams + * Method: createTestnetChainParams + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinChainParams_createTestnetChainParams + (JNIEnv *, jclass); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey.c b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey.c new file mode 100644 index 000000000..e3dcc8b41 --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey.c @@ -0,0 +1,43 @@ +// Copyright (c) 2019 breadwallet LLC. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include + +#include "BRBIP32Sequence.h" + +#include "BRCryptoJni.h" +#include "com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey.h" + +JNIEXPORT jlong JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey_createBitcoinMasterPubKey ( + JNIEnv * env, + jclass thisClass, + jbyteArray seedByteArray) +{ + assert (!(*env)->IsSameObject (env, seedByteArray, NULL)); + + jsize seedLength = (*env)->GetArrayLength (env, seedByteArray); + jbyte *seedBytes = (*env)->GetByteArrayElements (env, seedByteArray, 0); + + BRMasterPubKey *resKey = (BRMasterPubKey *) calloc (1, sizeof (BRMasterPubKey)); + *resKey = BRBIP32MasterPubKey(seedBytes, seedLength); + + return (jlong) resKey; +} \ No newline at end of file diff --git a/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey.h b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey.h new file mode 100644 index 000000000..28f483c09 --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey */ + +#ifndef _Included_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey +#define _Included_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey + * Method: createBitcoinMasterPubKey + * Signature: ([B)J + */ +JNIEXPORT jlong JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinMasterPubKey_createBitcoinMasterPubKey + (JNIEnv *, jclass, jbyteArray); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager.c b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager.c new file mode 100644 index 000000000..0465269a8 --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager.c @@ -0,0 +1,199 @@ +// Copyright (c) 2019 breadwallet LLC. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include + +#include "BRWalletManager.h" + +#include "BRCryptoJni.h" +#include "com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager.h" + +static jclass trampolineClass = NULL; +static jmethodID trampolineHandleTransactionAdded = NULL; +static jmethodID trampolineHandleTransactionUpdated = NULL; +static jmethodID trampolineHandleTransactionDeleted = NULL; + +static jmethodID trampolineHandleWalletCreated = NULL; +static jmethodID trampolineHandleWalletBalanceUpdated = NULL; +static jmethodID trampolineHandleWalletDeleted = NULL; + +static jmethodID trampolineHandleWalletManagerConnected = NULL; +static jmethodID trampolineHandleWalletManagerDisconnected = NULL; +static jmethodID trampolineHandleWalletManagerSyncStarted = NULL; +static jmethodID trampolineHandleWalletManagerSyncStopped = NULL; + +static void +transactionEventCallback (BRWalletManager manager, + BRWallet *wallet, + BRTransaction *transaction, + BRTransactionEvent event); + +static void +walletEventCallback (BRWalletManager manager, + BRWallet *wallet, + BRWalletEvent event); + +static void +walletManagerEventCallback (BRWalletManager manager, + BRWalletManagerEvent event); + +static jmethodID +trampolineOrFatal (JNIEnv *env, const char *name, const char *signature); + +JNIEXPORT void JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager_initializeNative ( + JNIEnv * env, + jclass thisClass) +{ + trampolineClass = (*env)->NewGlobalRef(env, thisClass); + + trampolineHandleTransactionAdded = trampolineOrFatal (env, "handleTransactionAdded", "(JJJ)V"); + trampolineHandleTransactionUpdated = trampolineOrFatal (env, "handleTransactionUpdated", "(JJJ)V"); + trampolineHandleTransactionDeleted = trampolineOrFatal (env, "handleTransactionDeleted", "(JJJ)V"); + + trampolineHandleWalletCreated = trampolineOrFatal (env, "handleWalletCreated", "(JJ)V"); + trampolineHandleWalletBalanceUpdated = trampolineOrFatal (env, "handleWalletBalanceUpdated", "(JJJ)V"); + trampolineHandleWalletDeleted = trampolineOrFatal (env, "handleWalletDeleted", "(JJ)V"); + + trampolineHandleWalletManagerConnected = trampolineOrFatal (env, "handleWalletManagerConnected", "(J)V"); + trampolineHandleWalletManagerDisconnected = trampolineOrFatal (env, "handleWalletManagerDisconnected", "(J)V"); + trampolineHandleWalletManagerSyncStarted = trampolineOrFatal (env, "handleWalletManagerSyncStarted", "(J)V"); + trampolineHandleWalletManagerSyncStopped = trampolineOrFatal (env, "handleWalletManagerSyncStopped", "(JI)V"); +} + +JNIEXPORT jlong JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager_createBitcoinWalletManager ( + JNIEnv * env, + jclass thisClass, + jobject masterPublicKeyObject, + jobject chainParamsObject, + jint earliestKeyTime, + jstring storagePathString) +{ + assert (!(*env)->IsSameObject (env, masterPublicKeyObject, NULL)); + assert (!(*env)->IsSameObject (env, chainParamsObject, NULL)); + assert (!(*env)->IsSameObject (env, storagePathString, NULL)); + assert (earliestKeyTime >= 0); + + BRMasterPubKey *masterPubKey = (BRMasterPubKey *) getJNIReference(env, masterPublicKeyObject); + BRChainParams *chainParams = (BRChainParams *) getJNIReference(env, chainParamsObject); + const char *storagePath = (*env)->GetStringUTFChars (env, storagePathString, 0); + + BRWalletManagerClient client = { transactionEventCallback, walletEventCallback, walletManagerEventCallback }; + BRWalletManager *walletManager = BRWalletManagerNew(client, *masterPubKey, chainParams, earliestKeyTime, storagePath); + + return (jlong) walletManager; +} + +JNIEXPORT void JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager_connect ( + JNIEnv * env, + jobject thisObject) +{ + BRWalletManager *walletManager = (BRWalletManager *) getJNIReference(env, thisObject); + BRWalletManagerConnect(walletManager); +} + +JNIEXPORT void JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager_disconnect ( + JNIEnv * env, + jobject thisObject) +{ + BRWalletManager *walletManager = (BRWalletManager *) getJNIReference(env, thisObject); + BRWalletManagerDisconnect(walletManager); +} + +JNIEXPORT void JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager_disposeNative ( + JNIEnv * env, + jobject thisObject) +{ + BRWalletManager *walletManager = (BRWalletManager *) getJNIReference(env, thisObject); + if (NULL != walletManager) BRWalletManagerFree(walletManager); +} + + +static jmethodID +trampolineOrFatal (JNIEnv *env, const char *name, const char *signature) { + jmethodID method = (*env)->GetStaticMethodID (env, trampolineClass, name, signature); + assert (NULL != method); + return method; +} + + +static void +transactionEventCallback (BRWalletManager wmid, + BRWallet *wid, + BRTransaction *tid, + BRTransactionEvent e) { + JNIEnv *env = getEnv(); + if (NULL == env) return; + + switch (e.type) { + case BITCOIN_TRANSACTION_ADDED: + (*env)->CallStaticVoidMethod(env, trampolineClass, trampolineHandleTransactionAdded, (jlong) wmid, (jlong) wid, (jlong) tid); + break; + case BITCOIN_TRANSACTION_UPDATED: + (*env)->CallStaticVoidMethod(env, trampolineClass, trampolineHandleTransactionUpdated, (jlong) wmid, (jlong) wid, (jlong) tid); + break; + case BITCOIN_TRANSACTION_DELETED: + (*env)->CallStaticVoidMethod(env, trampolineClass, trampolineHandleTransactionDeleted, (jlong) wmid, (jlong) wid, (jlong) tid); + break; + } + +} + +static void +walletEventCallback (BRWalletManager wmid, + BRWallet *wid, + BRWalletEvent e) { + JNIEnv *env = getEnv(); + if (NULL == env) return; + + switch (e.type) { + case BITCOIN_WALLET_CREATED: + (*env)->CallStaticVoidMethod(env, trampolineClass, trampolineHandleWalletCreated, (jlong) wmid, (jlong) wid); + break; + case BITCOIN_WALLET_BALANCE_UPDATED: + (*env)->CallStaticVoidMethod(env, trampolineClass, trampolineHandleWalletBalanceUpdated, (jlong) wmid, (jlong) wid, (jlong) e.u.balance.satoshi); + break; + case BITCOIN_WALLET_DELETED: + (*env)->CallStaticVoidMethod(env, trampolineClass, trampolineHandleWalletDeleted, (jlong) wmid, (jlong) wid); + break; + } +} + +static void +walletManagerEventCallback (BRWalletManager wmid, + BRWalletManagerEvent e) { + JNIEnv *env = getEnv(); + if (NULL == env) return; + + switch (e.type) { + case BITCOIN_WALLET_MANAGER_CONNECTED: + (*env)->CallStaticVoidMethod(env, trampolineClass, trampolineHandleWalletManagerConnected, (jlong) wmid); + break; + case BITCOIN_WALLET_MANAGER_DISCONNECTED: + (*env)->CallStaticVoidMethod(env, trampolineClass, trampolineHandleWalletManagerDisconnected, (jlong) wmid); + break; + case BITCOIN_WALLET_MANAGER_SYNC_STARTED: + (*env)->CallStaticVoidMethod(env, trampolineClass, trampolineHandleWalletManagerSyncStarted, (jlong) wmid); + break; + case BITCOIN_WALLET_MANAGER_SYNC_STOPPED: + (*env)->CallStaticVoidMethod(env, trampolineClass, trampolineHandleWalletManagerSyncStopped, (jlong) wmid, (jint) e.u.syncStopped.error); + break; + } +} diff --git a/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager.h b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager.h new file mode 100644 index 000000000..9263f6c5d --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager.h @@ -0,0 +1,53 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager */ + +#ifndef _Included_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager +#define _Included_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager + * Method: createBitcoinWalletManager + * Signature: (Lcom/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinMasterPubKey;Lcom/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinChainParams;ILjava/lang/String;)J + */ +JNIEXPORT jlong JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager_createBitcoinWalletManager + (JNIEnv *, jclass, jobject, jobject, jint, jstring); + +/* + * Class: com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager + * Method: initializeNative + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager_initializeNative + (JNIEnv *, jclass); + +/* + * Class: com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager + * Method: connect + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager_connect + (JNIEnv *, jobject); + +/* + * Class: com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager + * Method: disconnect + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager_disconnect + (JNIEnv *, jobject); + +/* + * Class: com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager + * Method: disposeNative + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_breadwallet_crypto_core_bitcoin_jni_CoreBitcoinWalletManager_disposeNative + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_common_jni_JniReference.c b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_common_jni_JniReference.c new file mode 100644 index 000000000..f15c7941e --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_common_jni_JniReference.c @@ -0,0 +1,65 @@ +// Copyright (c) 2019 breadwallet LLC. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include + +#include "BRCryptoJni.h" +#include "com_breadwallet_crypto_core_common_jni_JniReference.h" + +#define JNI_REFERENCE_ADDRESS_FIELD_NAME "jniReferenceAddress" +#define JNI_REFERENCE_ADDRESS_FIELD_TYPE "J" // long + +static jfieldID getJNIReferenceField ( + JNIEnv *env, + jobject thisObject) +{ + jclass thisClass = (*env)->GetObjectClass (env, thisObject); + jfieldID thisFieldId = (*env)->GetFieldID(env, thisClass, + JNI_REFERENCE_ADDRESS_FIELD_NAME, + JNI_REFERENCE_ADDRESS_FIELD_TYPE); + (*env)->DeleteLocalRef (env, thisClass); + return thisFieldId; +} + +static jlong getJNIReferenceAddress ( + JNIEnv *env, + jobject thisObject) +{ + jfieldID coreBRKeyAddressField = getJNIReferenceField(env, thisObject); + assert (NULL != coreBRKeyAddressField); + + return (*env)->GetLongField (env, thisObject, coreBRKeyAddressField); +} + +extern void *getJNIReference ( + JNIEnv *env, + jobject thisObject) +{ + return (void *) getJNIReferenceAddress(env, thisObject); +} + +JNIEXPORT void JNICALL Java_com_breadwallet_crypto_core_common_jni_JniReference_disposeNative ( + JNIEnv * env, + jobject thisObject) +{ + void *reference = getJNIReference(env, thisObject); + if (NULL != reference) free (reference); +} \ No newline at end of file diff --git a/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_common_jni_JniReference.h b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_common_jni_JniReference.h new file mode 100644 index 000000000..61e3458ba --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_common_jni_JniReference.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_breadwallet_crypto_core_common_jni_JniReference */ + +#ifndef _Included_com_breadwallet_crypto_core_common_jni_JniReference +#define _Included_com_breadwallet_crypto_core_common_jni_JniReference +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_breadwallet_crypto_core_common_jni_JniReference + * Method: disposeNative + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_com_breadwallet_crypto_core_common_jni_JniReference_disposeNative + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_jni_Bip39.c b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_jni_Bip39.c new file mode 100644 index 000000000..229ce02be --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_jni_Bip39.c @@ -0,0 +1,45 @@ +// Copyright (c) 2019 breadwallet LLC. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include + +#include "BRInt.h" +#include "BRBIP39Mnemonic.h" + +#include "com_breadwallet_crypto_core_jni_Bip39.h" + +JNIEXPORT jbyteArray JNICALL Java_com_breadwallet_crypto_core_jni_Bip39_deriveKey ( + JNIEnv * env, + jclass thisClass, + jstring seedString) +{ + assert (!(*env)->IsSameObject (env, thisClass, NULL)); + + UInt512 seed = UINT512_ZERO; + const char *status = (*env)->GetStringUTFChars (env, seedString, 0); + + BRBIP39DeriveKey(seed.u8, status, NULL); + + jbyteArray seedData = (*env)->NewByteArray (env, sizeof(seed)); + (*env)->SetByteArrayRegion (env, seedData, 0, (jsize) sizeof(seed), (const jbyte *) seed.u8); + + return seedData; +} \ No newline at end of file diff --git a/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_jni_Bip39.h b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_jni_Bip39.h new file mode 100644 index 000000000..38239926e --- /dev/null +++ b/Java/Crypto/src/main/cpp/jni/com_breadwallet_crypto_core_jni_Bip39.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class com_breadwallet_crypto_core_jni_Bip39 */ + +#ifndef _Included_com_breadwallet_crypto_core_jni_Bip39 +#define _Included_com_breadwallet_crypto_core_jni_Bip39 +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: com_breadwallet_crypto_core_jni_Bip39 + * Method: deriveKey + * Signature: (Ljava/lang/String;)[B + */ +JNIEXPORT jbyteArray JNICALL Java_com_breadwallet_crypto_core_jni_Bip39_deriveKey + (JNIEnv *, jclass, jstring); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/Account.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/Account.java deleted file mode 100644 index 6eef2f8bf..000000000 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/Account.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.breadwallet.crypto; - -public class Account { -} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/Address.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/Address.java deleted file mode 100644 index 22f627cf6..000000000 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/Address.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.breadwallet.crypto; - -public class Address { -} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/Network.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/Network.java deleted file mode 100644 index d0d1bc65b..000000000 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/Network.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.breadwallet.crypto; -import com.breadwallet.crypto.ethereum.Ethereum; - -public class Network { - enum Type { Bitcoin, Bitcash, Ethereum } - - public static final class Bitcoin { - final String name; - final int forkId; - // chainParams - - public Bitcoin(String name, int forkId) { - this.name = name; - this.forkId = forkId; - } - } - - public static final class Bitcash { - // as above - - } - - public static final class Ethereum { - final String name; - final int chainId; - // BREthereumNetwork - - public Ethereum(String name, int chainId) { - this.name = name; - this.chainId = chainId; - } - } - - public final Currency currency; - - private final Type type; - private final Bitcoin bitcoin; - private final Bitcash bitcash; - private final Ethereum ethereum; - - public Network(Type type, Bitcoin bitcoin, Bitcash bitcash, Ethereum ethereum, Currency currency) { - this.type = type; - this.bitcoin = bitcoin; - this.bitcash = bitcash; - this.ethereum = ethereum; - this.currency = currency; - } - - public Network (Bitcoin bitcoin) { - this (Type.Bitcoin, bitcoin, null, null, null); - } - - public Network (Bitcash bitcash) { - this (Type.Bitcash, null, bitcash, null, null); - } - - public Network (Ethereum ethereum) { - this (Type.Ethereum, null, null, ethereum, - com.breadwallet.crypto.ethereum.Ethereum.currency); - } -} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/Transfer.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/Transfer.java deleted file mode 100644 index f35d4d5d1..000000000 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/Transfer.java +++ /dev/null @@ -1,50 +0,0 @@ -package com.breadwallet.crypto; - -public abstract class Transfer { - public Wallet wallet; - - public Address source; - - public Address target; - - public Amount amount; - - public Amount fee; - - /* - /// The owning wallet - var wallet: Wallet { get } - - /// The source pays the fee and sends the amount. - var source: Address? { get } - - /// The target receives the amount - var target: Address? { get } - - /// The amount to transfer - var amount: Amount { get } - - /// The fee paid - before the transfer is confirmed, this is the estimated fee. - var fee: Amount { get } - - /// The basis for the fee. - var feeBasis: TransferFeeBasis { get } - - /// An optional confirmation. - var confirmation: TransferConfirmation? { get } - - /// An optional hash - var hash: TransferHash? { get } - - /// The current state - var state: TransferState { get } -*/ - - protected Transfer(Wallet wallet, Address source, Address target, Amount amount, Amount fee) { - this.wallet = wallet; - this.source = source; - this.target = target; - this.amount = amount; - this.fee = fee; - } -} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/Wallet.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/Wallet.java deleted file mode 100644 index 2f247081a..000000000 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/Wallet.java +++ /dev/null @@ -1,53 +0,0 @@ -package com.breadwallet.crypto; - -public abstract class Wallet { - public final WalletManager manager; - - public final String name; - - public final Currency currency; - - public abstract Amount getBalance (); - - public abstract Transfer[] getTransfers(); - - - /* - /// The owning manager - var manager: WalletManager { get } - - /// The name - var name: String { get } - - /// The current balance for currency - var balance: Amount { get } - - /// The transfers of currency yielding `balance` - var transfers: [Transfer] { get } - - /// Use a hash to lookup a transfer - func lookup (transfer: TransferHash) -> Transfer? - - /// The current state. - var state: WalletState { get } - - /// The default TransferFeeBasis for created transfers. - var defaultFeeBasis: TransferFeeBasis { get set } - - /// The default TransferFactory for creating transfers. - var transferFactory: TransferFactory { get set } - - // func sign (transfer: Transfer) - // submit - // ... cancel, replace - if appropriate - - /// An address suitable for a transfer target (receiving). - var target: Address { get } -*/ - - public Wallet (WalletManager manager, Currency currency, String name) { - this.manager = manager; - this.currency = currency; - this.name = name; - } -} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/WalletManager.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/WalletManager.java deleted file mode 100644 index 029fe5335..000000000 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/WalletManager.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.breadwallet.crypto; - -public abstract class WalletManager { - public interface Listener { - - } - - public interface PersistenceClient { - - } - - public interface BackendClient { - - } - - public final Account account; - - public final Network network; - - public final Listener listener; - -/* - /// The listener receives Wallet, Transfer and perhaps other asynchronous events. - var listener: WalletManagerListener { get } - - /// The account - var account: Account { get } - - /// The network - var network: Network { get } - - /// The primaryWallet - var primaryWallet: Wallet { get } - - /// The managed wallets - often will just be [primaryWallet] - var wallets: [Wallet] { get } - - // The mode determines how the manager manages the account and wallets on network - var mode: WalletManagerMode { get } - - // The file-system path to use for persistent storage. - var path: String { get } // persistent storage - - var state: WalletManagerState { get } - - #if false - /// The default WalletFactory for creating wallets. - var walletFactory: WalletFactory { get set } - #endif - - /// Connect to network and begin managing wallets for account - func connect () - - /// Disconnect from the network. - func disconnect () - - /// isConnected - /// sync(...) - /// isSyncing - - /// sign(transfer) - /// submit(transfer) -*/ - - protected WalletManager (Listener listener, Account account, Network network) { - this.listener = listener; - this.account = account; - this.network = network; - } -} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Account.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Account.java new file mode 100644 index 000000000..201ce0649 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Account.java @@ -0,0 +1,19 @@ +package com.breadwallet.crypto.api; + +import com.breadwallet.crypto.api.bitcoin.BitcoinMasterPubKey; +import com.breadwallet.crypto.api.factories.AccountFactory; + +public abstract class Account { + + private static AccountFactory FACTORY = CryptoApi.provider().accountFactory(); + + public static Account create(String phrase) { + return FACTORY.create(phrase); + } + + public static Account create(byte[] seed) { + return FACTORY.create(seed); + } + + public abstract BitcoinMasterPubKey masterPublicKey(); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Address.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Address.java new file mode 100644 index 000000000..e3231e008 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Address.java @@ -0,0 +1,4 @@ +package com.breadwallet.crypto.api; + +public interface Address { +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/Amount.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Amount.java similarity index 69% rename from Java/Crypto/src/main/java/com/breadwallet/crypto/Amount.java rename to Java/Crypto/src/main/java/com/breadwallet/crypto/api/Amount.java index 2b948a372..ef6f7fafe 100644 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/Amount.java +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Amount.java @@ -1,8 +1,9 @@ -package com.breadwallet.crypto; +package com.breadwallet.crypto.api; import java.math.BigInteger; public class Amount { + public final BigInteger value; // UInt256 *core public final Unit unit; public final boolean isNegative; @@ -16,4 +17,9 @@ private Amount (BigInteger value, Unit unit) { public Amount (long value, Unit unit) { this (BigInteger.valueOf(value), unit); } + + @Override + public String toString() { + return String.format("Amount(value = %s, unit = %s, negative = %b)", value, unit, isNegative); + } } diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Bitcoin.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Bitcoin.java new file mode 100644 index 000000000..7178d021e --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Bitcoin.java @@ -0,0 +1,13 @@ +package com.breadwallet.crypto.api; + +public final class Bitcoin { + + public static final Currency CURRENCY = new Currency ("BTC", "\u20BF", "Bitcoin", 8, "SAT", "sat"); + + public static final Unit SATOSHI = CURRENCY.baseUnit; + public static final Unit BITCOIN = CURRENCY.defaultUnit; + + public static final Network TESTNET = CryptoApi.provider().networkFactory().testnet(); + + public static final Network MAINNET = CryptoApi.provider().networkFactory().mainnet(); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/CryptoApi.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/CryptoApi.java new file mode 100644 index 000000000..46e5dca9d --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/CryptoApi.java @@ -0,0 +1,28 @@ +package com.breadwallet.crypto.api; + +import com.breadwallet.crypto.api.factories.AccountFactory; +import com.breadwallet.crypto.api.factories.NetworkFactory; +import com.breadwallet.crypto.api.factories.WalletManagerFactory; + +public class CryptoApi { + + public interface Provider { + + AccountFactory accountFactory(); + + WalletManagerFactory walletManagerFactory(); + + NetworkFactory networkFactory(); + } + + private static Provider provider; + + public static synchronized void init(Provider provider) { + if (null != CryptoApi.provider) throw new IllegalStateException("Provider already set"); + CryptoApi.provider = provider; + } + + /* package */ static Provider provider() { + return provider; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/Currency.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Currency.java similarity index 69% rename from Java/Crypto/src/main/java/com/breadwallet/crypto/Currency.java rename to Java/Crypto/src/main/java/com/breadwallet/crypto/api/Currency.java index 2311f4701..45af7386c 100644 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/Currency.java +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Currency.java @@ -1,6 +1,7 @@ -package com.breadwallet.crypto; +package com.breadwallet.crypto.api; public class Currency { + public final String code; public final String symbol; public final String name; @@ -17,4 +18,10 @@ public Currency(String code, String symbol, String name, int decimals, String ba this.baseUnit = new Unit (this, baseUnitName, baseUnitSymbol); this.defaultUnit = new Unit (code, symbol, (long) Math.pow (10, decimals), this.baseUnit); } + + @Override + public String toString() { + return String.format("Currency(code = %s, symbol = %s, name = %s, decimals = %d, base = %s, default = %s)", + code, symbol, name, decimals, baseUnit, defaultUnit); + } } diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Network.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Network.java new file mode 100644 index 000000000..87e8ddbc1 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Network.java @@ -0,0 +1,92 @@ +package com.breadwallet.crypto.api; + +import com.breadwallet.crypto.api.bitcoin.BitcoinChainParams; + +// TODO: Revisit this class and consider moving to interfaces along with the Visitor pattern +public class Network { + + enum Type { BITCOIN, BITCASH, ETHEREUM} + + public static final class Bitcoin { + final String name; + final int forkId; + final BitcoinChainParams chainParams; + + public Bitcoin(String name, int forkId, BitcoinChainParams chainParams) { + this.name = name; + this.forkId = forkId; + this.chainParams = chainParams; + } + } + + public static final class Bitcash { + final String name; + final int forkId; + final BitcoinChainParams chainParams; + + public Bitcash(String name, int forkId, BitcoinChainParams chainParams) { + this.name = name; + this.forkId = forkId; + this.chainParams = chainParams; + } + } + + public static final class Ethereum { + final String name; + final int chainId; + + public Ethereum(String name, int chainId) { + this.name = name; + this.chainId = chainId; + } + } + + private final Type type; + private final Bitcoin bitcoin; + private final Bitcash bitcash; + private final Ethereum ethereum; + + private Network(Type type, Bitcoin bitcoin, Bitcash bitcash, Ethereum ethereum) { + this.type = type; + this.bitcoin = bitcoin; + this.bitcash = bitcash; + this.ethereum = ethereum; + } + + public Network (Bitcoin bitcoin) { + this (Type.BITCOIN, bitcoin, null, null); + } + + public Network (Bitcash bitcash) { + this (Type.BITCASH, null, bitcash, null); + } + + public Network (Ethereum ethereum) { + this (Type.ETHEREUM, null, null, ethereum); + } + + public String name() { + switch (type) { + case BITCOIN: return bitcoin.name; + case BITCASH: return bitcash.name; + case ETHEREUM: return ethereum.name; + default: throw new IllegalStateException(); + } + } + + public int forkId() { + switch (type) { + case BITCOIN: return bitcoin.forkId; + case BITCASH: return bitcash.forkId; + default: throw new IllegalStateException(); + } + } + + public BitcoinChainParams chainParams() { + switch (type) { + case BITCOIN: return bitcoin.chainParams; + case BITCASH: return bitcash.chainParams; + default: throw new IllegalStateException(); + } + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Transfer.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Transfer.java new file mode 100644 index 000000000..ca484b4e2 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Transfer.java @@ -0,0 +1,14 @@ +package com.breadwallet.crypto.api; + +public interface Transfer { + + Wallet wallet(); + + Address source(); + + Address target(); + + Amount amount(); + + Amount fee(); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/Unit.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Unit.java similarity index 75% rename from Java/Crypto/src/main/java/com/breadwallet/crypto/Unit.java rename to Java/Crypto/src/main/java/com/breadwallet/crypto/api/Unit.java index f5383b167..5b9e48a4a 100644 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/Unit.java +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Unit.java @@ -1,6 +1,7 @@ -package com.breadwallet.crypto; +package com.breadwallet.crypto.api; public class Unit { + public final Currency currency; public final String name; public final String symbol; @@ -29,4 +30,9 @@ public Unit(String name, String symbol, long scale, Unit base) { this.base = base; } + @Override + public String toString() { + return String.format("Unit(currency = %s, name = %s, symbol = %s, scale = %d, base = %s)", + currency, name, symbol, scale, base); + } } diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Wallet.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Wallet.java new file mode 100644 index 000000000..246065f4f --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/Wallet.java @@ -0,0 +1,14 @@ +package com.breadwallet.crypto.api; + +public interface Wallet { + + WalletManager manager(); + + String name(); + + Currency currency(); + + Amount balance(); + + Transfer[] transfers(); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/WalletManager.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/WalletManager.java new file mode 100644 index 000000000..9e322b06a --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/WalletManager.java @@ -0,0 +1,41 @@ +package com.breadwallet.crypto.api; + +import com.breadwallet.crypto.api.bitcoin.BitcoinBackendClient; +import com.breadwallet.crypto.api.bitcoin.BitcoinPersistenceClient; +import com.breadwallet.crypto.api.bitcoin.BitcoinWalletManagerListener; +import com.breadwallet.crypto.api.factories.WalletManagerFactory; + +import java.util.concurrent.Executor; + +public abstract class WalletManager { + + private static final WalletManagerFactory FACTORY = CryptoApi.provider().walletManagerFactory(); + + public static WalletManager createBitcoinWalletManager(Account account, + Network network, + Mode mode, + int earliestKeyTime, + String storagePath, + BitcoinPersistenceClient persistenceClient, + BitcoinBackendClient backendClient, + BitcoinWalletManagerListener listener, + Executor listenerExecutor) { + return FACTORY.createBitcoinWalletManager(account, + network, + mode, + earliestKeyTime, + storagePath, + persistenceClient, + backendClient, + listener, + listenerExecutor); + } + + public enum Mode { API_ONLY, API_WITH_P2P_SUBMIT, P2P_WITH_API_SYNC, P2P_ONLY, } + + public enum State { CREATED, DISCONNECTED, CONNECTED, SYNCING, DELETED } + + public abstract void connect(); + + public abstract void disconnect(); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinBackendClient.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinBackendClient.java new file mode 100644 index 000000000..60eaeb754 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinBackendClient.java @@ -0,0 +1,6 @@ +package com.breadwallet.crypto.api.bitcoin; + +import com.breadwallet.crypto.api.walletmanager.WalletManagerBackendClient; + +public interface BitcoinBackendClient extends WalletManagerBackendClient { +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinChainParams.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinChainParams.java new file mode 100644 index 000000000..0f9b7133a --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinChainParams.java @@ -0,0 +1,4 @@ +package com.breadwallet.crypto.api.bitcoin; + +public interface BitcoinChainParams { +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinMasterPubKey.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinMasterPubKey.java new file mode 100644 index 000000000..d617026aa --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinMasterPubKey.java @@ -0,0 +1,4 @@ +package com.breadwallet.crypto.api.bitcoin; + +public interface BitcoinMasterPubKey { +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinPersistenceClient.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinPersistenceClient.java new file mode 100644 index 000000000..0d55ced6c --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinPersistenceClient.java @@ -0,0 +1,6 @@ +package com.breadwallet.crypto.api.bitcoin; + +import com.breadwallet.crypto.api.walletmanager.WalletManagerPersistenceClient; + +public interface BitcoinPersistenceClient extends WalletManagerPersistenceClient { +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinWalletManagerListener.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinWalletManagerListener.java new file mode 100644 index 000000000..36dc5d57f --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/bitcoin/BitcoinWalletManagerListener.java @@ -0,0 +1,6 @@ +package com.breadwallet.crypto.api.bitcoin; + +import com.breadwallet.crypto.api.walletmanager.WalletManagerListener; + +public interface BitcoinWalletManagerListener extends WalletManagerListener { +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/CreatedTransferEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/CreatedTransferEvent.java new file mode 100644 index 000000000..8f179ac5b --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/CreatedTransferEvent.java @@ -0,0 +1,14 @@ +package com.breadwallet.crypto.api.events.transfer; + +public class CreatedTransferEvent implements TransferEvent { + + @Override + public T accept(TransferEventVisitor visitor) { + return visitor.visit(this); + } + + @Override + public String toString() { + return "CreatedTransferEvent"; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/DeletedTransferEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/DeletedTransferEvent.java new file mode 100644 index 000000000..a0d76fb9b --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/DeletedTransferEvent.java @@ -0,0 +1,14 @@ +package com.breadwallet.crypto.api.events.transfer; + +public class DeletedTransferEvent implements TransferEvent { + + @Override + public T accept(TransferEventVisitor visitor) { + return visitor.visit(this); + } + + @Override + public String toString() { + return "DeletedTransferEvent"; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/TransferEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/TransferEvent.java new file mode 100644 index 000000000..4e3e30061 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/TransferEvent.java @@ -0,0 +1,7 @@ +package com.breadwallet.crypto.api.events.transfer; + +// TODO: Add changed event +public interface TransferEvent { + + T accept(TransferEventVisitor visitor); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/TransferEventVisitor.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/TransferEventVisitor.java new file mode 100644 index 000000000..51f85a8ab --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/transfer/TransferEventVisitor.java @@ -0,0 +1,8 @@ +package com.breadwallet.crypto.api.events.transfer; + +public interface TransferEventVisitor { + + T visit(CreatedTransferEvent event); + + T visit(DeletedTransferEvent event); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/BalanceUpdatedWalletEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/BalanceUpdatedWalletEvent.java new file mode 100644 index 000000000..7a7da3950 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/BalanceUpdatedWalletEvent.java @@ -0,0 +1,26 @@ +package com.breadwallet.crypto.api.events.wallet; + +import com.breadwallet.crypto.api.Amount; + +public class BalanceUpdatedWalletEvent implements WalletEvent { + + private final Amount amount; + + public BalanceUpdatedWalletEvent(Amount amount) { + this.amount = amount; + } + + public Amount amount() { + return amount; + } + + @Override + public T accept(WalletEventVisitor visitor) { + return visitor.visit(this); + } + + @Override + public String toString() { + return String.format("BalanceUpdatedWalletEvent(amount = %s)", amount); + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/CreatedWalletEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/CreatedWalletEvent.java new file mode 100644 index 000000000..a6c1fd8ef --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/CreatedWalletEvent.java @@ -0,0 +1,14 @@ +package com.breadwallet.crypto.api.events.wallet; + +public class CreatedWalletEvent implements WalletEvent { + + @Override + public T accept(WalletEventVisitor visitor) { + return visitor.visit(this); + } + + @Override + public String toString() { + return "CreatedWalletEvent"; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/DeletedWalletEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/DeletedWalletEvent.java new file mode 100644 index 000000000..2a67dd823 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/DeletedWalletEvent.java @@ -0,0 +1,14 @@ +package com.breadwallet.crypto.api.events.wallet; + +public class DeletedWalletEvent implements WalletEvent { + + @Override + public T accept(WalletEventVisitor visitor) { + return visitor.visit(this); + } + + @Override + public String toString() { + return "DeletedWalletEvent"; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/WalletEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/WalletEvent.java new file mode 100644 index 000000000..5ad6de0f1 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/WalletEvent.java @@ -0,0 +1,7 @@ +package com.breadwallet.crypto.api.events.wallet; + +// TODO: Add transferAdded, transferChanged, transferDeleted & feeBasisUpdated events +public interface WalletEvent { + + T accept(WalletEventVisitor visitor); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/WalletEventVisitor.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/WalletEventVisitor.java new file mode 100644 index 000000000..6527dfafa --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/wallet/WalletEventVisitor.java @@ -0,0 +1,10 @@ +package com.breadwallet.crypto.api.events.wallet; + +public interface WalletEventVisitor { + + T visit(BalanceUpdatedWalletEvent event); + + T visit(CreatedWalletEvent event); + + T visit(DeletedWalletEvent event); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/ChangedWalletManagerEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/ChangedWalletManagerEvent.java new file mode 100644 index 000000000..d4dfebcc6 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/ChangedWalletManagerEvent.java @@ -0,0 +1,32 @@ +package com.breadwallet.crypto.api.events.walletmanager; + +import com.breadwallet.crypto.api.WalletManager.State; + +public class ChangedWalletManagerEvent implements WalletManagerEvent { + + private final State oldState; + private final State newState; + + public ChangedWalletManagerEvent(State oldState, State newState) { + this.oldState = oldState; + this.newState = newState; + } + + public State oldState() { + return oldState; + } + + public State newState() { + return newState; + } + + @Override + public T accept(WalletManagerEventVisitor visitor) { + return visitor.visit(this); + } + + @Override + public String toString() { + return String.format("ChangedWalletManagerEvent(old: %s, new: %s)", oldState, newState); + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/SyncEndedWalletManagerEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/SyncEndedWalletManagerEvent.java new file mode 100644 index 000000000..a3726e3b2 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/SyncEndedWalletManagerEvent.java @@ -0,0 +1,20 @@ +package com.breadwallet.crypto.api.events.walletmanager; + +public class SyncEndedWalletManagerEvent implements WalletManagerEvent { + + private final String error; + + public SyncEndedWalletManagerEvent(String error) { + this.error = error; + } + + @Override + public T accept(WalletManagerEventVisitor visitor) { + return visitor.visit(this); + } + + @Override + public String toString() { + return String.format("SyncEndedWalletManagerEvent(err: %s)", error); + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/SyncStartedWalletManagerEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/SyncStartedWalletManagerEvent.java new file mode 100644 index 000000000..8e8a9acff --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/SyncStartedWalletManagerEvent.java @@ -0,0 +1,14 @@ +package com.breadwallet.crypto.api.events.walletmanager; + +public class SyncStartedWalletManagerEvent implements WalletManagerEvent { + + @Override + public T accept(WalletManagerEventVisitor visitor) { + return visitor.visit(this); + } + + @Override + public String toString() { + return "SyncStartedWalletManagerEvent"; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/WalletManagerEvent.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/WalletManagerEvent.java new file mode 100644 index 000000000..98d571403 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/WalletManagerEvent.java @@ -0,0 +1,7 @@ +package com.breadwallet.crypto.api.events.walletmanager; + +// TODO: Add walletAdded, walletChanged, walletDeleted, syncStarted, syncProgress & syncEnded events +public interface WalletManagerEvent { + + T accept(WalletManagerEventVisitor visitor); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/WalletManagerEventVisitor.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/WalletManagerEventVisitor.java new file mode 100644 index 000000000..acb6666d6 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/events/walletmanager/WalletManagerEventVisitor.java @@ -0,0 +1,10 @@ +package com.breadwallet.crypto.api.events.walletmanager; + +public interface WalletManagerEventVisitor { + + T visit(ChangedWalletManagerEvent event); + + T visit(SyncEndedWalletManagerEvent event); + + T visit(SyncStartedWalletManagerEvent event); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/factories/AccountFactory.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/factories/AccountFactory.java new file mode 100644 index 000000000..7f44c54e0 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/factories/AccountFactory.java @@ -0,0 +1,10 @@ +package com.breadwallet.crypto.api.factories; + +import com.breadwallet.crypto.api.Account; + +public interface AccountFactory { + + Account create(String phrase); + + Account create(byte[] seed); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/factories/NetworkFactory.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/factories/NetworkFactory.java new file mode 100644 index 000000000..7b746c452 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/factories/NetworkFactory.java @@ -0,0 +1,10 @@ +package com.breadwallet.crypto.api.factories; + +import com.breadwallet.crypto.api.Network; + +public interface NetworkFactory { + + Network testnet(); + + Network mainnet(); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/factories/WalletManagerFactory.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/factories/WalletManagerFactory.java new file mode 100644 index 000000000..7f5bf81fd --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/factories/WalletManagerFactory.java @@ -0,0 +1,24 @@ +package com.breadwallet.crypto.api.factories; + +import com.breadwallet.crypto.api.Account; +import com.breadwallet.crypto.api.Network; +import com.breadwallet.crypto.api.WalletManager; +import com.breadwallet.crypto.api.WalletManager.Mode; +import com.breadwallet.crypto.api.bitcoin.BitcoinBackendClient; +import com.breadwallet.crypto.api.bitcoin.BitcoinPersistenceClient; +import com.breadwallet.crypto.api.bitcoin.BitcoinWalletManagerListener; + +import java.util.concurrent.Executor; + +public interface WalletManagerFactory { + + WalletManager createBitcoinWalletManager(Account account, + Network network, + Mode mode, + int earliestKeyTime, + String storagePath, + BitcoinPersistenceClient persistenceClient, + BitcoinBackendClient backendClient, + BitcoinWalletManagerListener listener, + Executor listenerExecutor); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/walletmanager/WalletManagerBackendClient.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/walletmanager/WalletManagerBackendClient.java new file mode 100644 index 000000000..bebd76ded --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/walletmanager/WalletManagerBackendClient.java @@ -0,0 +1,6 @@ +package com.breadwallet.crypto.api.walletmanager; + +public interface WalletManagerBackendClient { + + boolean isReachable(); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/walletmanager/WalletManagerListener.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/walletmanager/WalletManagerListener.java new file mode 100644 index 000000000..e845a83ce --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/walletmanager/WalletManagerListener.java @@ -0,0 +1,17 @@ +package com.breadwallet.crypto.api.walletmanager; + +import com.breadwallet.crypto.api.Transfer; +import com.breadwallet.crypto.api.Wallet; +import com.breadwallet.crypto.api.WalletManager; +import com.breadwallet.crypto.api.events.transfer.TransferEvent; +import com.breadwallet.crypto.api.events.wallet.WalletEvent; +import com.breadwallet.crypto.api.events.walletmanager.WalletManagerEvent; + +public interface WalletManagerListener { + + void handleManagerEvent(WalletManager manager, WalletManagerEvent event); + + void handleTransferEvent(WalletManager manager, Wallet wallet, Transfer transfer, TransferEvent event); + + void handleWalletEvent(WalletManager manager, Wallet wallet, WalletEvent event); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/api/walletmanager/WalletManagerPersistenceClient.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/walletmanager/WalletManagerPersistenceClient.java new file mode 100644 index 000000000..90fc8eb9f --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/api/walletmanager/WalletManagerPersistenceClient.java @@ -0,0 +1,16 @@ +package com.breadwallet.crypto.api.walletmanager; + +import com.breadwallet.crypto.api.WalletManager; + +import java.util.Map; + +public interface WalletManagerPersistenceClient { + + enum ChangeType { ADDED, UPDATED, DELETED } + + void savePeers(WalletManager walletManager, Map data); + + void saveBlocks(WalletManager walletManager, Map data); + + void changeTransaction(WalletManager walletManager, ChangeType type, String hash, String data); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/Account.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/Account.java new file mode 100644 index 000000000..9c81fe9ad --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/Account.java @@ -0,0 +1,22 @@ +package com.breadwallet.crypto.core; + +import com.breadwallet.crypto.api.bitcoin.BitcoinMasterPubKey; +import com.breadwallet.crypto.core.jni.Bip39; + +public final class Account extends com.breadwallet.crypto.api.Account { + + private final BitcoinMasterPubKey masterPublicKey; + + public Account(String phrase) { + this(Bip39.deriveKey(phrase)); + } + + public Account(byte[] seed) { + this.masterPublicKey = new com.breadwallet.crypto.core.bitcoin.BitcoinMasterPubKey(seed); + } + + @Override + public BitcoinMasterPubKey masterPublicKey() { + return masterPublicKey; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/CoreCryptoApi.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/CoreCryptoApi.java new file mode 100644 index 000000000..d6a9e2a8f --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/CoreCryptoApi.java @@ -0,0 +1,85 @@ +package com.breadwallet.crypto.core; + +import com.breadwallet.crypto.api.*; +import com.breadwallet.crypto.api.Account; +import com.breadwallet.crypto.api.WalletManager.Mode; +import com.breadwallet.crypto.api.bitcoin.BitcoinBackendClient; +import com.breadwallet.crypto.api.bitcoin.BitcoinPersistenceClient; +import com.breadwallet.crypto.api.bitcoin.BitcoinWalletManagerListener; +import com.breadwallet.crypto.api.factories.AccountFactory; +import com.breadwallet.crypto.api.factories.NetworkFactory; +import com.breadwallet.crypto.api.factories.WalletManagerFactory; +import com.breadwallet.crypto.core.bitcoin.BitcoinChainParams; +import com.breadwallet.crypto.core.bitcoin.BitcoinWalletManager; + +import java.util.concurrent.Executor; + +public class CoreCryptoApi implements CryptoApi.Provider { + + static { + System.loadLibrary("crypto"); + } + + private final AccountFactory accountFactory = new AccountFactory() { + @Override + public Account create(String phrase) { + return new com.breadwallet.crypto.core.Account(phrase); + } + + @Override + public Account create(byte[] seed) { + return new com.breadwallet.crypto.core.Account(seed); + } + }; + + private final WalletManagerFactory walletManagerFactory = new WalletManagerFactory() { + @Override + public WalletManager createBitcoinWalletManager(Account account, + Network network, + Mode mode, + int earliestKeyTime, + String storagePath, + BitcoinPersistenceClient persistenceClient, + BitcoinBackendClient backendClient, + BitcoinWalletManagerListener listener, + Executor listenerExecutor) { + return new BitcoinWalletManager(account, + network, + mode, + earliestKeyTime, + storagePath, + persistenceClient, + backendClient, + listener, + listenerExecutor); + } + }; + + private final NetworkFactory networkFactory = new NetworkFactory() { + @Override + public Network testnet() { + return new Network(new Network.Bitcoin("BTC Testnet", 0x40, BitcoinChainParams.TESTNET)); + } + + @Override + public Network mainnet() { + // TODO: Implement this + return null; + } + }; + + @Override + public AccountFactory accountFactory() { + return accountFactory; + } + + @Override + public WalletManagerFactory walletManagerFactory() { + return walletManagerFactory; + } + + @Override + public NetworkFactory networkFactory() { + return networkFactory; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinChainParams.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinChainParams.java new file mode 100644 index 000000000..e2e9cd369 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinChainParams.java @@ -0,0 +1,19 @@ +package com.breadwallet.crypto.core.bitcoin; + +import com.breadwallet.crypto.core.bitcoin.jni.CoreBitcoinChainParams; + +public final class BitcoinChainParams implements com.breadwallet.crypto.api.bitcoin.BitcoinChainParams { + + // TODO: Add MAINNET + public static BitcoinChainParams TESTNET = new BitcoinChainParams(CoreBitcoinChainParams.TESTNET); + + private final CoreBitcoinChainParams chainParams; + + private BitcoinChainParams(CoreBitcoinChainParams chainParams) { + this.chainParams = chainParams; + } + + /* package */ CoreBitcoinChainParams chainParams() { + return chainParams; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinChainParamsAdapter.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinChainParamsAdapter.java new file mode 100644 index 000000000..7cd0f4b73 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinChainParamsAdapter.java @@ -0,0 +1,13 @@ +package com.breadwallet.crypto.core.bitcoin; + +import com.breadwallet.crypto.api.bitcoin.BitcoinChainParams; + +/* package */ final class BitcoinChainParamsAdapter { + + public static com.breadwallet.crypto.core.bitcoin.BitcoinChainParams from(BitcoinChainParams bcp) { + if (bcp instanceof com.breadwallet.crypto.core.bitcoin.BitcoinChainParams) { + return (com.breadwallet.crypto.core.bitcoin.BitcoinChainParams) bcp; + } + throw new IllegalArgumentException("Unsupported BitcoinChainParams implementation"); + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinMasterPubKey.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinMasterPubKey.java new file mode 100644 index 000000000..7996ed087 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinMasterPubKey.java @@ -0,0 +1,18 @@ +package com.breadwallet.crypto.core.bitcoin; + +import com.breadwallet.crypto.core.bitcoin.jni.CoreBitcoinMasterPubKey; + +public final class BitcoinMasterPubKey implements com.breadwallet.crypto.api.bitcoin.BitcoinMasterPubKey { + + private final CoreBitcoinMasterPubKey masterPubKey; + + public BitcoinMasterPubKey(byte[] seed) { + // TODO: Add additional seed validation, if necessary + if (null == seed) throw new IllegalArgumentException("Invalid seed"); + this.masterPubKey = new CoreBitcoinMasterPubKey(seed); + } + + /* package */ CoreBitcoinMasterPubKey masterPubKey() { + return masterPubKey; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinMasterPubKeyAdapter.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinMasterPubKeyAdapter.java new file mode 100644 index 000000000..b68338925 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinMasterPubKeyAdapter.java @@ -0,0 +1,13 @@ +package com.breadwallet.crypto.core.bitcoin; + +import com.breadwallet.crypto.api.bitcoin.BitcoinMasterPubKey; + +/* package */ final class BitcoinMasterPubKeyAdapter { + + public static com.breadwallet.crypto.core.bitcoin.BitcoinMasterPubKey from(BitcoinMasterPubKey mbk) { + if (mbk instanceof com.breadwallet.crypto.core.bitcoin.BitcoinMasterPubKey) { + return (com.breadwallet.crypto.core.bitcoin.BitcoinMasterPubKey) mbk; + } + throw new IllegalArgumentException("Unsupported BitcoinMasterPubKey implementation"); + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinWallet.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinWallet.java new file mode 100644 index 000000000..b6f672025 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinWallet.java @@ -0,0 +1,47 @@ +package com.breadwallet.crypto.core.bitcoin; + +import com.breadwallet.crypto.api.Amount; +import com.breadwallet.crypto.api.Currency; +import com.breadwallet.crypto.api.Transfer; +import com.breadwallet.crypto.api.Wallet; +import com.breadwallet.crypto.api.WalletManager; +import com.breadwallet.crypto.api.Bitcoin; +import com.breadwallet.crypto.core.bitcoin.jni.CoreBitcoinWallet; + +public final class BitcoinWallet implements Wallet { + + private final CoreBitcoinWallet wallet; + private final BitcoinWalletManager walletManager; + + /* packate */ BitcoinWallet(CoreBitcoinWallet wallet, BitcoinWalletManager walletManager) { + this.wallet = wallet; + this.walletManager = walletManager; + } + + @Override + public WalletManager manager() { + return walletManager; + } + + @Override + public String name() { + return Bitcoin.CURRENCY.name; + } + + @Override + public Currency currency() { + return Bitcoin.CURRENCY; + } + + @Override + public Amount balance() { + // TODO: Implement this + return null; + } + + @Override + public Transfer[] transfers() { + // TODO: Implement this + return new Transfer[0]; + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinWalletManager.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinWalletManager.java new file mode 100644 index 000000000..fb3767095 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/BitcoinWalletManager.java @@ -0,0 +1,217 @@ +package com.breadwallet.crypto.core.bitcoin; + +import com.breadwallet.crypto.api.Account; +import com.breadwallet.crypto.api.Amount; +import com.breadwallet.crypto.api.Network; +import com.breadwallet.crypto.api.Wallet; +import com.breadwallet.crypto.api.WalletManager; +import com.breadwallet.crypto.api.Bitcoin; +import com.breadwallet.crypto.api.bitcoin.BitcoinBackendClient; +import com.breadwallet.crypto.api.bitcoin.BitcoinPersistenceClient; +import com.breadwallet.crypto.api.bitcoin.BitcoinWalletManagerListener; +import com.breadwallet.crypto.api.events.wallet.BalanceUpdatedWalletEvent; +import com.breadwallet.crypto.api.events.wallet.CreatedWalletEvent; +import com.breadwallet.crypto.api.events.wallet.DeletedWalletEvent; +import com.breadwallet.crypto.api.events.walletmanager.ChangedWalletManagerEvent; +import com.breadwallet.crypto.api.events.walletmanager.SyncEndedWalletManagerEvent; +import com.breadwallet.crypto.api.events.walletmanager.SyncStartedWalletManagerEvent; +import com.breadwallet.crypto.core.bitcoin.jni.CoreBitcoinChainParams; +import com.breadwallet.crypto.core.bitcoin.jni.CoreBitcoinMasterPubKey; +import com.breadwallet.crypto.core.bitcoin.jni.CoreBitcoinWallet; +import com.breadwallet.crypto.core.bitcoin.jni.CoreBitcoinWalletManager; +import com.breadwallet.crypto.core.bitcoin.jni.CoreBitcoinWalletManagerClient; + +import java.lang.ref.WeakReference; +import java.util.concurrent.Executor; + +// TODO: Verify assumption that CoreBitcoinWalletManagerClient callbacks are on single native thread +public final class BitcoinWalletManager extends WalletManager implements CoreBitcoinWalletManagerClient { + + private final WeakReference listener; + private final CoreBitcoinWalletManager coreWalletManager; + + private final BitcoinPersistenceClient persistenceClient; + private final BitcoinBackendClient backendClient; + + private final Account account; + private final Network network; + private final Mode mode; + private final long earliestKeyTime; + private final String storagePath; + private final Executor listenerExecutor; + + private State state; + + public BitcoinWalletManager(Account account, + Network network, + Mode mode, + int earliestKeyTime, + String storagePath, + BitcoinPersistenceClient persistenceClient, + BitcoinBackendClient backendClient, + BitcoinWalletManagerListener listener, + Executor listenerExecutor) { + if (null == account) throw new IllegalArgumentException("Invalid seed"); + if (null == network) throw new IllegalArgumentException("Invalid network"); + if (null == mode) throw new IllegalArgumentException("Invalid mode"); + if (earliestKeyTime < 0) throw new IllegalArgumentException("Invalid earliest key time"); + if (null == storagePath) throw new IllegalArgumentException("Invalid storage path"); + if (null == persistenceClient) throw new IllegalArgumentException("Invalid persistence client"); + if (null == backendClient) throw new IllegalArgumentException("Invalid backend client"); + if (null == listener) throw new IllegalArgumentException("Invalid listener"); + if (null == listenerExecutor) throw new IllegalArgumentException("Invalid listener executor"); + + CoreBitcoinChainParams chainParams = BitcoinChainParamsAdapter.from(network.chainParams()).chainParams(); + CoreBitcoinMasterPubKey masterPubKey = BitcoinMasterPubKeyAdapter.from(account.masterPublicKey()).masterPubKey(); + + this.listenerExecutor = listenerExecutor; + this.account = account; + this.network = network; + this.mode = mode; + this.earliestKeyTime = earliestKeyTime; + this.storagePath = storagePath; + this.state = State.CREATED; + + this.persistenceClient = persistenceClient; + this.backendClient = backendClient; + + this.listener = new WeakReference<>(listener); + this.coreWalletManager = new CoreBitcoinWalletManager(this, masterPubKey, chainParams, earliestKeyTime, storagePath); + } + + // WalletManager + + @Override + public void connect() { + coreWalletManager.connect(); + } + + @Override + public void disconnect() { + coreWalletManager.disconnect(); + } + + // CoreWalletManagerClient + + @Override + public void handleTransactionAdded(CoreBitcoinWallet coreWallet) { + listenerExecutor.execute(() -> { + BitcoinWalletManagerListener l = listener.get(); + if (l != null) { + // TODO: Implement this + } + }); + } + + @Override + public void handleTransactionUpdated(CoreBitcoinWallet coreWallet) { + listenerExecutor.execute(() -> { + BitcoinWalletManagerListener l = listener.get(); + if (l != null) { + // TODO: Implement this + } + }); + } + + @Override + public void handleTransactionDeleted(CoreBitcoinWallet coreWallet) { + listenerExecutor.execute(() -> { + BitcoinWalletManagerListener l = listener.get(); + if (l != null) { + // TODO: Implement this + } + }); + } + + @Override + public void handleWalletCreated(CoreBitcoinWallet coreWallet) { + listenerExecutor.execute(() -> { + BitcoinWalletManagerListener l = listener.get(); + if (l != null) { + Wallet wallet = new BitcoinWallet(coreWallet, this); + l.handleWalletEvent(this, wallet, new CreatedWalletEvent()); + } + }); + } + + @Override + public void handleWalletBalanceUpdated(CoreBitcoinWallet coreWallet, long satoshi) { + listenerExecutor.execute(() -> { + BitcoinWalletManagerListener l = listener.get(); + if (l != null) { + Wallet wallet = new BitcoinWallet(coreWallet, this); + Amount amount = new Amount(satoshi, Bitcoin.SATOSHI); + l.handleWalletEvent(this, wallet, new BalanceUpdatedWalletEvent(amount)); + } + }); + } + + @Override + public void handleWalletDeleted(CoreBitcoinWallet coreWallet) { + listenerExecutor.execute(() -> { + BitcoinWalletManagerListener l = listener.get(); + if (l != null) { + Wallet wallet = new BitcoinWallet(coreWallet, this); + l.handleWalletEvent(this, wallet, new DeletedWalletEvent()); + } + }); + } + + @Override + public void handleWalletManagerConnected() { + State oldState = state; + state = State.CONNECTED; + State newState = state; + + listenerExecutor.execute(() -> { + BitcoinWalletManagerListener l = listener.get(); + if (l != null) { + l.handleManagerEvent(this, new ChangedWalletManagerEvent(oldState, newState)); + } + }); + } + + @Override + public void handleWalletManagerDisconnected() { + State oldState = state; + state = State.DISCONNECTED; + State newState = state; + + listenerExecutor.execute(() -> { + BitcoinWalletManagerListener l = listener.get(); + if (l != null) { + l.handleManagerEvent(this, new ChangedWalletManagerEvent(oldState, newState)); + } + }); + } + + @Override + public void handleWalletManagerSyncStarted() { + State oldState = state; + state = State.SYNCING; + State newState = state; + + listenerExecutor.execute(() -> { + BitcoinWalletManagerListener l = listener.get(); + if (l != null) { + l.handleManagerEvent(this, new ChangedWalletManagerEvent(oldState, newState)); + l.handleManagerEvent(this, new SyncStartedWalletManagerEvent()); + } + }); + } + + @Override + public void handleWalletManagerSyncStopped(String error) { + State oldState = state; + state = State.CONNECTED; + State newState = state; + + listenerExecutor.execute(() -> { + BitcoinWalletManagerListener l = listener.get(); + if (l != null) { + l.handleManagerEvent(this, new ChangedWalletManagerEvent(oldState, newState)); + l.handleManagerEvent(this, new SyncEndedWalletManagerEvent(error)); + } + }); + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinChainParams.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinChainParams.java new file mode 100644 index 000000000..ef0d4d5bf --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinChainParams.java @@ -0,0 +1,14 @@ +package com.breadwallet.crypto.core.bitcoin.jni; + +import com.breadwallet.crypto.core.common.jni.JniReference; + +public final class CoreBitcoinChainParams extends JniReference { + + public static CoreBitcoinChainParams TESTNET = new CoreBitcoinChainParams(createTestnetChainParams()); + + private static native long createTestnetChainParams(); + + private CoreBitcoinChainParams(long jniReferenceAddress) { + super(jniReferenceAddress); + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinMasterPubKey.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinMasterPubKey.java new file mode 100644 index 000000000..aebb8f4df --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinMasterPubKey.java @@ -0,0 +1,13 @@ +package com.breadwallet.crypto.core.bitcoin.jni; + +import com.breadwallet.crypto.api.bitcoin.BitcoinMasterPubKey; +import com.breadwallet.crypto.core.common.jni.JniReference; + +public final class CoreBitcoinMasterPubKey extends JniReference implements BitcoinMasterPubKey { + + private static native long createBitcoinMasterPubKey (byte[] seed); + + public CoreBitcoinMasterPubKey(byte[] seed) { + super(createBitcoinMasterPubKey(seed)); + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinWallet.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinWallet.java new file mode 100644 index 000000000..9bc43a92c --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinWallet.java @@ -0,0 +1,20 @@ +package com.breadwallet.crypto.core.bitcoin.jni; + +import com.breadwallet.crypto.core.common.jni.JniReference; + +public class CoreBitcoinWallet extends JniReference { + + // Maintain a reference to the owning wallet manager to avoid a user after free + private final CoreBitcoinWalletManager owner; + + /* package */ CoreBitcoinWallet(long jniReferenceAddress, CoreBitcoinWalletManager owner) { + super(jniReferenceAddress); + this.owner = owner; + } + + @Override + protected void dispose() { + // Intentionally omit call to disposeNative() as the jniReferenceAddress is borrowed + // from the owning wallet manager + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinWalletManager.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinWalletManager.java new file mode 100644 index 000000000..3ee433ac8 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinWalletManager.java @@ -0,0 +1,199 @@ +package com.breadwallet.crypto.core.bitcoin.jni; + +import com.breadwallet.crypto.core.common.jni.JniReference; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; + +public final class CoreBitcoinWalletManager extends JniReference { + + private static final Map> wmMap = new HashMap<>(); + + private static native long createBitcoinWalletManager(CoreBitcoinMasterPubKey mpk, + CoreBitcoinChainParams params, + int earliestKeyTime, + String storagePath); + + private static native void initializeNative(); + + private static CoreBitcoinWalletManager lookupWM (long wmid) { + WeakReference wm = wmMap.get(wmid); + return (null== wm ? null : wm.get()); + } + + private static void handleTransactionAdded(long wmid, long wid, long tid) { + CoreBitcoinWalletManager walletManager = lookupWM(wmid); + if (null != walletManager) { + walletManager.handleTransactionAdded(wid, tid); + } + } + + private static void handleTransactionUpdated(long wmid, long wid, long tid) { + CoreBitcoinWalletManager walletManager = lookupWM(wmid); + if (null != walletManager) { + walletManager.handleTransactionUpdated(wid, tid); + } + } + + private static void handleTransactionDeleted(long wmid, long wid, long tid) { + CoreBitcoinWalletManager walletManager = lookupWM(wmid); + if (null != walletManager) { + walletManager.handleTransactionDeleted(wid, tid); + } + } + + private static void handleWalletCreated(long wmid, long wid) { + CoreBitcoinWalletManager walletManager = lookupWM(wmid); + if (null != walletManager) { + walletManager.handleWalletCreated(wid); + } + } + + private static void handleWalletBalanceUpdated(long wmid, long wid, long satoshi) { + CoreBitcoinWalletManager walletManager = lookupWM(wmid); + if (null != walletManager) { + walletManager.handleWalletBalanceUpdated(wid, satoshi); + } + } + + private static void handleWalletDeleted(long wmid, long wid) { + CoreBitcoinWalletManager walletManager = lookupWM(wmid); + if (null != walletManager) { + walletManager.handleWalletDeleted(wid); + } + } + + private static void handleWalletManagerConnected(long wmid) { + CoreBitcoinWalletManager walletManager = lookupWM(wmid); + if (null != walletManager) { + walletManager.handleWalletManagerConnected(); + } + } + + private static void handleWalletManagerDisconnected(long wmid) { + CoreBitcoinWalletManager walletManager = lookupWM(wmid); + if (null != walletManager) { + walletManager.handleWalletManagerDisconnected(); + } + } + + private static void handleWalletManagerSyncStarted(long wmid) { + CoreBitcoinWalletManager walletManager = lookupWM(wmid); + if (null != walletManager) { + walletManager.handleWalletManagerSyncStarted(); + } + } + + private static void handleWalletManagerSyncStopped(long wmid, int errorCode) { + CoreBitcoinWalletManager walletManager = lookupWM(wmid); + if (null != walletManager) { + walletManager.handleWalletManagerSyncStopped(errorCode); + } + } + + static { initializeNative(); } + + private final WeakReference client; + + public CoreBitcoinWalletManager(CoreBitcoinWalletManagerClient client, + CoreBitcoinMasterPubKey mpk, + CoreBitcoinChainParams params, + int earliestKeyTime, + String storagePath) { + // ISSUE: we miss the first event because we are not registerd in the map yet, look into + // solutions + super(createBitcoinWalletManager(mpk, params, earliestKeyTime, storagePath)); + + wmMap.put(jniReferenceAddress, new WeakReference<> (this)); + + this.client = new WeakReference<>(client); + } + + public native void connect(); + + public native void disconnect(); + + @Override + protected native void disposeNative(); + + private void handleTransactionAdded(long wid, long tid) { + CoreBitcoinWalletManagerClient wmc = client.get(); + if (null != wmc) { + // TODO: Use tid to create transfer wrapper + CoreBitcoinWallet wallet = new CoreBitcoinWallet(wid, this); + wmc.handleTransactionAdded(wallet); + } + } + + private void handleTransactionUpdated(long wid, long tid) { + CoreBitcoinWalletManagerClient wmc = client.get(); + if (null != wmc) { + // TODO: Use tid to create transfer wrapper + CoreBitcoinWallet wallet = new CoreBitcoinWallet(wid, this); + wmc.handleTransactionUpdated(wallet); + } + } + + private void handleTransactionDeleted(long wid, long tid) { + CoreBitcoinWalletManagerClient wmc = client.get(); + if (null != wmc) { + // TODO: Use tid to create transfer wrapper + CoreBitcoinWallet wallet = new CoreBitcoinWallet(wid, this); + wmc.handleTransactionDeleted(wallet); + } + } + + private void handleWalletCreated(long wid) { + CoreBitcoinWalletManagerClient wmc = client.get(); + if (null != wmc) { + CoreBitcoinWallet wallet = new CoreBitcoinWallet(wid, this); + wmc.handleWalletCreated(wallet); + } + } + + private void handleWalletBalanceUpdated(long wid, long satoshi) { + CoreBitcoinWalletManagerClient wmc = client.get(); + if (null != wmc) { + CoreBitcoinWallet wallet = new CoreBitcoinWallet(wid, this); + wmc.handleWalletBalanceUpdated(wallet, satoshi); + } + } + + private void handleWalletDeleted(long wid) { + CoreBitcoinWalletManagerClient wmc = client.get(); + if (null != wmc) { + CoreBitcoinWallet wallet = new CoreBitcoinWallet(wid, this); + wmc.handleWalletDeleted(wallet); + } + } + + private void handleWalletManagerConnected() { + CoreBitcoinWalletManagerClient wmc = client.get(); + if (null != wmc) { + wmc.handleWalletManagerConnected(); + } + } + + private void handleWalletManagerDisconnected() { + CoreBitcoinWalletManagerClient wmc = client.get(); + if (null != wmc) { + wmc.handleWalletManagerDisconnected(); + } + } + + private void handleWalletManagerSyncStarted() { + CoreBitcoinWalletManagerClient wmc = client.get(); + if (null != wmc) { + wmc.handleWalletManagerSyncStarted(); + } + } + + private void handleWalletManagerSyncStopped(int errorCode) { + CoreBitcoinWalletManagerClient wmc = client.get(); + if (null != wmc) { + // TODO: Convert error code to string properly + wmc.handleWalletManagerSyncStopped(Integer.toString(errorCode)); + } + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinWalletManagerClient.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinWalletManagerClient.java new file mode 100644 index 000000000..302ffec3f --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/bitcoin/jni/CoreBitcoinWalletManagerClient.java @@ -0,0 +1,17 @@ +package com.breadwallet.crypto.core.bitcoin.jni; + +public interface CoreBitcoinWalletManagerClient { + + void handleTransactionAdded(CoreBitcoinWallet wallet); + void handleTransactionUpdated(CoreBitcoinWallet wallet); + void handleTransactionDeleted(CoreBitcoinWallet wallet); + + void handleWalletCreated(CoreBitcoinWallet wallet); + void handleWalletBalanceUpdated(CoreBitcoinWallet wallet, long satoshi); + void handleWalletDeleted(CoreBitcoinWallet wallet); + + void handleWalletManagerConnected(); + void handleWalletManagerDisconnected(); + void handleWalletManagerSyncStarted(); + void handleWalletManagerSyncStopped(String error); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/common/jni/JniReference.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/common/jni/JniReference.java new file mode 100644 index 000000000..5da9731a7 --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/common/jni/JniReference.java @@ -0,0 +1,37 @@ +package com.breadwallet.crypto.core.common.jni; + +public class JniReference { + + protected static boolean SHOW_FINALIZE = false; + + /** + * C Pointer (as a Java long) to the underlying Breadwallet Core entity allocated from the + * C heap memory. The referenced Core entity is used to implement native functions that + * call Core functions (and thus expect a Core entity). + * + * The address must be determined in a subclass specific way and thus must be provided in the + * subclasses constructor. + */ + protected long jniReferenceAddress; + + protected JniReference(long jniReferenceAddress) + { + this.jniReferenceAddress = jniReferenceAddress; + } + + protected void finalize() throws Throwable { + if (SHOW_FINALIZE) System.err.println("Finalize: " + toString()); + dispose(); + } + + protected void dispose() { + disposeNative(); + } + + protected native void disposeNative(); + + @Override + public String toString() { + return getClass().getName() + "@" + Integer.toHexString(hashCode()); + } +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/core/jni/Bip39.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/jni/Bip39.java new file mode 100644 index 000000000..772a96dbc --- /dev/null +++ b/Java/Crypto/src/main/java/com/breadwallet/crypto/core/jni/Bip39.java @@ -0,0 +1,8 @@ +package com.breadwallet.crypto.core.jni; + +// TODO: Expose a public static native method that wraps a private static native impl to +// facilitate checks +public class Bip39 { + + public static native byte[] deriveKey(String phrase); +} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/ethereum/Ethereum.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/ethereum/Ethereum.java deleted file mode 100644 index 9d1926288..000000000 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/ethereum/Ethereum.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.breadwallet.crypto.ethereum; - -import com.breadwallet.crypto.Currency; -import com.breadwallet.crypto.Network; -import com.breadwallet.crypto.Unit; - -public interface Ethereum { - Currency currency = new Currency ("ETH", "Ξ", "Ethereum", 18, "WEI", "wei"); - interface Units { - Unit WEI = currency.baseUnit; - Unit ETHER = currency.defaultUnit; - - Unit GWEI = new Unit ("GWEI", "gwei", 1000000000, WEI); - } - - interface Networks { - Network mainnet = new Network(new Network.Ethereum("Eth Mainnet", 1)); - Network ropsten = new Network(new Network.Ethereum("Eth Ropsten", 3)); - Network rinkeby = new Network(new Network.Ethereum("Eth Rinkeby", 4)); - } -} - diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/ethereum/Transfer.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/ethereum/Transfer.java deleted file mode 100644 index ba8a5ca4d..000000000 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/ethereum/Transfer.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.breadwallet.crypto.ethereum; - -import com.breadwallet.crypto.Address; -import com.breadwallet.crypto.Amount; -import com.breadwallet.crypto.Wallet; - -class Transfer extends com.breadwallet.crypto.Transfer { - long core; - - private Transfer(long core, Wallet wallet, Address source, Address target, Amount amount, Amount fee) { - super(wallet, source, target, amount, fee); - this.core = core; - } - - protected Transfer (Wallet wallet, long core) { - this (core, wallet, null, null, null, null); - } - -} diff --git a/Java/Crypto/src/main/java/com/breadwallet/crypto/ethereum/Wallet.java b/Java/Crypto/src/main/java/com/breadwallet/crypto/ethereum/Wallet.java deleted file mode 100644 index fccc8a8c7..000000000 --- a/Java/Crypto/src/main/java/com/breadwallet/crypto/ethereum/Wallet.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.breadwallet.crypto.ethereum; - -import com.breadwallet.crypto.Amount; -import com.breadwallet.crypto.Currency; -import com.breadwallet.crypto.WalletManager; - -public class Wallet extends com.breadwallet.crypto.Wallet { - long core; - - /// Balance - - protected Amount balance; - - @Override - public Amount getBalance() { - return balance; - } - - protected void setBalance(Amount balance) { - this.balance = balance; - } - - /// Transfers - protected Transfer[] transfers; - - public Transfer[] getTransfers() { - return transfers; - } - - public void setTransfers(Transfer[] transfers) { - this.transfers = transfers; - } - - - public Wallet(long core, WalletManager manager, Currency currency, String name, Amount balance, Transfer[] transfers) { - super(manager, currency, name); - this.core = core; - this.balance = balance; - this.transfers = transfers; - } - - public Wallet (WalletManager manager, Currency currency, long core) { - this (core, manager, currency, currency.name, - new Amount (0, currency.baseUnit), - new Transfer[]{}); - } -}