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.TransactionHash
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)
Calling
TransactionHash.requestTransactionReceipt()
returns the transaction receipt. (This is a blocking call) The result will be decorated byCallAdapter
inEtherSpace
. Ex:CoroutineCallAdapter
will returnDeferred<TransactionReceipt>
, andCompletableFutureCallAdapter
will returnCompletableFuture<TransactionReceipt>
. -
cc.etherspace.TransactionReceipt
Returns 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);