Smart Contract Interface - Wraecca/etherspace-java GitHub Wiki

Etherspace turns a Smart Contract into a Java/Kotlin interface by annotations.

Annotations

@Call / @Send

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;
}

@Call

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;
}

@Send

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 by CallAdapter in EtherSpace. Ex: CoroutineCallAdapter will return Deferred<TransactionReceipt>, and CompletableFutureCallAdapter will return CompletableFuture<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;
}

@Gas

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;
}

Options

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);

Solidity Data Types

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.)

Solidity Multiple Return Values

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;
}

Two dimensional array

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

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);
⚠️ **GitHub.com Fallback** ⚠️