Smart Contract Interface - Wraecca/etherspace-java GitHub Wiki
Etherspace turns a Smart Contract into a Java/Kotlin interface by annotations.
All the methods in the interface need to be annotated either by @cc.etherspace.Call or @cc.etherspace.Send.
The method name is the function name of the underlying Smart Contract function. (or you can override it with @Call.funcationName)
public interface Greeter {
@Send(functionName = "newGreeting")
TransactionHash anotherNewGreeting(String greeting) throws IOException;
}Method annotated with @Call represent it's a constant(or View, Pure) function.
The type and order of input/output parameters must match those defined in the Smart Contract function.
Corresponding Solidity/Java Types are defined in Solidity Data Types.
public interface Greeter {
@Call
String greet() throws IOException;
}Method annotated with @Send represent it's a function with transaction.
The type and order of input parameters must match those defined in the Smart Contract function.
The output parameter can be either TransactionHash, TransactionReceipt or String(Transaction Hash).
-
cc.etherspace.TransactionHashReturns the transaction hash without waiting for the block completed. This method will return right after the node accepted the transaction. (but not yet completed)
Calling
TransactionHash.requestTransactionReceipt()returns the transaction receipt. (This is a blocking call) The result will be decorated byCallAdapterinEtherSpace. Ex:CoroutineCallAdapterwill returnDeferred<TransactionReceipt>, andCompletableFutureCallAdapterwill returnCompletableFuture<TransactionReceipt>. -
cc.etherspace.TransactionReceiptReturns the transaction receipt of this transaction. This method will wait for the block completed.
-
String(Transaction Hash)Returns the transaction hash without waiting for the block completed. This method will return right after the node accepted the transaction. (but not yet completed)
// Java
public interface Greeter {
@Send
String newGreeting(String greeting) throws IOException;
@Send(functionName = "newGreeting")
TransactionReceipt newGreetingWithReceipt(String greeting) throws IOException;
}Adding a @cc.etherspace.Gas annotation to SmartContract interface or method to override the default gas settings.
@Gas(gas = "8000000", gasPrice = "22000000000")
public interface Greeter {
@Send
@Gas(gas = "8000000", gasPrice = "22000000000")
TransactionReceipt newGreeting(String greeting) throws IOException;
}An Options can be appended to the parameter list in Smart Contract methods.
Properties in Options will override predefined settings in runtime. (Gas, Credentials, ...)
public interface Greeter {
@Call
String greet() throws IOException;
}
EtherSpace etherSpace = new EtherSpace.Builder()
.provider("https://rinkeby.infura.io/") // Or your local node
.build();
Greeter greeter = etherSpace.create(SMART_CONTRACT_ADDRESS, Greeter.class);
Options options = new Options(BigInteger.ZERO, BigInteger.valueOf(8_000_000), BigInteger.valueOf(22_000_000_000L), new Credentials(YOUR_PRIVATE_KEY_OR_WALLET));
TransactionReceipt receipt = greeter.newGreeting("Hello World", options);For types in Solidity, below is a list of their corresponding Java Types:
| Solidity Type | Java Type |
|---|---|
| string | java.lang.String |
| bool | java.lang.Boolean |
| int16 | java.lang.Short |
| int32 | java.lang.Integer |
| int64 | java.lang.Long |
| int / int256 | java.math.BigInteger |
| uint16 | unsigned.Ushort |
| uint32 | unsigned.Uint |
| uint64 | unsigned.Ulong |
| uint / uint256 | cc.etherspace.SolUint256 |
| int8 ~ int248 (excluding int16,int32,int64) |
cc.etherspace.SolInt8 ~ cc.etherspace.SolInt248
|
| uint8 ~ uint248 (excluding uint16,uint32,uint64) |
cc.etherspace.SolUint8 ~ cc.etherspace.SolUint248
|
| address | cc.etherspace.SolAddress |
| byte / byte1 | java.lang.Byte |
| byte2 ~ byte32 |
cc.etherspace.SolBytes2 ~ cc.etherspace.SolBytes32
|
| bytes | byte[] |
| dynamic array |
java.util.List<T> (T must be one of the Java Types listed above.) |
| fixed size array |
cc.etherspace.SolArray1<T> ~ cc.etherspace.SolArray32<T> (T must be one of the Java Types listed above.) |
Functions with multiple return values should use Pair, Triple, Tuples as the values container.
| Number of Returns | Java Type |
|---|---|
| 2 | kotlin.Pair |
| 3 | kotlin.Triple |
| 4 | cc.etherspace.Tuple4 |
| 5 | cc.etherspace.Tuple5 |
| 6 | cc.etherspace.Tuple6 |
| 7 | cc.etherspace.Tuple7 |
| 8 | cc.etherspace.Tuple8 |
| 9 | cc.etherspace.Tuple9 |
| 10 | cc.etherspace.Tuple10 |
For example, a Smart Contract function with two return values:
// Kotlin
interface Greeter {
@Throws(IOException::class)
@Call
fun greet(): Pair<String, String>
}// Java
public interface Greeter {
@Call
Pair<String, String> greet() throws IOException;
}contract greeter {
function twoDimensionalArray(uint[5][] array) constant returns (uint) {
...
}
}// Kotlin
interface Greeter {
@Throws(IOException::class)
@Call
fun twoDimensionalArray(array: List<SolArray5<SolUint256>>): SolUint256
}// Java
public interface Greeter {
@Call
SolUint256 twoDimensionalArray(List<SolArray5<SolUint256>> array) throws IOException;
}Events defined in Smart Contract need be declared as classes in Java/Kotlin.
For example, we have an Modified event defined in Smart Contract:
event Modified(
string indexed oldGreetingIdx, string indexed newGreetingIdx,
string oldGreeting, string newGreeting);The corresponding Modified event is defined in Kotlin/Java below.
// Kotlin
data class Modified @EventConstructor constructor(
@Indexed(String::class) val oldGreetingIdx: SolBytes32,
@Indexed(String::class) val newGreetingIdx: SolBytes32,
val oldGreeting: String,
val newGreeting: String)
// Java
class Modified {
private SolBytes32 oldGreetingIdx;
private SolBytes32 newGreetingIdx;
private String oldGreeting;
private String newGreeting;
@EventConstructor
public Modified(@Indexed(String.class) SolBytes32 oldGreetingIdx, @Indexed(String.class) SolBytes32 newGreetingIdx, String oldGreeting, String newGreeting) {
this.oldGreetingIdx = oldGreetingIdx;
this.newGreetingIdx = newGreetingIdx;
this.oldGreeting = oldGreeting;
this.newGreeting = newGreeting;
}
// getters/setters ... etc
}One of the public constructors of the event class needs to be annotated with @cc.etherspace.EventConstructor and contains the same type and order of parameters.
All the indexed parameters need to be annotated with @cc.etherspace.Indexed with the Type defined in Smart Contract.
For all array types (string and array) in Solidity, the parameters will be @cc.etherspace.SolBytes32 instead. (See Events in Solidity document)
After TransactionReceipt received, you can list the received events from transaction logs:
// Kotlin
val receipt = greeter.newGreeting("Hello World")
val events = receipt.listEvents(Modified::class.java)// Java
TransactionReceipt receipt = greeter.newGreeting("Hello World");
List<Event<Modified>> events = receipt.listEvents(Modified.class);