This is continuation
to my previous post. Before reading this tutorial, I would recommend you to go
through my previous post 'Create simple Block chain using java'.
In this
tutorial, you are going to learn,
a. How to create a wallet
b. How to transfer money to other
wallet using block chain
To give a
persona, Bob, Alice and John are three users, want to use buka block chain to
transfer 'buka' coins.
a. Bob
wants to send 100 buka coins to Alice
b. John
wants to send 50 buka coins to Alice
How to create a wallet?
To transfer/receive the coins, you should have a wallet. Each wallet has unique address to receive the coins from other users.
Let's
create our Wallet first.
public
class Wallet {
private PrivateKey privateKey;
private PublicKey publicKey;
....
....
}
‘publicKey’
represents the wallet address, if User X wants to send N coins to User Y, then
X send coins to Y wallet public key. For our 'buka' coin, public key of the
wallet acts as address. User can share this public key to other users to
receive the payment.
‘privateKey’
is used to sign the transactions(Do not share wallet private key).
How to transfer money to other wallet
using block chain?
Procedure looks
like below.
A. Users Bob, Alice, and John create
their own wallets from ‘Buka’ block chain.
Wallet
bobWallet = bukaChainGenerator.newWallet();
Wallet
aliceWallet = bukaChainGenerator.newWallet();
Wallet
johnWallet = bukaChainGenerator.newWallet();
B. If user Bob wants to send 100 ‘buka’ coins
to Alice, then bob creates a transaction, that contains bobs address (Bob
public key), Alice address (Alice public key), amount to transfer, time stamp.
Bob
signs the transaction and submit this transaction to ‘Buka’ block chain.
public boolean sendMoney(PublicKey destinationAddress, double amount) throws Exception { Transaction transaction = TransactionGenerator.createTransaction(this.publicKey, destinationAddress, amount); byte[] signature = SignatureUtil.getSignature(transaction, this.privateKey, Constants.ALGORITHM_TO_SIGN); transaction.setDigitalSignature(signature); blockChainGenerator.submitTransaction(transaction, Constants.ALGORITHM_TO_SIGN); return true; }
c. ‘Buka’
block chain verifies the signature of the transaction and checks whether Bob
really has the amount in his wallet to transfer or not (right now this
validation is not implemented). If validation succeeds, then it creates a new block
with this transactional data.
public void createNewBlock(Transaction transactionalData) { Block<Transaction> block = new Block<>(); block.setTransactionalData(transactionalData); block.setPreviousBlockHashCode(lastBlock.getHashCode()); lastBlock.setNextBlock(block); lastBlock = block; HashUtil.setHashCode(block); }
Find the
below working application.
Constants.java
package com.sample.app.constants; public class Constants { public static final String ALGORITHM_TO_GENERATE_KEY_PAIR = "RSA"; public static final String ALGORITHM_TO_SIGN = "SHA256withRSA"; }
Block.java
package com.sample.app.model; import com.google.gson.annotations.Expose; public class Block<T> { @Expose private String hashCode; @Expose private String previousBlockHashCode; @Expose private T transactionalData; @Expose private long timeStamp; @Expose private Block<T> nextBlock; public String getHashCode() { return hashCode; } public void setHashCode(String hashCode) { this.hashCode = hashCode; } public String getPreviousBlockHashCode() { return previousBlockHashCode; } public void setPreviousBlockHashCode(String previousBlockHashCode) { this.previousBlockHashCode = previousBlockHashCode; } public T getTransactionalData() { return transactionalData; } public void setTransactionalData(T transactionalData) { this.transactionalData = transactionalData; } public long getTimeStamp() { return timeStamp; } public void setTimeStamp(long timeStamp) { this.timeStamp = timeStamp; } public Block<T> getNextBlock() { return nextBlock; } public void setNextBlock(Block<T> nextBlock) { this.nextBlock = nextBlock; } }
Transaction.java
package com.sample.app.model; import java.security.PublicKey; import java.util.Date; import com.google.gson.annotations.Expose; import com.sample.app.util.StringUtil; public class Transaction { @Expose private String id; private PublicKey sourceAddress; private PublicKey destinationAddress; @Expose private double amountTransferred; private byte[] digitalSignature; @Expose private String signature; // It is string representation of digitalSignature @Expose private long transactionCreatedTime; @Expose private String sourceWalletAddress; // String representation of sourceAddress @Expose private String destinationWalletAddress; // String representation of destinationAddress public Transaction() { Date date = new Date(); this.transactionCreatedTime = date.getTime(); } public String getId() { return id; } public void setId(String id) { this.id = id; } public PublicKey getSourceAddress() { return sourceAddress; } public void setSourceAddress(PublicKey sourceAddress) { this.sourceAddress = sourceAddress; this.sourceWalletAddress = StringUtil.toHexString(this.sourceAddress.getEncoded()); } public PublicKey getDestinationAddress() { return destinationAddress; } public void setDestinationAddress(PublicKey destinationAddress) { this.destinationAddress = destinationAddress; this.destinationWalletAddress = StringUtil.toHexString(this.destinationAddress.getEncoded()); } public double getAmountTransferred() { return amountTransferred; } public void setAmountTransferred(double amountTransferred) { this.amountTransferred = amountTransferred; } public byte[] getDigitalSignature() { return digitalSignature; } public void setDigitalSignature(byte[] digitalSignature) { this.digitalSignature = digitalSignature; this.signature = StringUtil.toHexString(digitalSignature); } public long getTransactionCreatedTime() { return transactionCreatedTime; } public void setTransactionCreatedTime(long transactionCreatedTime) { this.transactionCreatedTime = transactionCreatedTime; } public String getSourceWalletAddress() { return this.sourceWalletAddress; } public String getDestinationWalletAddress() { return this.destinationWalletAddress; } public String getSignature() { return this.signature; } public byte[] getDataToBeSigned() { StringBuilder builder = new StringBuilder(); builder.append(StringUtil.toHexString(this.sourceAddress.getEncoded())); builder.append(StringUtil.toHexString(this.destinationAddress.getEncoded())); builder.append(this.amountTransferred); builder.append(this.transactionCreatedTime); builder.append(this.id); return builder.toString().getBytes(); } public String toString() { return new String(getDataToBeSigned()); } }
Wallet.java
package com.sample.app.model; import java.security.PrivateKey; import java.security.PublicKey; import com.sample.app.constants.Constants; import com.sample.app.generators.BlockChainGenerator; import com.sample.app.generators.TransactionGenerator; import com.sample.app.util.SignatureUtil; /** * Wallet represents a virtual wallet where user can store crypto coins. * * publicKey represents the wallet address, if User X wants to send N coins to * User Y, then X send coins to Y wallet address. * * privateKey is used to sign the transactions. Do not share wallet private key. * * */ public class Wallet { private PrivateKey privateKey; private PublicKey publicKey; private BlockChainGenerator blockChainGenerator; public PrivateKey getPrivateKey() { return privateKey; } public void setPrivateKey(PrivateKey privateKey) { this.privateKey = privateKey; } public PublicKey getPublicKey() { return publicKey; } public void setPublicKey(PublicKey publicKey) { this.publicKey = publicKey; } public BlockChainGenerator getBlockChainGenerator() { return blockChainGenerator; } public void setBlockChainGenerator(BlockChainGenerator blockChainGenerator) { this.blockChainGenerator = blockChainGenerator; } public boolean sendMoney(PublicKey destinationAddress, double amount) throws Exception { Transaction transaction = TransactionGenerator.createTransaction(this.publicKey, destinationAddress, amount); byte[] signature = SignatureUtil.getSignature(transaction, this.privateKey, Constants.ALGORITHM_TO_SIGN); transaction.setDigitalSignature(signature); blockChainGenerator.submitTransaction(transaction, Constants.ALGORITHM_TO_SIGN); return true; } }
HashUtil.java
package com.sample.app.util; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Date; import com.sample.app.model.Block; public class HashUtil { public static final char[] HEXDIGITS = "0123456789ABCDEF".toCharArray(); private static MessageDigest getMessageDigest() { MessageDigest messageDigest = null; try { messageDigest = MessageDigest.getInstance("SHA-256"); return messageDigest; } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } public static <T> void setHashCode(Block<T> block) { MessageDigest messageDigest = getMessageDigest(); String hashCode = block.getPreviousBlockHashCode(); Date date = new Date(); block.setTimeStamp(date.getTime()); long time = date.getTime(); String transactionalData = block.getTransactionalData().toString(); String finalData = hashCode + transactionalData + time; messageDigest.update(finalData.getBytes()); byte[] digest = messageDigest.digest(); block.setHashCode(StringUtil.toHexString(digest)); } public static String getHash(String data) { MessageDigest messageDigest = getMessageDigest(); messageDigest.update(data.getBytes()); byte[] digest = messageDigest.digest(); return StringUtil.toHexString(digest); } }
JSONUtil.java
package com.sample.app.util; import com.google.gson.Gson; import com.google.gson.GsonBuilder; public class JSONUtil { private static Gson gson = new Gson(); private static Gson exclusedGson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().setPrettyPrinting().create(); private static Gson prettyGson = new GsonBuilder().setPrettyPrinting().create(); public static String getJson(Object obj) { return gson.toJson(obj); } public static String getOnlyExposedJson(Object obj) { return exclusedGson.toJson(obj); } public static String getPrettyJson(Object obj) { return prettyGson.toJson(obj); } public static <T> T getObject(String json, Class<T> clazz) { return gson.fromJson(json, clazz); } }
PublicKeyUtil.java
package com.sample.app.util; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; public class PublicKeyUtil { public static KeyPair getKeyPair(String algorithm) throws NoSuchAlgorithmException { KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm); return keyPairGenerator.generateKeyPair(); } }
SignatureUtil.java
package com.sample.app.util; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.SignatureException; import com.sample.app.model.Transaction; public class SignatureUtil { public static byte[] getSignature(Transaction transaction, PrivateKey senderPrivateKey, String algorithmToSign) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException { /* Get instance of Signature object */ Signature signature = Signature.getInstance(algorithmToSign); /* Initialize Signature object */ signature.initSign(senderPrivateKey); /* Feed Data */ signature.update(transaction.getDataToBeSigned()); /* Generate signature */ byte[] finalSig = signature.sign(); return finalSig; } public static boolean verifySignature(Transaction transaction, PublicKey publicKey, String algorithm) throws Exception { Signature verifySignature = Signature.getInstance(algorithm); verifySignature.initVerify(publicKey); verifySignature.update(transaction.getDataToBeSigned()); /* Verify signature */ return verifySignature.verify(transaction.getDigitalSignature()); } }
StringUtil.java
package com.sample.app.util; public class StringUtil { public static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 3); for (int b : bytes) { b &= 0xff; sb.append(HashUtil.HEXDIGITS[b >> 4]); sb.append(HashUtil.HEXDIGITS[b & 15]); // sb.append(' '); } return sb.toString(); } }
BlockChainGenerator.java
package com.sample.app.generators; import java.security.NoSuchAlgorithmException; import com.sample.app.constants.Constants; import com.sample.app.model.Block; import com.sample.app.model.Transaction; import com.sample.app.model.Wallet; import com.sample.app.util.HashUtil; import com.sample.app.util.JSONUtil; import com.sample.app.util.SignatureUtil; public class BlockChainGenerator { private Block<Transaction> rootBlock = null; private Block<Transaction> lastBlock = null; public void startNewBlockChain() { rootBlock = new Block<Transaction>(); rootBlock.setPreviousBlockHashCode(""); // HashUtil.update(rootBlock); lastBlock = rootBlock; } public void createNewBlock(Transaction transactionalData) { Block<Transaction> block = new Block<>(); block.setTransactionalData(transactionalData); block.setPreviousBlockHashCode(lastBlock.getHashCode()); lastBlock.setNextBlock(block); lastBlock = block; HashUtil.setHashCode(block); } public void printBlockChain() { System.out.println(JSONUtil.getOnlyExposedJson(rootBlock)); } public boolean isChainvalid() { if (rootBlock == null) return true; Block<Transaction> nextBlock = rootBlock.getNextBlock(); if (nextBlock == null) return true; Block<Transaction> currentBlock = nextBlock; nextBlock = currentBlock.getNextBlock(); while (nextBlock != null) { if (!nextBlock.getPreviousBlockHashCode().equals(currentBlock.getHashCode())) { return false; } currentBlock = nextBlock; nextBlock = nextBlock.getNextBlock(); } return true; } public boolean submitTransaction(Transaction transaction, String algorithmToSign) throws Exception { boolean isvalid = SignatureUtil.verifySignature(transaction, transaction.getSourceAddress(), algorithmToSign); if (!isvalid) { return false; } this.createNewBlock(transaction); return true; } public Wallet newWallet() throws NoSuchAlgorithmException { Wallet wallet = WalletGenerator.newWallet(Constants.ALGORITHM_TO_GENERATE_KEY_PAIR); wallet.setBlockChainGenerator(this); return wallet; } }
TransactionGenerator.java
package com.sample.app.generators; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.SignatureException; import com.sample.app.model.Transaction; import com.sample.app.model.Wallet; import com.sample.app.util.HashUtil; import com.sample.app.util.SignatureUtil; import com.sample.app.util.StringUtil; public class TransactionGenerator { public static Transaction createTransaction(PublicKey sourceAddress, PublicKey destinationAddress, double amountToTransfer) { Transaction transaction = new Transaction(); transaction.setSourceAddress(sourceAddress); transaction.setDestinationAddress(destinationAddress); transaction.setAmountTransferred(amountToTransfer); String sourceAddrStr = StringUtil.toHexString(sourceAddress.getEncoded()); String destAddrStr = StringUtil.toHexString(destinationAddress.getEncoded()); String hashStr = sourceAddrStr + destAddrStr + transaction.getTransactionCreatedTime() + amountToTransfer; String id = HashUtil.getHash(hashStr); transaction.setId(id); return transaction; } public static Transaction createTransaction(Wallet senderWallet, PublicKey destinationAddress, double amountToTransfer, String algorithmToSign) throws InvalidKeyException, SignatureException, NoSuchAlgorithmException { Transaction transaction = createTransaction(senderWallet.getPublicKey(), destinationAddress, amountToTransfer); byte[] signature = SignatureUtil.getSignature(transaction, senderWallet.getPrivateKey(), algorithmToSign); transaction.setDigitalSignature(signature); return transaction; } public static Transaction canTransferBukaCoins(Wallet senderWallet, PublicKey destinationAddress, double coinsToTransfer, String algorithmToSign) throws Exception { Transaction transaction = createTransaction(senderWallet, destinationAddress, coinsToTransfer, algorithmToSign); boolean isvalid = SignatureUtil.verifySignature(transaction, senderWallet.getPublicKey(), algorithmToSign); if (isvalid) { return transaction; } return null; } }
WalletGenerator.java
package com.sample.app.generators; import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import com.sample.app.model.Wallet; import com.sample.app.util.PublicKeyUtil; public class WalletGenerator { public static Wallet newWallet(String algorithm) throws NoSuchAlgorithmException { Wallet wallet = new Wallet(); KeyPair keyPair = PublicKeyUtil.getKeyPair(algorithm); wallet.setPrivateKey(keyPair.getPrivate()); wallet.setPublicKey(keyPair.getPublic()); return wallet; } }
App.java
package com.sample.app; import com.sample.app.generators.BlockChainGenerator; import com.sample.app.model.Wallet; public class App { public static void main(String args[]) throws Exception { // Start new block chain BlockChainGenerator bukaChainGenerator = new BlockChainGenerator(); bukaChainGenerator.startNewBlockChain(); // Create wallets Wallet bobWallet = bukaChainGenerator.newWallet(); Wallet aliceWallet = bukaChainGenerator.newWallet(); Wallet johnWallet = bukaChainGenerator.newWallet(); // Bob sent 100 buka coins alice bobWallet.sendMoney(aliceWallet.getPublicKey(), 100); // John sent 50 buka coins to alice johnWallet.sendMoney(aliceWallet.getPublicKey(), 50); // Alice sent 20.76 buka coins to Bob aliceWallet.sendMoney(bobWallet.getPublicKey(), 20.76); // Print block chain, if it is valid if (bukaChainGenerator.isChainvalid()) { bukaChainGenerator.printBlockChain(); } } }
Run App.java,
you can see below kind of output in console.
{ "previousBlockHashCode": "", "timeStamp": 0, "nextBlock": { "hashCode": "D6EF76B13B91A6CCEC1A88B5AF69D9C5F9CA9B742E7031D28375BAE744D8C3F9", "transactionalData": { "id": "A250200EAFE9D115FD1706C6BF44CD45A7F7AB2BC45CAA16453664FD01532EBE", "amountTransferred": 100.0, "signature": "60488582D6929FE0C2E5EAC16598C40ABFF43B5F115F612A37C2E5CBFC0F8260238DEDB1D8B6000E254336EAC2F34FA36A72701F3EE77EEBAC4FCBBB96E5330D768C32BC51A7C6AFCD1F3B242DE02A5B0A2F7CA286EA4545D9E31F214ACBC35E0D0CEDDAB9C888B8E32D5D78E5C25A09C52745A234129AE1F75E08C9AFE9DEEA782C11A0E257701D8F956B63C60F5E0EDE8012CF28BC97B7DB8E880472C84774C931929712E9A48405D759D210CA13D87CF5F53294F2FCA841814FD347C3068355BD7929426EC8C4B79732D0ADBD1131930D099704A96AB03F0C9C2ACA82FA825EF69C751C719F2E3A05760C5990E4FD2FE6AC67EA9EECE2E60575C1D69F3A03", "transactionCreatedTime": 1555058167442, "sourceWalletAddress": "30820122300D06092A864886F70D01010105000382010F003082010A02820101009F8216980AE9DFE731A8C99656F8A3907B5B55B39FC4E3003B6A1C74A381DB5FE585010EAECCA51E90807E79B7A0F90A3D119F9B3D4ACBB27D7D638A84B9FFC2EAB1A17038F905F6A6963F1250E104FA4EBDE9DD65090306E671BC76A2D1DF00BE6ABCD8FF92EC6BBCE603577FDF66BC7A578367A84DBF65C9A2F8FFD0185BDDD8831A6981E53F4100863655E6383662B371899645C6D539BA83DE3F408E6DC8B5AABDD6B8C5D8D702E6A832DC64B327D974433C911B1B1D5F147628E8399819F53B740BE43EB90EE12661786A2196BA3BB2055888558C7EFF31E504DDEA997D2D64F43E2E7C8B48E5D2647AE418EA48CC6A9461DD10BC3730A22AA069CC0BB70203010001", "destinationWalletAddress": "30820122300D06092A864886F70D01010105000382010F003082010A028201010088DD5533E812C8627F78A7DCACFA5CD9F8AA4C79645EBF40DA3363E3EABD1C0452826B5276A1CBBCC687A6B95D0DE145B6A4A22465A229FD694F45A28C122042E48F3AF13524FF63D01B6DECC4D4629A459017DD43FB757D1796DF23B062A4E1D749074F0FA21C518693DBEAAAE84B5DEBA72103F38DA33B58D1C8353BAB9F29CD41F237945BFDE2E49E9AACAA3FD01BA310344A42706FAC47AA12DA61F68A3E9663E65C0F91D51817A1A0E67F9BFBF5CC9DA19ADFE5816689958B3DB6346A4A64B57C9EC0D3B3B6BC2606E55B35AC7CAE9D3C2AE588767CBF3EC3DAEC004BDB7DF82FA6C0DAB0F6D38DF393AC9D1CAE09D1D5A4C4A66B8BF48D9079EA0DF9490203010001" }, "timeStamp": 1555058167450, "nextBlock": { "hashCode": "9725431A8C0D0B3442BC9B77A5A25F63D6DCB9C19931DCB8FFBCB38F0340034B", "previousBlockHashCode": "D6EF76B13B91A6CCEC1A88B5AF69D9C5F9CA9B742E7031D28375BAE744D8C3F9", "transactionalData": { "id": "433729572422DF6C8ECE982A2AC41C9480F83FA2231088310208F0FFD611BCE7", "amountTransferred": 50.0, "signature": "281A6B380297967A24E23B57447ED7928992C50D8129E2915F860127C41BD101BCB68A60F6D2D47DBBAC5E8C89CCF41D6F979B92406921544D21269601F4A3F60EA71485E89797E7527348EBC2AD570547EE0AA79A61361A1283A9D3FE1381D7B03E73B251D7F9F5731E3950F7C2C905180A61AF15EE0628BB832FA97FEA80400062DE0428FA3DFB0698EC7E0956A80C1523D2EA114E459CC6A8E488302418DE6878A67C2BBABA8EB8DBC41257ECC2242C3D72649B835930164E6A939C57B83BF50431B27E1F26176AFC1AE262AA8E6FDCD99D6F68939F8895D71135090CDFC9E675403801BEFBEAAC1F1BFE3D0FED470C7DDEB2C575AFAF5687F28CDCF9E5D8", "transactionCreatedTime": 1555058167450, "sourceWalletAddress": "30820122300D06092A864886F70D01010105000382010F003082010A0282010100AD6E07E87133DB7ED20B5B14AD7DA145B50710CF5E0A58BE159B766D17015C288378A4D5BD00A999DA819357433F6457CC9B277014065639D9C3CDFE6BC4A4EB2426879C2C765FDDD1FFFC5FC4BB900E97B355F3E4D539D2BFB3936D9A8F48B9469DC2AA5E63F780992ADEE5719CD1F0D8B18E95EF085E8F53FF6AD79837FD148A306BA09A219A690E6A761788DF0EFE3546CE3DE57AA5172AC728374B338333033A7D8F1EA648F40BE9F50BC2DCF97B340C4A39D6A2F7B22220F0608ABC0A8AE79E12463259595FA9697223EE9F38B5AF8969EF15117EA4E02DEC0EDBCEFC6EA3EE57984E4903C00297B7A9C035720CD7620362C1E9728A1051338BDA087AAB0203010001", "destinationWalletAddress": "30820122300D06092A864886F70D01010105000382010F003082010A028201010088DD5533E812C8627F78A7DCACFA5CD9F8AA4C79645EBF40DA3363E3EABD1C0452826B5276A1CBBCC687A6B95D0DE145B6A4A22465A229FD694F45A28C122042E48F3AF13524FF63D01B6DECC4D4629A459017DD43FB757D1796DF23B062A4E1D749074F0FA21C518693DBEAAAE84B5DEBA72103F38DA33B58D1C8353BAB9F29CD41F237945BFDE2E49E9AACAA3FD01BA310344A42706FAC47AA12DA61F68A3E9663E65C0F91D51817A1A0E67F9BFBF5CC9DA19ADFE5816689958B3DB6346A4A64B57C9EC0D3B3B6BC2606E55B35AC7CAE9D3C2AE588767CBF3EC3DAEC004BDB7DF82FA6C0DAB0F6D38DF393AC9D1CAE09D1D5A4C4A66B8BF48D9079EA0DF9490203010001" }, "timeStamp": 1555058167454, "nextBlock": { "hashCode": "80C800216856D149CE0CFF8B139239875438E7C33CED86EC73C87B1FECAE2EA0", "previousBlockHashCode": "9725431A8C0D0B3442BC9B77A5A25F63D6DCB9C19931DCB8FFBCB38F0340034B", "transactionalData": { "id": "F3B9B65EBF6B815DCBC148471FCB7C178D7ADEE652516F4E357D2F8F05B65541", "amountTransferred": 20.76, "signature": "028826E5CBB9B352CA1B64B400B71713AAFE7A50DB8800D1DED5C02CA22402857D56EA80AA46A22071A0537A21F36AA4BCFC6BDFAE3F87B9D22129BC3336C993BE810A15F63A5798D39DDD96AB500809D689CDE5D7254BA613163960FA1AC75E683775417068F52E60F4931A37176CF536C58AC76B5A2CE137FC47D6E3C0A749B6FCB19FC0A684EC7103A1A0C9477C6F1AAB65080C5DA6FE15122842C88AC2A2C082FF1BE5C5628340031489604EF6C6C58B7C3EC10169D629E3A4D96CFA69FCD7042FB75AACA6E29DEB5636727CE8D3BF7936D01CCA0E6FEC2E742B5D94774A6B4E42CF6BC3624DDD6B1BA322171D2AE252C9DF23EE82F6293E22ABF950C427", "transactionCreatedTime": 1555058167454, "sourceWalletAddress": "30820122300D06092A864886F70D01010105000382010F003082010A028201010088DD5533E812C8627F78A7DCACFA5CD9F8AA4C79645EBF40DA3363E3EABD1C0452826B5276A1CBBCC687A6B95D0DE145B6A4A22465A229FD694F45A28C122042E48F3AF13524FF63D01B6DECC4D4629A459017DD43FB757D1796DF23B062A4E1D749074F0FA21C518693DBEAAAE84B5DEBA72103F38DA33B58D1C8353BAB9F29CD41F237945BFDE2E49E9AACAA3FD01BA310344A42706FAC47AA12DA61F68A3E9663E65C0F91D51817A1A0E67F9BFBF5CC9DA19ADFE5816689958B3DB6346A4A64B57C9EC0D3B3B6BC2606E55B35AC7CAE9D3C2AE588767CBF3EC3DAEC004BDB7DF82FA6C0DAB0F6D38DF393AC9D1CAE09D1D5A4C4A66B8BF48D9079EA0DF9490203010001", "destinationWalletAddress": "30820122300D06092A864886F70D01010105000382010F003082010A02820101009F8216980AE9DFE731A8C99656F8A3907B5B55B39FC4E3003B6A1C74A381DB5FE585010EAECCA51E90807E79B7A0F90A3D119F9B3D4ACBB27D7D638A84B9FFC2EAB1A17038F905F6A6963F1250E104FA4EBDE9DD65090306E671BC76A2D1DF00BE6ABCD8FF92EC6BBCE603577FDF66BC7A578367A84DBF65C9A2F8FFD0185BDDD8831A6981E53F4100863655E6383662B371899645C6D539BA83DE3F408E6DC8B5AABDD6B8C5D8D702E6A832DC64B327D974433C911B1B1D5F147628E8399819F53B740BE43EB90EE12661786A2196BA3BB2055888558C7EFF31E504DDEA997D2D64F43E2E7C8B48E5D2647AE418EA48CC6A9461DD10BC3730A22AA069CC0BB70203010001" }, "timeStamp": 1555058167457 } } } }
You can get
the source code from following github location.
You may like
No comments:
Post a Comment