Skip to content

Commit

Permalink
Support new CIP37 address (#18)
Browse files Browse the repository at this point in the history
* supplyInfo add new field totalCirculate

* refactor Address type

* refactor address type from String to Address

* update readme and changelog
  • Loading branch information
Pana authored Jan 29, 2021
1 parent 9cb5ef5 commit 8037936
Show file tree
Hide file tree
Showing 40 changed files with 999 additions and 540 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ gradle-app.setting
.settings/
bin
.idea
todo.md
docs/cfx-address.md
docs/tmp.md
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
### 1.0.0

1. Class Address support new CIP37 address
2. Where ever need an address, you should pass an `Address` instance, String address will not work
3. `getStatus` return a new field `networkId`
4. `getSupplyInfo` return a new field `totalCirculating`
5. `Address.validate` has been moved to `AddressType.validateHexAddress`
6. ERC20Call, ERC20Executor, ERC777Call, ERC777Executor has been removed, you can use the new ERC20, ERC777
7. AccountManager's constructor add a new parameter `networkId`


### 0.9.0
Expand All @@ -6,4 +15,5 @@
2. Add new RPC methods: cfx_getDepositList, cfx_getVoteList, cfx_getSupplyInfo
3. Add support for InternalContracts
4. Merge ERC20, ERC777 call and executor
5. Update default gasPrice to 1 Drip
5. Update default gasPrice to 1 Drip
6. Update RawTransaction default chainId to 1029(mainnet)
58 changes: 32 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,27 @@ The Conflux Java SDK allows any Java client to interact with a local or remote C
## Docs

* [API](https://conflux-chain.github.io/java-conflux-sdk/index.html)
* [changelog](./CHANGELOG.md)

## Conflux Address
Conflux import a new base32 address at [CIP37](https://github.com/Conflux-Chain/CIPs/blob/master/CIPs/cip-37.md).
From `conflux-rust` v1.1.1, and `java-conflux-sdk` 1.0, the new CIP37 will be supported.
The `Address` class has added support for CIP37 address.

```java
int testNetId = 1; // mainnet is 1029
Address a = new Address("0x13d2bA4eD43542e7c54fbB6c5fCCb9f269C1f94C", testNetId);
Address b = new Address("cfxtest:aak7fsws4u4yf38fk870218p1h3gxut3ku00u1k1da");

a.getAddress(); // "cfxtest:aak7fsws4u4yf38fk870218p1h3gxut3ku00u1k1da"
a.getHexAddress(); // "0x13d2bA4eD43542e7c54fbB6c5fCCb9f269C1f94C"
a.getVerboseAddress(); // "NET1921:TYPE.USER:AAR8JZYBZV0FHZREAV49SYXNZUT8S0JT1AT8UHK7M3"
a.getNetworkId(); // 1
a.getType(); // user
```

For complete CIP37 address updates [check here](./docs/cfx-address.md)
Note: `java-conflux-sdk` `v1.0` is an incompatible version, it only work with `conflux-rust` `1.1.1 or above`.

## Manage Accounts
Use `AccountManager` to manage accounts at local machine.
Expand Down Expand Up @@ -35,11 +55,11 @@ public class App {

- Sign a transaction with unlocked account:
```java
AccountManager.signTransaction(RawTransaction tx, String address)
AccountManager.signTransaction(RawTransaction tx, Address address)
```
- Sign a transaction with passphrase for locked account:
```java
AccountManager.signTransaction(RawTransaction tx, String address, String password)
AccountManager.signTransaction(RawTransaction tx, Address address, String password)
```


Expand Down Expand Up @@ -72,7 +92,7 @@ To send a transaction, first you need to build a transaction and sign the transa
BigInteger value = new BigInteger("1000", 16);
TransactionBuilder txBuilder = new TransactionBuilder("0x-the-sender-address");
txBuilder.withChainId(1);
txBuilder.withTo("0x13d2bA4eD43542e7c54fbB6c5fCCb9f269C1f94C");
txBuilder.withTo(new Address("cfxtest:aak7fsws4u4yf38fk870218p1h3gxut3ku00u1k1da"));
txBuilder.withValue(value);
RawTransaction rawTx = txBuilder.build(cfx);
// get account from accountManager, `account.send` will sign the tx and send it to blockchain
Expand All @@ -88,22 +108,7 @@ If you just want to transfer some CFX, there is a simpler method `account.transf
Option opt = new Option();
opt.withChainId(1);
account.waitForNonceUpdated();
String result = account.transfer(opt, "0x13d2bA4eD43542e7c54fbB6c5fCCb9f269C1f94C", value);
```



## Conflux Address
There are three types of address in Conflux:
- User address: starts with `0x1`.
- Contract address: starts with `0x8`.
- Internal contract: starts with `0x0`.

Conflux Java SDK provides some utilities to validate or format address, please refer to `Address` and `AddressType` for more details.

The underlying library `Web3j` also provides API to convert address to a checksumed format.
```java
Keys.toChecksumAddress(String address)
String result = account.transfer(opt, new Address("0x13d2bA4eD43542e7c54fbB6c5fCCb9f269C1f94C"), value);
```

## Websocket and PubSub
Expand Down Expand Up @@ -136,16 +141,16 @@ To simple call a contract method you can use the ContractCall class
package conflux.sdk.examples;
import conflux.web3j.contract.ContractCall;

import org.web3j.abi.datatypes.Address;
import conflux.web3j.types.Address;
import conflux.web3j.contract.abi.DecodeUtil;
import org.web3j.abi.datatypes.generated.Uint256;

public class App {
public static void main(String[] args) throws Exception {
ContractCall contract = new ContractCall(cfx, "0x824df34537b198d9955c01c4e5a2a68733707b4f");
ContractCall contract = new ContractCall(cfx, new Address("0x824df34537b198d9955c01c4e5a2a68733707b4f", 1));
// passing method name and parameter to `contract.call`
// note: parameters should use web3j.abi.datatypes type
String amount = contract.call("balanceOf", new Address("0x1386B4185A223EF49592233b69291bbe5a80C527")).sendAndGet();
String amount = contract.call("balanceOf", new Address("0x1386B4185A223EF49592233b69291bbe5a80C527", 1).getABIAddress()).sendAndGet();
BigInteger balance = DecodeUtil.decode(amount, Uint256.class);
System.out.print("account balance: ");
System.out.println(balance);
Expand All @@ -163,21 +168,22 @@ package conflux.sdk.examples;
import conflux.web3j.Account;
import conflux.web3j.Account.Option;

import org.web3j.abi.datatypes.Address;
import conflux.web3j.types.Address;
import org.web3j.abi.datatypes.generated.Uint256;

public class App {
public static void main(String[] args) throws Exception {
String privateKey = "0xxxxxx";
String contractAddress = "0xxxxx";
String recipient = "0xxxx";
int netId = 1;
Address contractAddress = new Address("0xxxxx", netId);
Address recipient = new Address("0xxxx", netId);
BigInteger amount = 100;

// create account, then call contract's method
Account account = Account.create(cfx, privateKey);
Option opt = new Option();
// build transaction option info: nonce, gas, gasPrice and etc
String txHash = account.call(option, contractAddress, "transfer", new Address(recipient), new Uint256(amount));
String txHash = account.call(option, contractAddress, "transfer", recipient.getABIAddress(), new Uint256(amount));
System.out.println("tx hash: " + txHash);
}
}
Expand Down
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ dependencies {

// Use JUnit test framework
testImplementation 'junit:junit:4.12'

testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'

compile 'org.web3j:core:4.6.3'
}
2 changes: 2 additions & 0 deletions docs/cfx-address.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
CIP37 address
===
55 changes: 27 additions & 28 deletions src/main/java/conflux/web3j/Account.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.Arrays;
import java.util.Collections;

import conflux.web3j.types.*;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
Expand All @@ -17,48 +18,42 @@

import conflux.web3j.request.Call;
import conflux.web3j.response.UsedGasAndCollateral;
import conflux.web3j.types.AddressType;
import conflux.web3j.types.RawTransaction;
import conflux.web3j.types.SendTransactionError;
import conflux.web3j.types.SendTransactionResult;
import conflux.web3j.types.TransactionBuilder;

public class Account {

private Cfx cfx;
private String address;
private Address address;
private BigInteger nonce;

private AccountManager am;
private ECKeyPair ecKeyPair;

private Account(Cfx cfx, String address) {
private Account(Cfx cfx, Address address) {
this.cfx = cfx;
this.address = address;
this.nonce = cfx.getNonce(address).sendAndGet();
this.nonce = cfx.getNonce(this.address).sendAndGet();
}

public static Account unlock(Cfx cfx, AccountManager am, String address, String password) throws Exception {
public static Account unlock(Cfx cfx, AccountManager am, Address address, String password) throws Exception {
return unlock(cfx, am, address, password, Duration.ZERO);
}

public static Account unlock(Cfx cfx, AccountManager am, String address, String password, Duration unlockTimeout) throws Exception {
public static Account unlock(Cfx cfx, AccountManager am, Address address, String password, Duration unlockTimeout) throws Exception {
if (!am.unlock(address, password, unlockTimeout)) {
throw new Exception("account not found in keystore");
}

Account account = new Account(cfx, address);
account.am = am;

return account;
}

public static Account create(Cfx cfx, String privateKey) {
public static Account create(Cfx cfx, String privateKey) throws AddressException {
Credentials credentials = Credentials.create(privateKey);

Account account = new Account(cfx, AddressType.User.normalize(credentials.getAddress()));
String hexAddress = AddressType.User.normalize(credentials.getAddress());
Address address = new Address(hexAddress, cfx.getIntNetworkId());
Account account = new Account(cfx, address);
account.ecKeyPair = credentials.getEcKeyPair();

return account;
}

Expand All @@ -67,9 +62,13 @@ public Cfx getCfx() {
return cfx;
}

public String getAddress() {
public Address getAddress() {
return address;
}

public String getHexAddress() {
return this.address.getHexAddress();
}

public BigInteger getNonce() {
return nonce;
Expand All @@ -81,7 +80,7 @@ public void setNonce(BigInteger nonce) {

public String sign(RawTransaction tx) throws Exception {
return this.ecKeyPair == null
? this.am.signTransaction(tx, this.address)
? this.am.signTransaction(tx, this.getAddress())
: tx.sign(this.ecKeyPair);
}

Expand Down Expand Up @@ -127,11 +126,11 @@ public SendTransactionResult send(RawTransaction tx) throws Exception {
return this.send(signedTx);
}

public String transfer(String to, BigInteger value) throws Exception {
public String transfer(Address to, BigInteger value) throws Exception {
return this.transfer(new Option(), to, value);
}

public String transfer(Option option, String to, BigInteger value) throws Exception {
public String transfer(Option option, Address to, BigInteger value) throws Exception {
option.apply(this.cfx);
RawTransaction tx = RawTransaction.transfer(this.nonce, to, value, option.epochHeight);
option.updatePriceAndChainId(tx);
Expand All @@ -144,17 +143,17 @@ public String deploy(String bytecodes) throws Exception {
}

public String deploy(Option option, String bytecodes) throws Exception {
option.apply(this.cfx, this.address, "", bytecodes);
option.apply(this.cfx, this.getAddress(), null, bytecodes);
RawTransaction tx = RawTransaction.deploy(this.nonce, option.gasLimit, option.value, option.storageLimit, option.epochHeight, bytecodes);
option.updatePriceAndChainId(tx);
return this.mustSend(tx);
}

public String call(String contract, String method, Type<?>... inputs) throws Exception {
public String call(Address contract, String method, Type<?>... inputs) throws Exception {
return this.call(new Option(), contract, method, inputs);
}

public String call(Option option, String contract, String method, Type<?>... inputs) throws Exception {
public String call(Option option, Address contract, String method, Type<?>... inputs) throws Exception {
String data = "";

if (!Strings.isEmpty(method)) {
Expand All @@ -165,12 +164,12 @@ public String call(Option option, String contract, String method, Type<?>... inp
return this.call(option, contract, data);
}

public String call(String contract, String data) throws Exception {
public String call(Address contract, String data) throws Exception {
return this.call(new Option(), contract, data);
}

public String call(Option option, String contract, String data) throws Exception {
option.apply(this.cfx, this.address, contract, data);
public String call(Option option, Address contract, String data) throws Exception {
option.apply(this.cfx, this.getAddress(), contract, data);
RawTransaction tx = RawTransaction.create(this.nonce, option.gasLimit, contract, option.value, option.storageLimit, option.epochHeight, data);
option.updatePriceAndChainId(tx);
return this.mustSend(tx);
Expand Down Expand Up @@ -260,7 +259,7 @@ private void apply(Cfx cfx) {
}
}

private void apply(Cfx cfx, String from, String to, String data) {
private void apply(Cfx cfx, Address from, Address to, String data) {
if (this.epochHeight == null) {
this.epochHeight = cfx.getEpochNumber().sendAndGet();
}
Expand All @@ -271,11 +270,11 @@ private void apply(Cfx cfx, String from, String to, String data) {

Call call = new Call();

if (!Strings.isEmpty(from)) {
if (from != null) {
call.setFrom(from);
}

if (!Strings.isEmpty(to)) {
if (to != null) {
call.setTo(to);
}

Expand Down
Loading

0 comments on commit 8037936

Please sign in to comment.