ChainMaker Solidity语言版本智能合约完全兼容EVM,更多长安链证书与EVM地址的转换详情可参见EVM地址说明。
在“证书管理”界面申请证书后,可根据获得的用户证书文件user_sign.crt获取该用户的EVM地址,代码示例如下:
import(
"encoding/hex"
"encoding/pem"
"fmt"
"io/ioutil"
"chainmaker.org/chainmaker-go/common/crypto/x509"
"chainmaker.org/chainmaker-go/common/evmutils"
"github.com/ethereum/go-ethereum/accounts/abi"
)
func MakeAddrAndSkiFromCrtFilePath(){
crtFilePath:="./user_sign.crt"
crtBytes,err:=ioutil.ReadFile(crtFilePath)
if err!=nil{
fmt.Printf("fail to read the crt file:%v",err)
}
blockCrt,_:=pem.Decode(crtBytes)
crt,err:=x509.ParseCertificate(blockCrt.Bytes)
if err!=nil{
fmt.Printf("fail to parse certificate:%v",err)
}
ski:=hex.EncodeToString(crt.SubjectKeyId)
addrInt,err:=evmutils.MakeAddressFromHex(ski)
if err!=nil{
fmt.Printf("fail to make address from hex:%v",err)
}
//证书SKI
fmt.Printf("clientAddrSki:%sn",ski)
//EVM地址(十进制)
fmt.Printf("clientAddrInt:%sn",addrInt.String())
//EVM地址
fmt.Printf("clientEthAddr:0x%xn",addrInt.AsStringKey())
}
成功运行可以查看到如下图输出:
ABI编码示例
ChainMake Solidity语言版本智能合约完全兼容EVM,更多ABI编码的详情可参见Solidity官方文档。
合约初始化
以Token合约为例,对合约初始化参数进行ABI编码。代码示例如下:
import(
"encoding/hex"
"fmt"
"io/ioutil"
"math/big"
"strings"
"chainmaker.org/chainmaker-go/common/evmutils"
"github.com/ethereum/go-ethereum/accounts/abi"
)
const(
//编译合约后获取的abi文件的路径
tokenABIPath="./testdata/token-evm-demo/token.abi"
//合约安装时调用constructor,调用方法设为空字符串
function=""
//入参1:发行EVM地址,可根据用户证书转换取得
clientAddr="0x89f4090e315621696d6936453661ec4b9795ad27"
)
func testUserContractTokenEVMConstructor(){
abiJson,err:=ioutil.ReadFile(tokenABIPath)
if err!=nil{
fmt.Printf("fail to read the abi file:%v",err)
}
myAbi,err:=abi.JSON(strings.NewReader(string(abiJson)))
if err!=nil{
fmt.Printf("fail to get abi object:%v",err)
}
addr:=evmutils.BigToAddress(evmutils.FromHexString(clientAddr[2:]))
dataByte,err:=myAbi.Pack(function,addr)
if err!=nil{
fmt.Printf("fail to pack contract input:%v",err)
}
data:=hex.EncodeToString(dataByte)
pairs:=map[string]string{
"data":data,
}
//编码后的参数
fmt.Printf("FuncParam%vn",pairs)
}
输出结果如下:
FuncParam map[data:00000000000000000000000089f4090e315621696d6936453661ec4b9795ad27]
通过TBaaS控制台安装合约并填写对应初始化参数:
key取值:data
value取值:00000000000000000000000089f4090e315621696d6936453661ec4b9795ad27
合约调用
以Token合约为例,对transfer函数的函数名及调用参数进行ABI编码。代码示例如下:
import(
"encoding/hex"
"fmt"
"io/ioutil"
"math/big"
"strings"
"chainmaker.org/chainmaker-go/common/evmutils"
"github.com/ethereum/go-ethereum/accounts/abi"
)
const(
//编译合约后获取的abi文件的路径
tokenABIPath="./testdata/token-evm-demo/token.abi"
//调用方法
function="transfer"
//入参1:转账EVM地址,可根据用户证书转换取得
clientAddr="0xa55f1e0cb68b0cc589906078237094bdb9715bfd"
//入参2:转账金额
amount=200
)
func testUserContractTokenEVMTransfer(){
abiJson,err:=ioutil.ReadFile(tokenABIPath)
if err!=nil{
fmt.Printf("fail to read the abi file:%v",err)
}
myAbi,err:=abi.JSON(strings.NewReader(string(abiJson)))
if err!=nil{
fmt.Printf("fail to get abi object:%v",err)
}
addr:=evmutils.BigToAddress(evmutils.FromHexString(clientAddr[2:]))
dataByte,err:=myAbi.Pack(function,addr,big.NewInt(amount))
if err!=nil{
fmt.Printf("fail to pack contract input:%v",err)
}
data:=hex.EncodeToString(dataByte)
method:=data[0:8]
pairs:=map[string]string{
"data":data,
}
//编码后的函数名
fmt.Printf("FuncName:%sn",method)
//编码后的参数
fmt.Printf("FuncParam%vn",pairs)
}
输出结果如下:
FuncName:a9059cbb
FuncParam map[data:a9059cbb000000000000000000000000a55f1e0cb68b0cc589906078237094bdb9715bfd00000000000000000000000000000000000000000000000000000000000000c8]
长安链SDK调用示例
将ABI编码后的函数名及调用参数分别作为method与params,代码示例如下:
method:="a9059cbb"
params:=map[string]string{
"data":"a9059cbb000000000000000000000000a55f1e0cb68b0cc589906078237094bdb9715bfd00000000000000000000000000000000000000000000000000000000000000c8",
}
resp,err:=client.InvokeContract("fact",method,"",params,-1,true)
if err!=nil{
fmt.Printf("fail to invoke contract:%v",err)
}
云API调用示例
将ABI编码后的函数名及调用参数分别填入FuncName与FuncParam字段,代码示例如下:
action_params={
"ClusterId":"chainmaker-txtxtxtxtx",
"ChainId":"chain_txtxt",
"ContractName":"fact",
"FuncName":"a9059cbb",
"FuncParam":"{"data":"a9059cbb000000000000000000000000a55f1e0cb68b0cc589906078237094bdb9715bfd00000000000000000000000000000000000000000000000000000000000000c8"}",
"AsyncFlag":0,
"Action":"InvokeChainMakerContract",
"Version":"2018-04-16",
"Region":"ap-beijing"
}
#实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数
params=json.dumps(action_params)
req=models.InvokeChainMakerContractRequest()
#调用InvokeChainMakerContractRequest的from_json_string方法,使用params初始化req对象
req.from_json_string(params)
#通过client对象调用想要访问的接口,需要传入请求对象
resp=client.InvokeChainMakerContract(req)
#输出json格式的字符串回包
print(resp.to_json_string())