pragma solidity ^0.4.21;
contract TransactionFee {
// (1)
uint public fee;
// (2)
address public receiver;
// (3)
mapping (address => uint) public balances;
// (4)
event Sent(address from, address to, uint amount, bool sent);
// (5)
constructor(address _receiver, uint _fee) public {
receiver = _receiver;
fee = _fee;
}
// (6)
function getReceiverBalance() public view returns(uint) {
return receiver.balance;
}
// (7)
function sendTrx() public payable {
uint value = msg.value * fee / 100;
bool sent = receiver.send(value);
balances[receiver] += (value);
emit Sent(msg.sender, receiver, value, sent);
}
}
一旦我们创建了一个合约,我们必须编译并且创建源代码,这样我们才能够在我们的应用中部署合约并调用它的函数。有关 Solidity 编译器的相关信息,可以查阅官方网站:https://remix.ethereum.org。
- 编译合约并创建源代码
Solidity 为编译器提供了最新的 Docker 镜像,正式版本标记为stable,来自于开发分支的不稳定版本标记为nightly。但是,Docker 镜像只包含编译器可执行文件,因此我们必须将 Solidity 合约输入文件进行持久化卷挂载。假设这些文件在我们运行 Docker 容器机器的目录 /home/docker 下,我们可以使用以下命令进行编译。这个命令创建了两个文件:一个二进制文件 .bin,是 EVM 可以解释的智能合约代码,另外一个是应用程序二进制接口文件.abi,里面定义了智能合约方法。
$ docker run --rm -v /home/docker:/build ethereum/solc:stable /build/TransactionFee.sol --bin --abi --optimize -o /build
编译输出文件在容器的/build目录下,并且持久化存储在/home/docker目录下。在编译结束后,该容器被删除,因为现在不需要它。我们可以使用 web3j 库来从编译后的智能合约文件中创建源代码。web3j 的可执行文件在${WEB3J_HOME}/bin目录下,在创建源代码时,需要指定.bin 和 .abi文件的路径,并且设定目标包名和目录。
$ web3j solidity generate /build/transactionfee.bin /build/transactionfee.abi -p pl.piomin.services.contract.model -o src/main/java/
Web3j 可执行文件在给定的包名下创建了 Java 源文件,该类名为 Solidity 智能合约名,下面是我们创建出来的源代码。
public class Transactionfee extends Contract {
private static final String BINARY = "608060405234801561..."
public static final String FUNC_GETRECEIVERBALANCE = "getReceiverBalance";
public static final String FUNC_BALANCES = "balances";
public static final String FUNC_SENDTRX = "sendTrx";
public static final String FUNC_FEE = "fee";
public static final String FUNC_RECEIVER = "receiver";
// ...
protected Transactionfee(String contractAddress, Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit) {
super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit);
}
public RemoteCall getReceiverBalance() {
final Function function = new Function(FUNC_GETRECEIVERBALANCE,
Arrays.asList(),
Arrays.asList(new TypeReference() {}));
return executeRemoteCallSingleValueReturn(function, BigInteger.class);
}
public RemoteCall balances(String param0) {
final Function function = new Function(FUNC_BALANCES,
Arrays.asList(new org.web3j.abi.datatypes.Address(param0)),
Arrays.asList(new TypeReference() {}));
return executeRemoteCallSingleValueReturn(function, BigInteger.class);
}
public RemoteCall sendTrx(BigInteger weiValue) {
final Function function = new Function(
FUNC_SENDTRX,
Arrays.asList(),
Collections.emptyList());
return executeRemoteCallTransaction(function, weiValue);
}
public RemoteCall fee() {
final Function function = new Function(FUNC_FEE,
Arrays.asList(),
Arrays.asList(new TypeReference() {}));
return executeRemoteCallSingleValueReturn(function, BigInteger.class);
}
public RemoteCall receiver() {
final Function function = new Function(FUNC_RECEIVER,
Arrays.asList(),
Arrays.asList(new TypeReference
() {}));
return executeRemoteCallSingleValueReturn(function, String.class);
}
public static RemoteCall deploy(Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit, String _receiver, BigInteger _fee) {
String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(_receiver),
new org.web3j.abi.datatypes.generated.Uint256(_fee)));
return deployRemoteCall(Transactionfee.class, web3j, credentials, gasPrice, gasLimit, BINARY, encodedConstructor);
}
public static RemoteCall deploy(Web3j web3j, TransactionManager transactionManager, BigInteger gasPrice, BigInteger gasLimit, String _receiver, BigInteger _fee) {
String encodedConstructor = FunctionEncoder.encodeConstructor(Arrays.asList(new org.web3j.abi.datatypes.Address(_receiver),
new org.web3j.abi.datatypes.generated.Uint256(_fee)));
return deployRemoteCall(Transactionfee.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, encodedConstructor);
}