Contract to Contract
Java smart contracts are able to interact with other Java contracts on the Aion network. This page details how that is achieved.
Contract-to-contract calls still follow the same rules as regular contract calls. See Java Contract Fundamentals section for more information.
Example Contracts
You can use these contracts as templates. The Caller
contract makes a call to the Returner
contract.
Returner
This is the contract that will be called by the Caller
contract. If you want to test these contracts out, deploy this one first to get the contract address.
package aion;
import avm.Address;
import avm.Blockchain;
import org.aion.avm.tooling.abi.Callable;
import org.aion.avm.userlib.abi.ABIDecoder;
public class ReturnerExample {
@Callable
public static String getString(int index) {
String[] myStr = { "Hello AVM!", "AVM is great" };
return myStr[index];
}
}
Caller
Make sure to supply the address of the contract you want to call as a deployment argument. Supplying the contract address as a hardcoded variable within a contract is more expensive and less efficient​.
package aion;
import avm.Address;
import avm.Blockchain;
import avm.Result;
import org.aion.avm.tooling.abi.Callable;
import org.aion.avm.userlib.abi.ABIDecoder;
import org.aion.avm.userlib.abi.ABIEncoder;
import org.aion.avm.userlib.abi.ABIStreamingEncoder;
import java.math.BigInteger;
public class ContractInteractionCaller {
private static Address returnerContractAddress;
static {
ABIDecoder decoder = new ABIDecoder(Blockchain.getData());
returnerContractAddress = decoder.decodeOneAddress(); //Set the contract address that you want to call
}
@Callable
public static Address getReturnerContractAddress() {
return returnerContractAddress;
}
@Callable
public static String getStringInAnotherContract(int index) {
ABIStreamingEncoder encoder = new ABIStreamingEncoder();
byte[] data = encoder.encodeOneString("getString")
.encodeOneInteger(index)
.toBytes();
Result getString = Blockchain.call(returnerContractAddress, BigInteger.ZERO, data, Blockchain.getRemainingEnergy());
ABIDecoder decoder = new ABIDecoder(getString.getReturnData());
String myString = decoder.decodeOneString();
return myString;
}
}
Blockchain Call
To call a method in another Java contract, you can use Blockchain.call() method, and pass in the target contract address
, value
to transfer, data
to pass and the max energy
the invoked contract can use.
To get the right data
you want to pass, you will need an ABI StreamingEncoder.
Use it to encode the method
name as a String
first and then the arguments
corresponding to their types in order.
byte[] data = encoder.encodeOneString("getString").encodeOneInteger(index).toBytes();
Now you get everything you need to make a contract call.
If you are expecting some return data, you must create a Result
object.
AVM Result
The AVM Result
object represents a cross-call invocation result. To create a Result
instance for the contract method call:
Result getString = Blockchain.call(calleeContractAddress, BigInteger.ZERO, data, Blockchain.getRemainingEnergy());
Then, you must create an ABIDecoder object and use Result.getReturnData()
to get the data returned by the invoked call. See AVM ABIDecoder section for more details.
ABIDecoder decoder = new ABIDecoder(getString.getReturnData());
Once this has been created, you can decode the return data
according to the return data type.
String myString = decoder.decodeOneString();