ERC20 TOKEN DEVELOP

Environment setup

Open C:\MinGW\msys\1.0\msys.bat

1
2
3
4
5
yarn global add truffle
yarn global add ganache-cli

# download web3j and configue path
export PATH=$PATH:/C/Users/me/AppData/Local/Yarn/Data/global/node_modules/.bin:/C/Users/me/Downloads/web3j-3.5.0/bin`

Start enthereum client (or you can install geth-windows-386-1.8.13-225171a4.exe)

ganache-cli

Compile and deploy contract

Open another command prompt
Reference https://www.codeooze.com/blockchain/ethereum-truffle-hello-world/ to initialize a project

1
2
3
4
5
6
7
8
9
10
cd /d 
mkdir enthereumn-test && cd enthereumn-test
truffle init
truffle console
> web3.eth.accounts

truffle unbox tutorialtoken # init command no need to call
truffle create contract TutorialToken # write your own contract

yarn add openzeppelin-solidity

Add following code to tutorialtoken.sol

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
pragma solidity ^0.4.22;

import "openzeppelin-solidity/contracts/token/ERC20/StandardToken.sol";

contract TutorialToken is StandardToken {
string public name = "TutorialToken";
string public symbol = "TT";
uint8 public decimals = 2;
uint public INITIAL_SUPPLY = 12000;

constructor() public{
totalSupply_ = INITIAL_SUPPLY;
balances[msg.sender] = INITIAL_SUPPLY;
}
}

Compile and migrate solidity code

1
2
truffle compile # compile contracts\*.sol => build\contracts\*.json
truffle migrate # deploy contracts to ganache private network

Compile contract to java code

web3j.bat truffle generate --javaTypes D:\entherumn_env\tutorial-coin\build\contracts\TutorialToken.json -o .\java -p tutorialtoken
web3j.bat truffle generate --javaTypes D:\entherumn_env\tutorial-coin\build\contracts\SampleCrowdsaleToken.json -o .\java -p tutorialtoken
web3j.bat truffle generate --javaTypes D:\entherumn_env\tutorial-coin\build\contracts\SampleCrowdsale.json -o .\java -p tutorialtoken

Write junit to test the smart contract

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
package tutorialtoken;

import java.io.IOException;
import java.math.BigInteger;
import java.util.List;

import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Test;
import org.web3j.crypto.Credentials;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.admin.Admin;
import org.web3j.protocol.admin.methods.response.NewAccountIdentifier;
import org.web3j.protocol.admin.methods.response.PersonalUnlockAccount;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.EthAccounts;
import org.web3j.protocol.core.methods.response.EthCoinbase;
import org.web3j.protocol.core.methods.response.EthGetBalance;
import org.web3j.protocol.core.methods.response.EthGetTransactionCount;
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.Contract;

public class TutorialTokenTest {
private Web3j web3j;
private Admin admin;

private EthCoinbase coinbase;
private Credentials coinBaseCredentials;

private String contractAddressOfTT = "0xbea3c4344beb0e0681e3506d2e55315b6efe4c8b";

private static final Logger log = Logger.getLogger(TutorialTokenTest.class);

@Before
public void setup() throws IOException {
web3j = Web3j.build(new HttpService("http://localhost:8545"));
admin = Admin.build(new HttpService("http://127.0.0.1:8545"));

String coinbaseAccountPrivatekey = "0x0d10b7b76213f4b40fc95d8b3c1701213ba66bdd2a778279ad0f6165c51d73c5";
coinBaseCredentials = Credentials.create(coinbaseAccountPrivatekey);

coinbase = web3j.ethCoinbase().send();

web3j.transactionObservable().subscribe(tx -> {
log.info(String.format("New tx: id=%s, block=%s, from=%s, to=%s, value=%s", tx.getHash(), tx.getBlockHash(), tx.getFrom(), tx.getTo(), tx.getValue().intValue()));
});
}

@Test
public void showAccounts() throws IOException {
List<String> account = web3j.ethAccounts().send().getAccounts();
//account.stream().forEach(a -> log.info(a));
account.stream().forEach(System.out::println);

String coinbase = web3j.ethAccounts().send().getAccounts().get(0); // or coinbase = web3j.ethCoinbase().send();
log.info("coinbase = " + coinbase);
}

@Test
public void createAccount() throws IOException {
String password = "12345678";
NewAccountIdentifier newAccountIdentifier = admin.personalNewAccount(password).send();
String address = newAccountIdentifier.getAccountId();
log.info("New account address: " + address);
}

@Test
public void unlockAccount() throws IOException {
String password = "12345678";
NewAccountIdentifier newAccountIdentifier = admin.personalNewAccount(password).send();
String address = newAccountIdentifier.getAccountId();
log.info("New account address 22: " + address);

BigInteger unlockDuration = BigInteger.valueOf(60L);
try {
PersonalUnlockAccount personalUnlockAccount = admin.personalUnlockAccount(address, password, unlockDuration).send();
Boolean isUnlocked = personalUnlockAccount.accountUnlocked();
log.info("Account unlock " + isUnlocked);
} catch (IOException e) {
e.printStackTrace();
}
}

@Test
public void deployContract() throws Exception {
//Credentials credentials = Credentials.create("0xf2064bdf023de8d86e5e4aedc04e3e176f89d8051cedbb95332a7ea9fb99dcc4");
TutorialToken tutorialToken = TutorialToken.deploy(web3j, coinBaseCredentials, Contract.GAS_PRICE, Contract.GAS_LIMIT).send();
if (tutorialToken.getTransactionReceipt().isPresent()) {
log.info("TransactionReceipt: " + tutorialToken.getTransactionReceipt().get());
contractAddressOfTT = tutorialToken.getContractAddress();
log.info("TutorialToken contractAddress: " + contractAddressOfTT);

TutorialToken tutorialToken2 = TutorialToken.load(contractAddressOfTT, web3j, coinBaseCredentials, Contract.GAS_PRICE, Contract.GAS_LIMIT);
log.info("loaded tutorialToken: " + tutorialToken2);
log.info("tutorialToken isValid: " + tutorialToken2.isValid());
}
}

@Test
public void balanceOfTutorialToken() throws Exception {
//Credentials credentials = Credentials.create("0xf2064bdf023de8d86e5e4aedc04e3e176f89d8051cedbb95332a7ea9fb99dcc4");
//String contractAddress = "0x15b4cd705c0646c551e264c3a5f5b0ac0ad0ad09";

TutorialToken tutorialToken = TutorialToken.load(contractAddressOfTT, web3j, coinBaseCredentials, Contract.GAS_PRICE, Contract.GAS_LIMIT);
BigInteger balance = tutorialToken.balanceOf("0x231cbc2edc97071b903aed2e7d90ec792c08c57e").send();
log.info("TT balance: " + balance);
}

@Test
public void transferTutorialToken() throws Exception {
List<String> account = web3j.ethAccounts().send().getAccounts();
String account1 = account.get(0);
String account2 = account.get(1);

//String contractAddress = "0x15b4cd705c0646c551e264c3a5f5b0ac0ad0ad09";

TutorialToken tutorialToken = TutorialToken.load(contractAddressOfTT, web3j, coinBaseCredentials, Contract.GAS_PRICE, Contract.GAS_LIMIT);
TransactionReceipt receipt = tutorialToken.transfer(account2, BigInteger.valueOf(2000)).send();
log.info(String.format("New tx: id=%s, block=%s, from=%s, to=%s", receipt.getTransactionHash(), receipt.getBlockHash(), receipt.getFrom(), receipt.getTo()));

BigInteger balance = tutorialToken.balanceOf(account1).send();
log.info("TT balance: " + balance);

BigInteger balance2 = tutorialToken.balanceOf(account2).send();
log.info("balance2: " + balance2);

tutorialToken.getTransferEvents(receipt).forEach(resp -> {
log.info("TT transaction, from: " + resp.from + ", to: " + resp.to);
});
}

@Test
public void etherBalance() throws IOException {
EthGetTransactionCount transactionCount = web3j.ethGetTransactionCount(coinbase.getAddress(), DefaultBlockParameterName.LATEST).send();
Transaction transaction = Transaction.createEtherTransaction(coinbase.getAddress(), transactionCount.getTransactionCount(), BigInteger.valueOf(20_000_000_000L), BigInteger.valueOf(21_000),
coinBaseCredentials.getAddress(), BigInteger.valueOf(25_000_000_000_000_000L));
web3j.ethSendTransaction(transaction).send();
EthGetBalance balance = web3j.ethGetBalance(coinBaseCredentials.getAddress(), DefaultBlockParameterName.LATEST).send();
log.info("Ether Balance: " + balance.getBalance().longValue());
}

@Test
public void etherTransfer() throws IOException {
EthAccounts accounts = web3j.ethAccounts().send();
for (int i = 1; i < accounts.getAccounts().size(); i++) {
EthGetTransactionCount transactionCount = web3j.ethGetTransactionCount(coinbase.getAddress(), DefaultBlockParameterName.LATEST).send();
Transaction transaction = Transaction.createEtherTransaction(coinbase.getAddress(), transactionCount.getTransactionCount(), Contract.GAS_PRICE, Contract.GAS_LIMIT,
accounts.getAccounts().get(i), BigInteger.valueOf(25_000_000_000L));

EthSendTransaction response = web3j.ethSendTransaction(transaction).send();
if (response.getError() != null) {
log.error(String.format("Transaction error: %s", response.getError().getMessage()));
}

log.info(String.format("Transaction: %s, TransactionHash: %s", response.getResult(), response.getTransactionHash()));
EthGetTransactionReceipt receipt = web3j.ethGetTransactionReceipt(response.getTransactionHash()).send();
/*if (receipt.getTransactionReceipt().isPresent()) {
TransactionReceipt r = receipt.getTransactionReceipt().get();
log.info(String.format("Tx receipt: from=%s, to=%s, gas=%s, cumulativeGas=%s", r.getFrom(), r.getTo(), r.getGasUsed().intValue(), r.getCumulativeGasUsed().intValue()));
}*/

receipt.getTransactionReceipt()
.ifPresent(r -> log
.info(String.format("Tx receipt: from=%s, to=%s, gas=%s, cumulativeGas=%s", r.getFrom(), r.getTo(), r.getGasUsed().intValue(), r.getCumulativeGasUsed().intValue())));

EthGetBalance balance = web3j.ethGetBalance(accounts.getAccounts().get(i), DefaultBlockParameterName.LATEST).send();
log.info(String.format("Ether Balance: address=%s, amount=%s", accounts.getAccounts().get(i), balance.getBalance().longValue()));
}
}
}

Request ether from Rinkeby

https://gist.github.com/cryptogoth/10a98e8078cfd69f7ca892ddbdcf26bc

1
2
3
4
windows 1: geth --datadir=./.rinkeby attach ipc:\\.\pipe\geth.ipc console
windows 2: geth attach ipc:\\.\pipe\geth.ipc
> personal.newAccount("notmyrealpassword")
> eth.getBalance(eth.coinbase)

Go to https://www.rinkeby.io/#faucet and copy your post
Or
http://rinkeby-faucet.com/
https://rinkeby.etherscan.io/balancecheck-tool
https://ethereum.stackexchange.com/questions/34718/how-do-i-buy-tokens-on-the-rinkeby-test-environment

Register a infura.io account to get a access-api through https:/infura.io/register

endpoint: https://rinkeby.infura.io/v3/your-api
note that rinkeby does not support following method

1
2
3
web3j.transactionObservable().subscribe(tx -> {
log.info(String.format("New tx: id=%s, block=%s, from=%s, to=%s, value=%s", tx.getHash(), tx.getBlockHash(), tx.getFrom(), tx.getTo(), tx.getValue().intValue()));
});

Reference

https://stevenocean.github.io/2018/04/06/web3j-ethereum-token.html
https://dzone.com/articles/intro-to-blockchain-with-ethereum-web3j-and-spring
https://www.codeooze.com/categories/blockchain/

https://truffleframework.com/tutorials/pet-shop
https://truffleframework.com/docs/truffle/testing/writing-tests-in-javascript
https://truffleframework.com/tutorials/robust-smart-contracts-with-openzeppelin
https://metamask.io
https://medium.com/@dmihal/create-an-erc20-token-using-zeppelin-ethpm-fc99f794d153

https://github.com/eugenp/tutorials/tree/master/ethereum
https://docs.web3j.io/getting_started.html#transactions
https://piotrminkowski.wordpress.com/2018/06/22/introduction-to-blockchain-with-java-using-ethereum-web3j-and-spring-boot/
https://github.com/piomin/sample-spring-blockchain-contract

https://cryptozombies.io

https://theethereum.wiki/w/index.php/ERC20_Token_Standard

crowdsale

https://github.com/TokenMarketNet/ico
https://medium.com/@VladimirTikhomirov/how-its-made-crowdsale-contract-1120b487cc4a
https://www.ethereum.org/crowdsale
https://blog.zeppelin.solutions/how-to-create-token-and-initial-coin-offering-contracts-using-truffle-openzeppelin-1b7a5dae99b6
https://github.com/OpenZeppelin/openzeppelin-solidity/blob/master/contracts/examples/SampleCrowdsale.sol