Unverified Commit e44ba57b authored by vipwzw's avatar vipwzw Committed by GitHub

Merge pull request #1105 from zhengjunhe/exchange_order_0929

Exchange order 0929
parents e869c482 e09bf312
......@@ -387,6 +387,9 @@ ForkAutonomyEnableItem=0
[fork.sub.jsvm]
Enable=0
[fork.sub.evmxgo]
Enable=0
[fork.sub.issuance]
Enable=0
ForkIssuanceTableUpdate=0
......
proj := "build"
.PHONY: default build remote winset
SRC_CLI := 33cn/plugin/plugin/dapp/bridgevmxgo/boss4x
OUT := build
default: build
build:
@go build -o ${OUT}/boss4x
remote:
@go build -v -o ${OUT}/boss4x_remote -ldflags "-X ${SRC_CLI}/buildFlags.RPCAddr4Chain33=http://183.129.226.74:8901"
winset:
@CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -o ${OUT}/boss4x.exe -ldflags "-X ${SRC_CLI}/buildFlags.RPCAddr4Chain33=http://183.129.226.74:8901"
clean:
@rm ${OUT}/*
package buildFlags
var RPCAddr4Chain33 string
var paraName string
package chain33
import (
"github.com/33cn/plugin/plugin/dapp/bridgevmxgo/boss4x/chain33/offline"
"github.com/spf13/cobra"
)
func Chain33Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "chain33",
Short: "deploy to chain33",
}
cmd.AddCommand(
offline.Boss4xOfflineCmd(),
)
return cmd
}
package offline
import (
"fmt"
"math/big"
"github.com/33cn/plugin/plugin/dapp/bridgevmxgo/contracts/generated"
ebTypes "github.com/33cn/plugin/plugin/dapp/cross2eth/ebrelayer/types"
utilsRelayer "github.com/33cn/plugin/plugin/dapp/cross2eth/ebrelayer/utils"
evmAbi "github.com/33cn/plugin/plugin/dapp/evm/executor/abi"
"github.com/spf13/cobra"
)
/*
./boss4x chain33 offline set_offline_token -c 1MaP3rrwiLV1wrxPhDwAfHggtei1ByaKrP -s BTY -m 100000000000 -p 50 -k 0x027ca96466c71c7e7c5d73b7e1f43cb889b3bd65ebd2413eefd31c6709c262ae --chainID 33
./boss4x chain33 offline send -f chain33_set_offline_token.txt
*/
func ConfigLockedTokenOfflineSaveCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "set_offline_token",
Short: "set config offline locked token",
Run: ConfigMultisignLockedTokenOfflineSave,
}
addConfigLockedTokenOfflineSaveFlags(cmd)
return cmd
}
func addConfigLockedTokenOfflineSaveFlags(cmd *cobra.Command) {
cmd.Flags().StringP("contract", "c", "", "bridgebank contract address")
_ = cmd.MarkFlagRequired("contract")
cmd.Flags().StringP("token", "t", "", "token addr")
cmd.Flags().StringP("symbol", "s", "", "token symbol")
_ = cmd.MarkFlagRequired("symbol")
cmd.Flags().StringP("threshold", "m", "0", "threshold")
_ = cmd.MarkFlagRequired("threshold")
cmd.Flags().Uint8P("percents", "p", 50, "percents")
cmd.Flags().StringP("key", "k", "", "the deployer private key")
_ = cmd.MarkFlagRequired("key")
cmd.Flags().StringP("note", "n", "", "transaction note info (optional)")
cmd.Flags().Float64P("fee", "f", 0, "contract gas fee (optional)")
}
func ConfigMultisignLockedTokenOfflineSave(cmd *cobra.Command, _ []string) {
contract, _ := cmd.Flags().GetString("contract")
token, _ := cmd.Flags().GetString("token")
symbol, _ := cmd.Flags().GetString("symbol")
threshold, _ := cmd.Flags().GetString("threshold")
percents, _ := cmd.Flags().GetUint8("percents")
bn := big.NewInt(1)
bn, _ = bn.SetString(utilsRelayer.TrimZeroAndDot(threshold), 10)
if token == "" || symbol == "BTY" {
token = ebTypes.BTYAddrChain33
}
parameter := fmt.Sprintf("configLockedTokenOfflineSave(%s,%s,%d,%d)", token, symbol, bn, percents)
_, packData, err := evmAbi.Pack(parameter, generated.BridgeBankABI, false)
if nil != err {
fmt.Println("configOfflineSaveAccount", "Failed to do abi.Pack due to:", err.Error())
return
}
callContractAndSignWrite(cmd, packData, contract, "chain33_set_offline_token")
}
package offline
import (
"fmt"
"github.com/33cn/plugin/plugin/dapp/bridgevmxgo/contracts/generated"
evmAbi "github.com/33cn/plugin/plugin/dapp/evm/executor/abi"
"github.com/spf13/cobra"
)
/*
./boss4x chain33 offline set_offline_addr -a 16skyHQA4YPPnhrDSSpZnexDzasS8BNx1R -c 1QD5pHMKZ9QWiNb9AsH3G1aG3Hashye83o -k 0x027ca96466c71c7e7c5d73b7e1f43cb889b3bd65ebd2413eefd31c6709c262ae --chainID 33
./boss4x chain33 offline send -f chain33_set_offline_addr.txt
*/
func ConfigOfflineSaveAccountCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "set_offline_addr",
Short: "save config offline account",
Run: ConfigMultisignOfflineSaveAccount, //配置账户
}
addConfigOfflineSaveAccountFlags(cmd)
return cmd
}
func addConfigOfflineSaveAccountFlags(cmd *cobra.Command) {
cmd.Flags().StringP("address", "a", "", "multisign address")
_ = cmd.MarkFlagRequired("address")
cmd.Flags().StringP("contract", "c", "", "bridgebank contract address")
_ = cmd.MarkFlagRequired("contract")
cmd.Flags().StringP("key", "k", "", "the deployer private key")
_ = cmd.MarkFlagRequired("key")
cmd.Flags().StringP("note", "n", "", "transaction note info (optional)")
cmd.Flags().Float64P("fee", "f", 0, "contract gas fee (optional)")
}
func ConfigMultisignOfflineSaveAccount(cmd *cobra.Command, _ []string) {
multisign, _ := cmd.Flags().GetString("address")
contract, _ := cmd.Flags().GetString("contract")
parameter := fmt.Sprintf("configOfflineSaveAccount(%s)", multisign)
_, packData, err := evmAbi.Pack(parameter, generated.BridgeBankABI, false)
if nil != err {
fmt.Println("configOfflineSaveAccount", "Failed to do abi.Pack due to:", err.Error())
return
}
callContractAndSignWrite(cmd, packData, contract, "chain33_set_offline_addr")
}
package offline
import (
"encoding/json"
"fmt"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/system/crypto/secp256k1"
"github.com/33cn/plugin/plugin/dapp/bridgevmxgo/contracts/generated"
erc20 "github.com/33cn/plugin/plugin/dapp/cross2eth/contracts/erc20/generated"
"github.com/33cn/plugin/plugin/dapp/dex/utils"
evmAbi "github.com/33cn/plugin/plugin/dapp/evm/executor/abi"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/spf13/cobra"
)
/*
./boss4x chain33 offline create_erc20 -s YCC -k 0x027ca96466c71c7e7c5d73b7e1f43cb889b3bd65ebd2413eefd31c6709c262ae -o 1N6HstkyLFS8QCeVfdvYxx1xoryXoJtvvZ --chainID 33
./boss4x chain33 offline send -f deployErc20YCCChain33.txt
./boss4x chain33 offline approve_erc20 -a 330000000000 -s 1JmWVu1GEdQYSN1opxS9C39aS4NvG57yTr -c 1998HqVnt4JUirhC9KL5V71xYU8cFRn82c -k 0x027ca96466c71c7e7c5d73b7e1f43cb889b3bd65ebd2413eefd31c6709c262ae --chainID 33
./boss4x chain33 offline send -f approve_erc20.txt
./boss4x chain33 offline create_add_lock_list -c 1JmWVu1GEdQYSN1opxS9C39aS4NvG57yTr -k 0x027ca96466c71c7e7c5d73b7e1f43cb889b3bd65ebd2413eefd31c6709c262ae -t 1998HqVnt4JUirhC9KL5V71xYU8cFRn82c --chainID 33 -s YCC
./boss4x chain33 offline send -f create_add_lock_list.txt
./boss4x chain33 offline create_bridge_token -c 1JmWVu1GEdQYSN1opxS9C39aS4NvG57yTr -k 0x027ca96466c71c7e7c5d73b7e1f43cb889b3bd65ebd2413eefd31c6709c262ae -s YCC --chainID 33
./boss4x chain33 offline send -f create_bridge_token.txt
${Chain33Cli} evm abi call -a "${chain33BridgeBank}" -c "${chain33DeployAddr}" -b "getToken2address(YCC)"
./chain33-cli evm abi call -a 1JmWVu1GEdQYSN1opxS9C39aS4NvG57yTr -c 1N6HstkyLFS8QCeVfdvYxx1xoryXoJtvvZ -b 'getToken2address(YCC)'
*/
func CreateERC20Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create_erc20",
Short: "create erc20 contracts and sign, default 3300*1e8 to be minted",
Run: CreateERC20,
}
CreateERC20Flags(cmd)
return cmd
}
//CreateERC20Flags ...
func CreateERC20Flags(cmd *cobra.Command) {
cmd.Flags().StringP("key", "k", "", "the deployer private key")
_ = cmd.MarkFlagRequired("key")
cmd.Flags().StringP("owner", "o", "", "owner address")
_ = cmd.MarkFlagRequired("owner")
cmd.Flags().StringP("symbol", "s", "", "token symbol")
_ = cmd.MarkFlagRequired("symbol")
cmd.Flags().Float64P("amount", "a", 0, "amount to be minted(optional),default to 3300*1e8")
}
func CreateERC20(cmd *cobra.Command, _ []string) {
symbol, _ := cmd.Flags().GetString("symbol")
owner, _ := cmd.Flags().GetString("owner")
amount, _ := cmd.Flags().GetFloat64("amount")
amountInt64 := int64(3300 * 1e8)
if 0 != int64(amount) {
amountInt64 = int64(amount)
}
privateKeyStr, _ := cmd.Flags().GetString("key")
var driver secp256k1.Driver
privateKeySli := common.FromHex(privateKeyStr)
privateKey, err := driver.PrivKeyFromBytes(privateKeySli)
if nil != err {
fmt.Println("Failed to do PrivKeyFromBytes")
return
}
fromAddr := address.PubKeyToAddress(privateKey.PubKey().Bytes())
from := common.Address{
Addr: fromAddr,
}
createPara := fmt.Sprintf("%s,%s,%s,%s", symbol, symbol, fmt.Sprintf("%d", amountInt64), owner)
content, txHash, err := utils.CreateContractAndSign(getTxInfo(cmd), erc20.ERC20Bin, erc20.ERC20ABI, createPara, "ERC20:"+symbol)
if nil != err {
fmt.Println("CreateContractAndSign erc20 fail")
return
}
newContractAddr := common.NewContractAddress(from, txHash).String()
Erc20Tx := &utils.Chain33OfflineTx{
ContractAddr: newContractAddr,
TxHash: common.Bytes2Hex(txHash),
SignedRawTx: content,
OperationName: "deploy ERC20:" + symbol,
}
data, err := json.MarshalIndent(Erc20Tx, "", " ")
if err != nil {
fmt.Println("MarshalIndent error", err.Error())
return
}
fmt.Println(string(data))
var txs []*utils.Chain33OfflineTx
txs = append(txs, Erc20Tx)
fileName := fmt.Sprintf("deployErc20%sChain33.txt", symbol)
fmt.Printf("Write all the txs to file: %s \n", fileName)
utils.WriteToFileInJson(fileName, txs)
}
func ApproveErc20Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "approve_erc20",
Short: "approve erc20",
Run: ApproveErc20, //配置账户
}
addApproveErc20Flags(cmd)
return cmd
}
func addApproveErc20Flags(cmd *cobra.Command) {
cmd.Flags().StringP("approve", "s", "", "approve addr")
_ = cmd.MarkFlagRequired("approve")
cmd.Flags().Float64P("amount", "a", 0, "approve amount")
_ = cmd.MarkFlagRequired("amount")
cmd.Flags().StringP("contract", "c", "", "Erc20 contract address")
_ = cmd.MarkFlagRequired("contract")
cmd.Flags().StringP("key", "k", "", "the deployer private key")
_ = cmd.MarkFlagRequired("key")
cmd.Flags().StringP("note", "n", "", "transaction note info (optional)")
cmd.Flags().Float64P("fee", "f", 0, "contract gas fee (optional)")
}
func ApproveErc20(cmd *cobra.Command, _ []string) {
contract, _ := cmd.Flags().GetString("contract")
approve, _ := cmd.Flags().GetString("approve")
amount, _ := cmd.Flags().GetFloat64("amount")
parameter := fmt.Sprintf("approve(%s,%d)", approve, int64(amount))
_, packData, err := evmAbi.Pack(parameter, generated.BridgeTokenABI, false)
if nil != err {
fmt.Println("configOfflineSaveAccount", "Failed to do abi.Pack due to:", err.Error())
return
}
callContractAndSignWrite(cmd, packData, contract, "approve_erc20")
}
func AddToken2LockListCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create_add_lock_list",
Short: "add token to lock list",
Run: AddToken2LockList, //配置账户
}
addAddToken2LockListFlags(cmd)
return cmd
}
func addAddToken2LockListFlags(cmd *cobra.Command) {
cmd.Flags().StringP("symbol", "s", "", "token symbol")
_ = cmd.MarkFlagRequired("symbol")
cmd.Flags().StringP("token", "t", "", "token addr")
_ = cmd.MarkFlagRequired("token")
cmd.Flags().StringP("contract", "c", "", "bridgebank contract address")
_ = cmd.MarkFlagRequired("contract")
cmd.Flags().StringP("key", "k", "", "the deployer private key")
_ = cmd.MarkFlagRequired("key")
cmd.Flags().StringP("note", "n", "", "transaction note info (optional)")
cmd.Flags().Float64P("fee", "f", 0, "contract gas fee (optional)")
}
func AddToken2LockList(cmd *cobra.Command, _ []string) {
contract, _ := cmd.Flags().GetString("contract")
symbol, _ := cmd.Flags().GetString("symbol")
token, _ := cmd.Flags().GetString("token")
parameter := fmt.Sprintf("addToken2LockList(%s,%s)", token, symbol)
_, packData, err := evmAbi.Pack(parameter, generated.BridgeBankABI, false)
if nil != err {
fmt.Println("configOfflineSaveAccount", "Failed to do abi.Pack due to:", err.Error())
return
}
callContractAndSignWrite(cmd, packData, contract, "create_add_lock_list")
}
func CreateNewBridgeTokenCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create_bridge_token",
Short: "create new token as ethereum asset on chain33, and it's should be done by operator",
Run: CreateNewBridgeToken, //配置账户
}
addCreateNewBridgeTokenFlags(cmd)
return cmd
}
func addCreateNewBridgeTokenFlags(cmd *cobra.Command) {
cmd.Flags().StringP("symbol", "s", "", "token symbol")
_ = cmd.MarkFlagRequired("symbol")
cmd.Flags().StringP("contract", "c", "", "bridgebank contract address")
_ = cmd.MarkFlagRequired("contract")
cmd.Flags().StringP("key", "k", "", "the deployer private key")
_ = cmd.MarkFlagRequired("key")
cmd.Flags().StringP("note", "n", "", "transaction note info (optional)")
cmd.Flags().Float64P("fee", "f", 0, "contract gas fee (optional)")
}
func CreateNewBridgeToken(cmd *cobra.Command, _ []string) {
contract, _ := cmd.Flags().GetString("contract")
symbol, _ := cmd.Flags().GetString("symbol")
parameter := fmt.Sprintf("createNewBridgeToken(%s)", symbol)
_, packData, err := evmAbi.Pack(parameter, generated.BridgeBankABI, false)
if nil != err {
fmt.Println("configOfflineSaveAccount", "Failed to do abi.Pack due to:", err.Error())
return
}
callContractAndSignWrite(cmd, packData, contract, "create_bridge_token")
}
package offline
import (
"fmt"
"strings"
gnosis "github.com/33cn/plugin/plugin/dapp/cross2eth/contracts/gnosis/generated"
ebTypes "github.com/33cn/plugin/plugin/dapp/cross2eth/ebrelayer/types"
evmAbi "github.com/33cn/plugin/plugin/dapp/evm/executor/abi"
"github.com/spf13/cobra"
)
/*
./boss4x chain33 offline multisign_setup -m 1GrhufvPtnBCtfxDrFGcCoihmYMHJafuPn -o 168Sn1DXnLrZHTcAM9stD6t2P49fNuJfJ9,13KTf57aCkVVJYNJBXBBveiA5V811SrLcT,1JQwQWsShTHC4zxHzbUfYQK4kRBriUQdEe,1NHuKqoKe3hyv52PF8XBAyaTmJWAqA2Jbb -k 0x027ca96466c71c7e7c5d73b7e1f43cb889b3bd65ebd2413eefd31c6709c262ae --chainID 33
./boss4x chain33 offline send -f multisign_setup.txt
*/
func SetupCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "multisign_setup",
Short: "Setup owners to contract",
Run: SetupOwner,
}
SetupOwnerFlags(cmd)
return cmd
}
func SetupOwnerFlags(cmd *cobra.Command) {
cmd.Flags().StringP("owner", "o", "", "owners's address, separated by ','")
_ = cmd.MarkFlagRequired("owner")
cmd.Flags().StringP("key", "k", "", "operator private key")
_ = cmd.MarkFlagRequired("operator")
cmd.Flags().StringP("multisign", "m", "", "multisign contract address")
_ = cmd.MarkFlagRequired("multisign")
}
func SetupOwner(cmd *cobra.Command, _ []string) {
multisign, _ := cmd.Flags().GetString("multisign")
owner, _ := cmd.Flags().GetString("owner")
owners := strings.Split(owner, ",")
BTYAddrChain33 := ebTypes.BTYAddrChain33
parameter := "setup(["
parameter += fmt.Sprintf("%s", owners[0])
for _, owner := range owners[1:] {
parameter += fmt.Sprintf(",%s", owner)
}
parameter += "], "
parameter += fmt.Sprintf("%d, %s, 0102, %s, %s, 0, %s)", len(owners), BTYAddrChain33, BTYAddrChain33, BTYAddrChain33, BTYAddrChain33)
_, packData, err := evmAbi.Pack(parameter, gnosis.GnosisSafeABI, false)
if nil != err {
fmt.Println("multisign_setup", "Failed to do abi.Pack due to:", err.Error())
return
}
callContractAndSignWrite(cmd, packData, multisign, "multisign_setup")
}
package offline
import (
"fmt"
"math/big"
"strings"
"github.com/33cn/plugin/plugin/dapp/cross2eth/contracts/gnosis/generated"
gnosis "github.com/33cn/plugin/plugin/dapp/cross2eth/contracts/gnosis/generated"
chain33Common "github.com/33cn/chain33/common"
"github.com/33cn/chain33/system/crypto/secp256k1"
erc20 "github.com/33cn/plugin/plugin/dapp/cross2eth/contracts/erc20/generated"
chain33Relayer "github.com/33cn/plugin/plugin/dapp/cross2eth/ebrelayer/relayer/chain33"
ebrelayerTypes "github.com/33cn/plugin/plugin/dapp/cross2eth/ebrelayer/types"
relayerutils "github.com/33cn/plugin/plugin/dapp/cross2eth/ebrelayer/utils"
evmAbi "github.com/33cn/plugin/plugin/dapp/evm/executor/abi"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common/math"
btcecsecp256k1 "github.com/btcsuite/btcd/btcec"
ethSecp256k1 "github.com/ethereum/go-ethereum/crypto/secp256k1"
"github.com/spf13/cobra"
)
/*
./boss4x chain33 offline create_multisign_transfer -a 10 -r 168Sn1DXnLrZHTcAM9stD6t2P49fNuJfJ9 -m 1NFDfEwne4kjuxAZrtYEh4kfSrnGSE7ap
./boss4x chain33 offline multisign_transfer -k 0x027ca96466c71c7e7c5d73b7e1f43cb889b3bd65ebd2413eefd31c6709c262a -s 0xcd284cd17456b73619fa609bb9e3105e8eff5d059c5e0b6eb1effbebd4d64144,0xe892212221b3b58211b90194365f4662764b6d5474ef2961ef77c909e31eeed3,0x9d19a2e9a440187010634f4f08ce36e2bc7b521581436a99f05568be94dc66ea,0x45d4ce009e25e6d5e00d8d3a50565944b2e3604aa473680a656b242d9acbff35 --chainID 33
./boss4x chain33 offline send -f multisign_transfer.txt
*/
type transferTxData struct {
Receiver string
Token string
MultisignAddr string
Data string
Amount float64
name string
}
func CreateMultisignTransferCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create_multisign_transfer",
Short: "create multisign transfer tx",
Run: CreateMultisignTransfer,
}
addCreateMultisignTransferFlags(cmd)
return cmd
}
func addCreateMultisignTransferFlags(cmd *cobra.Command) {
cmd.Flags().StringP("receiver", "r", "", "receive address")
_ = cmd.MarkFlagRequired("receiver")
cmd.Flags().Float64P("amount", "a", 0, "amount to transfer")
_ = cmd.MarkFlagRequired("amount")
cmd.Flags().StringP("token", "t", "", "erc20 address,not need to set for BTY(optional)")
//
cmd.Flags().StringP("address", "m", "", "multisign address")
_ = cmd.MarkFlagRequired("address")
}
func CreateMultisignTransfer(cmd *cobra.Command, _ []string) {
rpcLaddr, _ := cmd.Flags().GetString("rpc_laddr")
receiver, _ := cmd.Flags().GetString("receiver")
token, _ := cmd.Flags().GetString("token")
amount, _ := cmd.Flags().GetFloat64("amount")
multisign, _ := cmd.Flags().GetString("address")
//对于平台币转账,这个data只是个占位符,没有作用
dataStr := "0x"
safeTxGas := int64(10 * 10000)
baseGas := 0
gasPrice := 0
valueStr := relayerutils.ToWei(amount, 8).String()
//如果是bty转账,则直接将to地址设置为receiver,而如果是ERC20转账,则需要将其设置为token地址
to := receiver
//如果是erc20转账,则需要构建data数据
if "" != token {
parameter := fmt.Sprintf("transfer(%s, %s)", receiver, relayerutils.ToWei(amount, 8).String())
_, data, err := evmAbi.Pack(parameter, erc20.ERC20ABI, false)
if err != nil {
fmt.Println("Failed to do abi.Pack due to:", err.Error())
return
}
//对于其他erc20资产,直接将其设置为0
valueStr = "0"
to = token
dataStr = chain33Common.ToHex(data)
}
//获取nonce
nonce := getMulSignNonce(multisign, rpcLaddr)
parameter2getHash := fmt.Sprintf("getTransactionHash(%s, %s, %s, 0, %d, %d, %d, %s, %s, %d)", to, valueStr, dataStr,
safeTxGas, baseGas, gasPrice, ebrelayerTypes.NilAddrChain33, ebrelayerTypes.NilAddrChain33, nonce)
result := chain33Relayer.Query(multisign, parameter2getHash, multisign, rpcLaddr, generated.GnosisSafeABI)
if nil == result {
fmt.Println("Failed to getTransactionHash :", ebrelayerTypes.ErrGetTransactionHash)
return
}
contentHashArray := result.([32]byte)
contentHash := contentHashArray[:]
var txinfo transferTxData
txinfo.Receiver = receiver
txinfo.MultisignAddr = multisign
txinfo.Amount = amount
txinfo.Data = chain33Common.ToHex(contentHash)
txinfo.Token = token
txinfo.name = "create_multisign_transfer"
writeToFile(txinfo.name+".txt", txinfo)
}
func MultisignTransferCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "multisign_transfer",
Short: "create multisign transfer tx and sign",
Run: MultisignTransfer,
}
addMultisignTransferFlags(cmd)
return cmd
}
func addMultisignTransferFlags(cmd *cobra.Command) {
cmd.Flags().StringP("file", "t", "create_multisign_transfer.txt", "tx file, default: create_multisign_transfer.txt")
cmd.Flags().StringP("keys", "s", "", "owners' private key, separated by ','")
_ = cmd.MarkFlagRequired("keys")
cmd.Flags().StringP("key", "k", "", "the deployer private key")
_ = cmd.MarkFlagRequired("key")
cmd.Flags().StringP("note", "n", "", "transaction note info (optional)")
cmd.Flags().Float64P("fee", "f", 0, "contract gas fee (optional)")
}
func MultisignTransfer(cmd *cobra.Command, _ []string) {
keysStr, _ := cmd.Flags().GetString("keys")
keys := strings.Split(keysStr, ",")
txFilePath, _ := cmd.Flags().GetString("file")
var txinfo transferTxData
err := paraseFile(txFilePath, &txinfo)
if err != nil {
fmt.Println("paraseFile Err:", err)
return
}
//对于平台币转账,这个data只是个占位符,没有作用
dataStr := "0x"
contentHash, err := chain33Common.FromHex(txinfo.Data)
safeTxGas := int64(10 * 10000)
baseGas := 0
gasPrice := 0
valueStr := relayerutils.ToWei(txinfo.Amount, 8).String()
//如果是bty转账,则直接将to地址设置为receiver,而如果是ERC20转账,则需要将其设置为token地址
to := txinfo.Receiver
//如果是erc20转账,则需要构建data数据
if "" != txinfo.Token {
parameter := fmt.Sprintf("transfer(%s, %s)", txinfo.Receiver, relayerutils.ToWei(txinfo.Amount, 8).String())
_, data, err := evmAbi.Pack(parameter, erc20.ERC20ABI, false)
if err != nil {
fmt.Println("evmAbi.Pack(parameter, erc20.ERC20ABI, false)", "Failed", err.Error())
return
}
//对于其他erc20资产,直接将其设置为0
valueStr = "0"
to = txinfo.Token
dataStr = chain33Common.ToHex(data)
}
var sigs []byte
for _, privateKey := range keys {
var driver secp256k1.Driver
privateKeySli, err := chain33Common.FromHex(privateKey)
if nil != err {
fmt.Println("evmAbi.Pack(parameter, erc20.ERC20ABI, false)", "Failed", err.Error())
return
}
ownerPrivateKey, err := driver.PrivKeyFromBytes(privateKeySli)
if nil != err {
fmt.Println("evmAbi.Pack(parameter, erc20.ERC20ABI, false)", "Failed", err.Error())
return
}
temp, _ := btcecsecp256k1.PrivKeyFromBytes(btcecsecp256k1.S256(), ownerPrivateKey.Bytes())
privateKey4chain33Ecdsa := temp.ToECDSA()
sig, err := ethSecp256k1.Sign(contentHash, math.PaddedBigBytes(privateKey4chain33Ecdsa.D, 32))
if nil != err {
fmt.Println("evmAbi.Pack(parameter, erc20.ERC20ABI, false)", "Failed", err.Error())
return
}
sig[64] += 27
sigs = append(sigs, sig...)
}
//构造execTransaction参数
parameter2Exec := fmt.Sprintf("execTransaction(%s, %s, %s, 0, %d, %d, %d, %s, %s, %s)", to, valueStr, dataStr,
safeTxGas, baseGas, gasPrice, ebrelayerTypes.NilAddrChain33, ebrelayerTypes.NilAddrChain33, chain33Common.ToHex(sigs))
_, packData, err := evmAbi.Pack(parameter2Exec, gnosis.GnosisSafeABI, false)
if nil != err {
fmt.Println("execTransaction evmAbi.Pack", "Failed", err.Error())
return
}
callContractAndSignWrite(cmd, packData, txinfo.MultisignAddr, "multisign_transfer")
}
func getMulSignNonce(mulsign, rpcLaddr string) int64 {
parameter := fmt.Sprintf("nonce()")
result := chain33Relayer.Query(mulsign, parameter, mulsign, rpcLaddr, gnosis.GnosisSafeABI)
if nil == result {
return 0
}
nonce := result.(*big.Int)
return nonce.Int64()
}
package offline
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"github.com/33cn/plugin/plugin/dapp/dex/utils"
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
"github.com/ethereum/go-ethereum/common"
"github.com/spf13/cobra"
)
var crossXfileName = "deployBridgevmxgo2Chain33.txt"
func Boss4xOfflineCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "offline",
Short: "create and sign offline tx to deploy and set cross contracts to chain33",
}
cmd.AddCommand(
CreateBridgevmxgoCmd(),
SendSignTxs2Chain33Cmd(),
CreateERC20Cmd(),
ApproveErc20Cmd(),
AddToken2LockListCmd(),
CreateNewBridgeTokenCmd(),
SetupCmd(),
ConfigOfflineSaveAccountCmd(),
ConfigLockedTokenOfflineSaveCmd(),
CreateMultisignTransferCmd(),
MultisignTransferCmd(),
)
return cmd
}
func SendSignTxs2Chain33Cmd() *cobra.Command {
cmd := &cobra.Command{
Use: "send",
Short: "send all the txs to chain33 in serial",
Run: sendSignTxs2Chain33,
}
addSendSignTxs2Chain33Flags(cmd)
return cmd
}
func addSendSignTxs2Chain33Flags(cmd *cobra.Command) {
cmd.Flags().StringP("file", "f", "", "signed tx file")
_ = cmd.MarkFlagRequired("file")
}
func sendSignTxs2Chain33(cmd *cobra.Command, _ []string) {
filePath, _ := cmd.Flags().GetString("file")
url, _ := cmd.Flags().GetString("rpc_laddr")
utils.SendSignTxs2Chain33(filePath, url)
}
func getTxInfo(cmd *cobra.Command) *utils.TxCreateInfo {
privateKey, _ := cmd.Flags().GetString("key")
expire, _ := cmd.Flags().GetString("expire")
note, _ := cmd.Flags().GetString("note")
fee, _ := cmd.Flags().GetFloat64("fee")
paraName, _ := cmd.Flags().GetString("paraName")
chainID, _ := cmd.Flags().GetInt32("chainID")
feeInt64 := int64(fee*1e4) * 1e4
info := &utils.TxCreateInfo{
PrivateKey: privateKey,
Expire: expire,
Note: note,
Fee: feeInt64,
ParaName: paraName,
ChainID: chainID,
}
return info
}
func writeToFile(fileName string, content interface{}) {
jbytes, err := json.MarshalIndent(content, "", "\t")
if err != nil {
panic(err)
}
err = ioutil.WriteFile(fileName, jbytes, 0666)
if err != nil {
fmt.Println("Failed to write to file:", fileName)
}
fmt.Println("tx is written to file: ", fileName)
}
func paraseFile(file string, result interface{}) error {
_, err := os.Stat(file)
if err != nil {
fmt.Println(err.Error())
return err
}
f, err := os.Open(file)
if err != nil {
panic(err)
}
b, err := ioutil.ReadAll(f)
if err != nil {
panic(err)
}
return json.Unmarshal(b, result)
}
func callContractAndSignWrite(cmd *cobra.Command, para []byte, contractAddr, name string) {
action := &evmtypes.EVMContractAction{Amount: 0, GasLimit: 0, GasPrice: 0, Note: name, Para: para, ContractAddr: contractAddr}
content, txHash, err := utils.CallContractAndSign(getTxInfo(cmd), action, contractAddr)
if nil != err {
fmt.Println("CallContractAndSign", "Failed", err.Error())
return
}
Tx := &utils.Chain33OfflineTx{
ContractAddr: contractAddr,
TxHash: common.Bytes2Hex(txHash),
SignedRawTx: content,
OperationName: name,
}
_, err = json.MarshalIndent(Tx, "", " ")
if err != nil {
fmt.Println("MarshalIndent error", err.Error())
return
}
var txs []*utils.Chain33OfflineTx
txs = append(txs, Tx)
fileName := fmt.Sprintf(Tx.OperationName + ".txt")
fmt.Printf("Write all the txs to file: %s \n", fileName)
utils.WriteToFileInJson(fileName, txs)
}
package main
import (
"fmt"
"net/http"
"os"
"strings"
"github.com/33cn/plugin/plugin/dapp/bridgevmxgo/boss4x/buildFlags"
"github.com/33cn/plugin/plugin/dapp/bridgevmxgo/boss4x/chain33"
"github.com/spf13/cobra"
)
func main() {
if buildFlags.RPCAddr4Chain33 == "" {
buildFlags.RPCAddr4Chain33 = "http://localhost:8801"
}
buildFlags.RPCAddr4Chain33 = testTLS(buildFlags.RPCAddr4Chain33)
rootCmd := RootCmd()
rootCmd.PersistentFlags().String("rpc_laddr", buildFlags.RPCAddr4Chain33, "http url")
rootCmd.PersistentFlags().String("paraName", "", "para chain name,Eg:user.p.fzm.")
rootCmd.PersistentFlags().String("expire", "120m", "transaction expire time (optional)")
rootCmd.PersistentFlags().Int32("chainID", 0, "chain id, default to 0")
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
// RootCmd Cmd x2ethereum client command
func RootCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "boss for bridgevmxgo",
Short: "manage create offline tx or deploy contracts(bridgevmxgo) for test",
}
cmd.AddCommand(
chain33.Chain33Cmd(),
)
return cmd
}
func testTLS(RPCAddr string) string {
rpcaddr := RPCAddr
if !strings.HasPrefix(rpcaddr, "http://") {
return RPCAddr
}
// if http://
if rpcaddr[len(rpcaddr)-1] != '/' {
rpcaddr += "/"
}
rpcaddr += "test"
/* #nosec */
resp, err := http.Get(rpcaddr)
if err != nil {
return "https://" + RPCAddr[7:]
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
return RPCAddr
}
return "https://" + RPCAddr[7:]
}
all:
chmod +x ./build.sh
./build.sh $(OUT) $(FLAG)
#!/usr/bin/env bash
# 官方ci集成脚本
strpwd=$(pwd)
strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*}
SRC_EBCLI=github.com/33cn/plugin/plugin/dapp/cross2eth/ebcli
SRC_EBRELAYER=github.com/33cn/plugin/plugin/dapp/cross2eth/ebrelayer
SRC_BOSS4XCLI=github.com/33cn/plugin/plugin/dapp/cross2eth/boss4x
SRC_EVMXGOBOSS4XCLI=github.com/33cn/plugin/plugin/dapp/bridgevmxgo/boss4x
OUT_DIR="${1}/$strapp"
FLAG=$2
# shellcheck disable=SC2086,1072
go build -i ${FLAG} -v -o "${OUT_DIR}/ebrelayer" "${SRC_EBRELAYER}"
# shellcheck disable=SC2086,1072
go build -i ${FLAG} -v -o "${OUT_DIR}/ebcli_A" "${SRC_EBCLI}"
# shellcheck disable=SC2086,1072
go build -i ${FLAG} -v -o "${OUT_DIR}/ebcli_B" -ldflags "-X ${SRC_EBCLI}/buildflags.RPCAddr=http://localhost:9902" "${SRC_EBCLI}"
# shellcheck disable=SC2086,1072
go build -i ${FLAG} -v -o "${OUT_DIR}/ebcli_C" -ldflags "-X ${SRC_EBCLI}/buildflags.RPCAddr=http://localhost:9903" "${SRC_EBCLI}"
# shellcheck disable=SC2086,1072
go build -i ${FLAG} -v -o "${OUT_DIR}/ebcli_D" -ldflags "-X ${SRC_EBCLI}/buildflags.RPCAddr=http://localhost:9904" "${SRC_EBCLI}"
# shellcheck disable=SC2086,1072
go build -i ${FLAG} -v -o "${OUT_DIR}/boss4x" "${SRC_BOSS4XCLI}"
# shellcheck disable=SC2086,1072
go build -i ${FLAG} -v -o "${OUT_DIR}/evmxgoboss4x" "${SRC_EVMXGOBOSS4XCLI}"
cp ../../../../chain33.para.toml "${OUT_DIR}"
cp ../../cross2eth/ebrelayer/relayer.toml "${OUT_DIR}/relayer.toml"
cp ./build/* "${OUT_DIR}"
cp ./build/abi/* "${OUT_DIR}"
cp ./build/public/* "${OUT_DIR}"
OUT_TESTDIR="${1}/dapptest/$strapp"
mkdir -p "${OUT_TESTDIR}"
cp ./test/* "${OUT_TESTDIR}"
FROM ubuntu:16.04
WORKDIR /root
COPY chain33 chain33
COPY chain33-cli chain33-cli
COPY chain33.toml chain33*.toml ./
COPY entrypoint.sh entrypoint.sh
CMD ["/root/chain33", "-f", "/root/chain33.toml"]
FROM ubuntu:16.04
WORKDIR /root
COPY ebrelayer ebrelayer
COPY ebcli_A ebcli_A
COPY boss4x boss4x
COPY evmxgoboss4x evmxgoboss4x
COPY sleep.sh sleep.sh
CMD ["/root/sleep.sh"]
[{"inputs":[{"internalType":"address","name":"_ethereumBridge","type":"address"},{"internalType":"address","name":"_bridgeBank","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"address","name":"_valset","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_ethereumBridge","type":"address"},{"indexed":false,"internalType":"address","name":"_bridgeBank","type":"address"},{"indexed":false,"internalType":"address","name":"_oracle","type":"address"},{"indexed":false,"internalType":"address","name":"_valset","type":"address"}],"name":"LogContractsRegistered","type":"event"},{"constant":true,"inputs":[],"name":"bridgeBank","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"deployHeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"ethereumBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"valset","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]
\ No newline at end of file
[{"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"MinterAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"}],"name":"MinterRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"addMinter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burnFrom","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"isMinter","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[],"name":"renounceMinter","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
[{"inputs":[{"internalType":"address","name":"_operatorAddress","type":"address"},{"internalType":"address","name":"_oracleAddress","type":"address"},{"internalType":"address","name":"_ethereumBridgeAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_beneficiary","type":"address"}],"name":"LogBridgeTokenMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_ownerFrom","type":"address"},{"indexed":false,"internalType":"bytes","name":"_ethereumReceiver","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"LogEthereumTokenBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"bytes","name":"_to","type":"bytes"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"LogLock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"}],"name":"LogNewBridgeToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"LogUnlock","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"addToken2LockList","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"bridgeTokenCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTokenCreated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bridgeTokenWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_ethereumReceiver","type":"bytes"},{"internalType":"address","name":"_ethereumTokenAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burnBridgeTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_threshold","type":"uint256"},{"internalType":"uint8","name":"_percents","type":"uint8"}],"name":"configLockedTokenOfflineSave","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"addresspayable","name":"_offlineSave","type":"address"}],"name":"configOfflineSaveAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"createNewBridgeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"ethereumBridge","outputs":[{"internalType":"contractEthereumBridge","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"getEthereumDepositStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getLockedTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getToken2address","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getofflineSaveCfg","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"hasBridgeTokenCreated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"highThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_recipient","type":"bytes"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"lock","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"lockNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lockedFunds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lowThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_ethereumSender","type":"bytes"},{"internalType":"addresspayable","name":"_intendedRecipient","type":"address"},{"internalType":"address","name":"_bridgeTokenAddress","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintBridgeTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"offlineSave","outputs":[{"internalType":"addresspayable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"offlineSaveCfgs","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"_threshold","type":"uint256"},{"internalType":"uint8","name":"_percents","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"contractOracle","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"token2address","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenAllow2Lock","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"addresspayable","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unlock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"viewEthereumDeposit","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"addresspayable","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
\ No newline at end of file
[{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"uint256","name":"supply","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
\ No newline at end of file
[{"inputs":[{"internalType":"address","name":"_operatorAddress","type":"address"},{"internalType":"address","name":"_oracleAddress","type":"address"},{"internalType":"address","name":"_chain33BridgeAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_beneficiary","type":"address"}],"name":"LogBridgeTokenMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_ownerFrom","type":"address"},{"indexed":false,"internalType":"bytes","name":"_chain33Receiver","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"LogChain33TokenBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"bytes","name":"_to","type":"bytes"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"LogLock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"}],"name":"LogNewBridgeToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"LogUnlock","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"addToken2LockList","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"bridgeTokenCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTokenCreated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bridgeTokenWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_chain33Receiver","type":"bytes"},{"internalType":"address","name":"_chain33TokenAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burnBridgeTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"chain33Bridge","outputs":[{"internalType":"contractChain33Bridge","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_threshold","type":"uint256"},{"internalType":"uint8","name":"_percents","type":"uint8"}],"name":"configLockedTokenOfflineSave","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"addresspayable","name":"_offlineSave","type":"address"}],"name":"configOfflineSaveAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"createNewBridgeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"getChain33DepositStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getLockedTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getToken2address","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getToken2addressV2","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getofflineSaveCfg","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"hasBridgeTokenCreated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"highThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_recipient","type":"bytes"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"lock","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"lockNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lockedFunds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lowThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"bytes","name":"_chain33Sender","type":"bytes"},{"internalType":"addresspayable","name":"_intendedRecipient","type":"address"},{"internalType":"address","name":"_bridgeTokenAddress","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintBridgeTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"offlineSave","outputs":[{"internalType":"addresspayable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"offlineSaveCfgs","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"_threshold","type":"uint256"},{"internalType":"uint8","name":"_percents","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"contractOracle","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"token2address","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenAllow2Lock","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"addresspayable","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unlock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"viewChain33Deposit","outputs":[{"internalType":"bytes","name":"","type":"bytes"},{"internalType":"addresspayable","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
\ No newline at end of file
[{"inputs":[{"internalType":"address","name":"_goAssetBridge","type":"address"},{"internalType":"address","name":"_bridgeBank","type":"address"},{"internalType":"address","name":"_oracle","type":"address"},{"internalType":"address","name":"_valset","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_goAssetBridge","type":"address"},{"indexed":false,"internalType":"address","name":"_bridgeBank","type":"address"},{"indexed":false,"internalType":"address","name":"_oracle","type":"address"},{"indexed":false,"internalType":"address","name":"_valset","type":"address"}],"name":"LogContractsRegistered","type":"event"},{"constant":true,"inputs":[],"name":"bridgeBank","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"deployHeight","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"goAssetBridge","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"valset","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"}]
\ No newline at end of file
[{"inputs":[{"internalType":"address","name":"_operatorAddress","type":"address"},{"internalType":"address","name":"_oracleAddress","type":"address"},{"internalType":"address","name":"_goAssetBridgeAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_beneficiary","type":"address"}],"name":"LogBridgeTokenMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_ownerFrom","type":"address"},{"indexed":false,"internalType":"address","name":"_goAssetReceiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"LogGoAssetTokenBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"LogLock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"}],"name":"LogNewBridgeToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"LogUnlock","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"addToken2LockList","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"bridgeTokenCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTokenCreated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bridgeTokenWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_goAssetReceiver","type":"address"},{"internalType":"address","name":"_goAssetTokenAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burnBridgeTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_threshold","type":"uint256"},{"internalType":"uint8","name":"_percents","type":"uint8"}],"name":"configLockedTokenOfflineSave","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"addresspayable","name":"_offlineSave","type":"address"}],"name":"configOfflineSaveAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"createNewBridgeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"getGoAssetDepositStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getLockedTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getToken2address","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getofflineSaveCfg","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"goAssetBridge","outputs":[{"internalType":"contractGoAssetBridge","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"hasBridgeTokenCreated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"highThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"lock","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"lockNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lockedFunds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lowThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_goAssetSender","type":"address"},{"internalType":"addresspayable","name":"_intendedRecipient","type":"address"},{"internalType":"address","name":"_bridgeTokenAddress","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintBridgeTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"offlineSave","outputs":[{"internalType":"addresspayable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"offlineSaveCfgs","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"_threshold","type":"uint256"},{"internalType":"uint8","name":"_percents","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"contractOracle","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"token2address","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenAllow2Lock","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"addresspayable","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unlock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"viewGoAssetDeposit","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"addresspayable","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
\ No newline at end of file
[{"inputs":[{"internalType":"address","name":"_operatorAddress","type":"address"},{"internalType":"address","name":"_oracleAddress","type":"address"},{"internalType":"address","name":"_goAssetBridgeAddress","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_beneficiary","type":"address"}],"name":"LogBridgeTokenMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_amount","type":"uint256"},{"indexed":false,"internalType":"address","name":"_ownerFrom","type":"address"},{"indexed":false,"internalType":"address","name":"_goAssetReceiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"LogGoAssetTokenBurn","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_from","type":"address"},{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_nonce","type":"uint256"}],"name":"LogLock","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"}],"name":"LogNewBridgeToken","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_to","type":"address"},{"indexed":false,"internalType":"address","name":"_token","type":"address"},{"indexed":false,"internalType":"string","name":"_symbol","type":"string"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"LogUnlock","type":"event"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"}],"name":"addToken2LockList","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"bridgeTokenCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"bridgeTokenCreated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"bridgeTokenWhitelist","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_goAssetReceiver","type":"address"},{"internalType":"address","name":"_goAssetTokenAddress","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"burnBridgeTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_threshold","type":"uint256"},{"internalType":"uint8","name":"_percents","type":"uint8"}],"name":"configLockedTokenOfflineSave","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"addresspayable","name":"_offlineSave","type":"address"}],"name":"configOfflineSaveAccount","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"createNewBridgeToken","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"getGoAssetDepositStatus","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getLockedTokenAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"getToken2address","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"_token","type":"address"}],"name":"getofflineSaveCfg","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"goAssetBridge","outputs":[{"internalType":"contractGoAssetBridge","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"string","name":"_symbol","type":"string"}],"name":"hasBridgeTokenCreated","outputs":[{"internalType":"bool","name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"highThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"lock","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[],"name":"lockNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"lockedFunds","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"lowThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"address","name":"_goAssetSender","type":"address"},{"internalType":"addresspayable","name":"_intendedRecipient","type":"address"},{"internalType":"address","name":"_bridgeTokenAddress","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mintBridgeTokens","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"offlineSave","outputs":[{"internalType":"addresspayable","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"offlineSaveCfgs","outputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint256","name":"_threshold","type":"uint256"},{"internalType":"uint8","name":"_percents","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"operator","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"oracle","outputs":[{"internalType":"contractOracle","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"token2address","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenAllow2Lock","outputs":[{"internalType":"address","name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"internalType":"addresspayable","name":"_recipient","type":"address"},{"internalType":"address","name":"_token","type":"address"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"unlock","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"internalType":"bytes32","name":"_id","type":"bytes32"}],"name":"viewGoAssetDeposit","outputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"addresspayable","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}]
\ No newline at end of file
version: '3'
services:
ganachetest:
entrypoint: ["node", "/app/ganache-core.docker.cli.js", "-a", "20", "-b", "2", "--debug", "-m", "coast bar giraffe art venue decide symbol law visual crater vital fold", "-e", "1000"]
image: trufflesuite/ganache-cli:latest
ports:
- "8545:8545"
ebrelayera:
build:
context: .
dockerfile: Dockerfile-bridgevmxgo
ports:
- "9901:9901"
ebrelayerb:
build:
context: .
dockerfile: Dockerfile-bridgevmxgo
ebrelayerc:
build:
context: .
dockerfile: Dockerfile-bridgevmxgo
ebrelayerd:
build:
context: .
dockerfile: Dockerfile-bridgevmxgo
chain33:
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para33.toml"
expose:
- "8802"
ports:
- "8801:8801"
- "8901:8901"
chain32:
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para32.toml"
chain31:
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para31.toml"
chain30:
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para30.toml"
expose:
- "8802"
chain29:
entrypoint: /root/entrypoint.sh
environment:
PARAFILE: "/root/chain33.para29.toml"
nginx:
image: nginx:latest
depends_on:
- chain33
- chain30
- chain29
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf
expose:
- "8803"
\ No newline at end of file
This diff is collapsed.
#!/usr/bin/env bash
/root/chain33 -f /root/chain33.toml &
# to wait nginx start
sleep 15
/root/chain33 -f "$PARAFILE"
#user nobody;
worker_processes 1;
events {
#worker_connections 1024 may not enough
worker_connections 204800;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 1000;
#gzip on;
upstream chain33url{
ip_hash;
server chain33:8802 weight=1;
#server chain30:8802 weight=1;
}
server {
listen 8803 http2;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
location / {
#proxy_pass http://yankerp;
grpc_pass grpc://chain33url;
}
#error_page 404 /404.html;
# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
}
This diff is collapsed.
#!/usr/bin/env bash
# shellcheck disable=SC2128
# shellcheck source=/dev/null
set -x
set +e
source "./publicTest.sh"
source "./relayerPublic.sh"
# shellcheck disable=SC2120
function mainTest() {
kill_ebrelayer "chain33 -f"
sleep 2
# delete chain33 datadir
rm ../../datadir ../../logs -rf
local ganacheName=ganachetest
# shellcheck disable=SC2155
local isExit=$(docker inspect ${ganacheName} | jq ".[]" | jq ".Id")
if [[ ${isExit} != "" ]]; then
docker stop ${ganacheName}
docker rm ${ganacheName}
fi
kill_all_ebrelayer
cp ../../../plugin/dapp/cross2eth/ebrelayer/relayer.toml ./relayer.toml
}
mainTest "${1}"
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#!/usr/bin/env bash
# shellcheck disable=SC2128
# shellcheck source=/dev/null
set -x
set +e
# 主要在平行链上测试
source "./offlinePublic.sh"
# shellcheck disable=SC2034
{
# ETH 部署合约者的私钥 用于部署合约时签名使用
ethDeployAddr="0x8AFDADFC88a1087c9A1D6c0F5Dd04634b87F303a"
ethDeployKey="0x8656d2bc732a8a816a461ba5e2d8aac7c7f85c26a813df30d5327210465eb230"
# chain33 部署合约者的私钥 用于部署合约时签名使用
chain33DeployAddr="1JxhYLYsrscjTaQfaMoVUrnSdrejP7XRQD"
chain33DeployKey="0x9ef82623a5e9aac58d3a6b06392af66ec77289522b28896aed66abaaede66903"
# validatorsAddr=["0x92C8b16aFD6d423652559C6E266cBE1c29Bfd84f", "0x0df9a824699bc5878232c9e612fe1a5346a5a368", "0xcb074cb21cdddf3ce9c3c0a7ac4497d633c9d9f1", "0xd9dab021e74ecf475788ed7b61356056b2095830"]# shellcheck disable=SC2034
# eth 验证者私钥
ethValidatorAddra="0x92C8b16aFD6d423652559C6E266cBE1c29Bfd84f"
ethValidatorAddrb="0x0df9a824699bc5878232c9e612fe1a5346a5a368"
ethValidatorAddrc="0xcb074cb21cdddf3ce9c3c0a7ac4497d633c9d9f1"
ethValidatorAddrd="0xd9dab021e74ecf475788ed7b61356056b2095830"
ethValidatorAddrKeya="3fa21584ae2e4fd74db9b58e2386f5481607dfa4d7ba0617aaa7858e5025dc1e"
ethValidatorAddrKeyb="a5f3063552f4483cfc20ac4f40f45b798791379862219de9e915c64722c1d400"
ethValidatorAddrKeyc="bbf5e65539e9af0eb0cfac30bad475111054b09c11d668fc0731d54ea777471e"
ethValidatorAddrKeyd="c9fa31d7984edf81b8ef3b40c761f1847f6fcd5711ab2462da97dc458f1f896b"
# 新增地址 chain33 需要导入地址 转入 10 bty当收费费
chain33Validatora="1N6HstkyLFS8QCeVfdvYxx1xoryXoJtvvZ"
chain33Validatorb="155ooMPBTF8QQsGAknkK7ei5D78rwDEFe6"
chain33Validatorc="13zBdQwuyDh7cKN79oT2odkxYuDbgQiXFv"
chain33Validatord="113ZzVamKfAtGt9dq45fX1mNsEoDiN95HG"
chain33ValidatorKeya="0x027ca96466c71c7e7c5d73b7e1f43cb889b3bd65ebd2413eefd31c6709c262ae"
chain33ValidatorKeyb="0x9d539bc5fd084eb7fe86ad631dba9aa086dba38418725c38d9751459f567da66"
chain33ValidatorKeyc="0x0a6671f101e30a2cc2d79d77436b62cdf2664ed33eb631a9c9e3f3dd348a23be"
chain33ValidatorKeyd="0x3818b257b05ee75b6e43ee0e3cfc2d8502342cf67caed533e3756966690b62a5"
ethTestAddr1=0xbc333839E37bc7fAAD0137aBaE2275030555101f
ethTestAddrKey1=0x0c61f5a879d70807686e43eccc1f52987a15230ae0472902834af4d1933674f2
ethTestAddr2=0x495953A743ef169EC5D4aC7b5F786BF2Bd56aFd5
ethTestAddrKey2=0x2809477ede1261da21270096776ba7dc68b89c9df5f029965eaa5fe7f0b80697
ethReceiverAddr1="0xa4ea64a583f6e51c3799335b28a8f0529570a635"
#ethReceiverAddrKey1="355b876d7cbcb930d5dfab767f66336ce327e082cbaa1877210c1bae89b1df71"
chain33TestAddr1="1Cj1rqUenPmkeD6A8MGEzkBKQFN2H9yL3x"
chain33TestAddrKey1="0x7269a7a87d476310da37a9ca1ddc9333c9d7a0dfe1f2998b84758843a895433b"
chain33TestAddr2="1BCGLhdcdthNutQowV2YShuuN9fJRRGLxu"
chain33TestAddrKey2="0xb74acfd4eebbbd07bcae212baa7f094235ab8dc04f2f1d828681477b98b24008"
chain33ReceiverAddr="12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
chain33ReceiverAddrKey="4257d8692ef7fe13c68b65d6a52f03933db2fa5ce8faf210b5b8b80c721ced01"
chain33BridgeBank=""
ethBridgeBank=""
chain33BtyERC20TokenAddr="1111111111111111111114oLvT2"
chain33EthBridgeTokenAddr=""
ethereumBtyBridgeTokenAddr=""
chain33BycBridgeTokenAddr=""
ethereumBycERC20TokenAddr=""
BridgeRegistryOnChain33=""
chain33YccERC20TokenAddr=""
BridgeRegistryOnEth=""
ethereumYccBridgeTokenAddr=""
chain33ZbcERC20TokenAddr=""
ethereumZbcBridgeTokenAddr=""
multisignChain33Addr=""
multisignEthAddr=""
Chain33Cli=""
maturityDegree=10
chain33ID=0
}
# shellcheck disable=SC2120
function offline_set_offline_token_Bty() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
echo -e "${GRE}===== chain33 端 configLockedTokenOfflineSave BTY ======${NOC}"
# echo '2:#配置自动转离线钱包(bty, 100, 50%)'
local threshold=10000000000
local percents=50
if [[ $# -eq 2 ]]; then
threshold=$1
percents=$2
fi
# shellcheck disable=SC2086
${Boss4xCLI} chain33 offline set_offline_token -c "${chain33BridgeBank}" -s BTY -m ${threshold} -p ${percents} -k "${chain33DeployKey}" --chainID "${chain33ID}"
chain33_offline_send "chain33_set_offline_token.txt"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
# shellcheck disable=SC2120
function offline_set_offline_token_Chain33Ycc() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
echo -e "${GRE}===== chain33 端 configLockedTokenOfflineSave ERC20 YCC ======${NOC}"
# echo '2:#配置自动转离线钱包(YCC, 100, 60%)'
local threshold=10000000000
local percents=60
if [[ $# -eq 2 ]]; then
threshold=$1
percents=$2
fi
# shellcheck disable=SC2086
${Boss4xCLI} chain33 offline set_offline_token -c "${chain33BridgeBank}" -t "${chain33YccERC20TokenAddr}" -s YCC -m ${threshold} -p ${percents} -k "${chain33DeployKey}" --chainID "${chain33ID}"
chain33_offline_send "chain33_set_offline_token.txt"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
# shellcheck disable=SC2120
function offline_set_offline_token_Eth() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
# echo '2:#配置自动转离线钱包(eth, 20, 50%)'
local threshold=20
local percents=50
if [[ $# -eq 2 ]]; then
threshold=$1
percents=$2
fi
# shellcheck disable=SC2086
${Boss4xCLI} ethereum offline set_offline_token -s ETH -m ${threshold} -p ${percents} -c "${ethBridgeBank}" -d "${ethDeployAddr}"
ethereum_offline_sign_send "set_offline_token.txt"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
# shellcheck disable=SC2120
function offline_set_offline_token_EthYcc() {
echo -e "${GRE}=========== $FUNCNAME begin ===========${NOC}"
local threshold=100
local percents=40
if [[ $# -eq 2 ]]; then
threshold=$1
percents=$2
fi
# shellcheck disable=SC2086
${Boss4xCLI} ethereum offline set_offline_token -s BYC -m ${threshold} -p ${percents} -t "${ethereumBycERC20TokenAddr}" -c "${ethBridgeBank}" -d "${ethDeployAddr}"
ethereum_offline_sign_send "set_offline_token.txt"
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
function MainTest() {
set +e
chain33ID=0
chain33BridgeBank=15Myyvq97WinTWto8zcEdm838zXmvJKfnX
ethBridgeBank=0xC65B02a22B714b55D708518E2426a22ffB79113d
# ethereumBtyBridgeTokenAddr=0x9c3d40a44a2f61ef8d46fa8c7a731c08fb16ccef
# chain33EthBridgeTokenAddr=1JVFbJhFUWUNH41PxbV7NqwUd3F9BJ3nqV
ethereumBycERC20TokenAddr=0x20a32A5680EBf55740B0C98B54cDE8e6FD5a4FB0
# ethereumYccBridgeTokenAddr=0x05f3f31c7d53bcb71a6487dff3115d86370698bd
# chain33BycBridgeTokenAddr=1BdREGqsjbcKkvRheXWYKRq37vJHMs22Uy
chain33YccERC20TokenAddr=17yu1yULdGFddUz26PEeaHpJtkFGEpzYrA
# chain33ZbcERC20TokenAddr=1AqRwUa4T3q9DuCyUwn5ucHgtUhbUP2yfu
# ethereumZbcBridgeTokenAddr=0x89bb32184e466a9c8ea50c31174b575c2bcd64c2
dockerNamePrefix="build"
docker_chain33_ip=$(get_docker_addr "${dockerNamePrefix}_chain33_1")
# MainCli="./chain33-cli --rpc_laddr http://${docker_chain33_ip}:8801"
# Para8801Cli="./chain33-cli --rpc_laddr http://${docker_chain33_ip}:8901 --paraName user.p.para."
Para8901Cli="./chain33-cli --rpc_laddr http://${docker_chain33_ip}:8901 --paraName user.p.para."
# shellcheck disable=SC2034
{
CLIA="docker exec ${dockerNamePrefix}_ebrelayera_1 /root/ebcli_A"
CLIB="docker exec ${dockerNamePrefix}_ebrelayerb_1 /root/ebcli_A"
CLIC="docker exec ${dockerNamePrefix}_ebrelayerc_1 /root/ebcli_A"
CLID="docker exec ${dockerNamePrefix}_ebrelayerd_1 /root/ebcli_A"
docker_ganachetest_ip=$(get_docker_addr "${dockerNamePrefix}_ganachetest_1")
Boss4xCLI="docker exec ${dockerNamePrefix}_ebrelayera_1 /root/boss4x --rpc_laddr http://${docker_chain33_ip}:8901 --rpc_laddr_ethereum http://${docker_ganachetest_ip}:8545 --paraName user.p.para."
echo "${Boss4xCLI}"
}
# shellcheck disable=SC2034
Chain33Cli=${Para8901Cli}
# 离线多签地址转入阈值设大
offline_set_offline_token_Bty 100000000000000 10
offline_set_offline_token_Chain33Ycc 100000000000000 10
offline_set_offline_token_Eth 100000000000000 10
offline_set_offline_token_EthYcc 100000000000000 10
echo -e "${GRE}=========== $FUNCNAME end ===========${NOC}"
}
MainTest
#!/usr/bin/env bash
# shellcheck disable=SC2050
# shellcheck source=/dev/null
set -x
set +e
while [ 1 == 1 ]; do
sleep 100
done
Title="local"
TestNet=true
CoinSymbol="bty"
TxHeight=true
ChainID=33
# crypto模块配置
[crypto]
enableTypes=[] #设置启用的加密插件名称,不配置启用所有
[crypto.enableHeight] #配置已启用插件的启用高度,不配置采用默认高度0, 负数表示不启用
secp256k1=0
[crypto.sub.secp256k1] #支持插件子配置
[log]
# 日志级别,支持debug(dbug)/info/warn/error(eror)/crit
loglevel = "debug"
logConsoleLevel = "info"
# 日志文件名,可带目录,所有生成的日志文件都放到此目录下
logFile = "logs/chain33.log"
# 单个日志文件的最大值(单位:兆)
maxFileSize = 20
# 最多保存的历史日志文件个数
maxBackups = 20
# 最多保存的历史日志消息(单位:天)
maxAge = 28
# 日志文件名是否使用本地事件(否则使用UTC时间)
localTime = true
# 历史日志文件是否压缩(压缩格式为gz)
compress = false
# 是否打印调用源文件和行号
callerFile = true
# 是否打印调用方法
callerFunction = true
[blockchain]
defCacheSize=128
maxFetchBlockNum=128
timeoutSeconds=5
batchBlockNum=128
driver="leveldb"
dbPath="datadir"
dbCache=64
isStrongConsistency=true
singleMode=true
batchsync=false
isRecordBlockSequence=true
isParaChain=false
enableTxQuickIndex=true
# 使能精简localdb
enableReduceLocaldb=false
# 关闭分片存储,默认false为开启分片存储;平行链不需要分片需要修改此默认参数为true
disableShard=false
# 分片存储中每个大块包含的区块数
chunkblockNum=1000
# 使能从P2pStore中获取数据
enableFetchP2pstore=false
# 使能假设已删除已归档数据后,获取数据情况
enableIfDelLocalChunk=false
# 开启推送功能
enablePushSubscribe=true
[p2p]
types=[ "dht"]
enable=true
driver="leveldb"
dbPath="datadir/addrbook"
dbCache=4
grpcLogFile="grpc33.log"
[p2p.sub.dht]
port=13803
[rpc]
jrpcBindAddr="localhost:8801"
grpcBindAddr="localhost:8802"
whitelist=["127.0.0.1"]
jrpcFuncWhitelist=["*"]
grpcFuncWhitelist=["*"]
enableTLS=false
certFile="cert.pem"
keyFile="key.pem"
[mempool]
name="timeline"
poolCacheSize=10240
# 最小得交易手续费率,这个没有默认值,必填,一般是0.001 coins
minTxFeeRate=100000
# 最大的交易手续费率, 0.1 coins
maxTxFeeRate=10000000
# 单笔交易最大的手续费, 10 coins
maxTxFee=1000000000
maxTxNumPerAccount=100
isLevelFee=false
[mempool.sub.timeline]
poolCacheSize=10240
[mempool.sub.score]
poolCacheSize=10240
timeParam=1 #时间占价格比例
priceConstant=1544 #手续费相对于时间的一个合适的常量,取当前unxi时间戳前四位数,排序时手续费高1e-5~=快1s
pricePower=1 #常量比例
[mempool.sub.price]
poolCacheSize=10240
[consensus]
name="solo"
minerstart=true
genesisBlockTime=1514533394
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
minerExecs=["ticket", "autonomy"]
[mver.consensus]
fundKeyAddr = "1BQXS6TxaYYG5mADaWij4AxhZZUTpw95a5"
powLimitBits = "0x1f00ffff"
maxTxNumber = 1600 #160
[mver.consensus.ForkChainParamV1]
maxTxNumber = 10000
[mver.consensus.ForkChainParamV2]
powLimitBits = "0x1f2fffff"
[mver.consensus.ForkTicketFundAddrV1]
fundKeyAddr = "1Ji3W12KGScCM7C2p8bg635sNkayDM8MGY"
[mver.consensus.ticket]
coinReward = 18
coinDevFund = 12
ticketPrice = 10000
retargetAdjustmentFactor = 4
futureBlockTime = 16
ticketFrozenTime = 5 #5s only for test
ticketWithdrawTime = 10 #10s only for test
ticketMinerWaitTime = 2 #2s only for test
targetTimespan = 2304
targetTimePerBlock = 16
[mver.consensus.ticket.ForkChainParamV1]
targetTimespan = 288 #only for test
targetTimePerBlock = 2
[consensus.sub.solo]
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
genesisBlockTime=1514533394
hotkeyAddr="12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
waitTxMs=10
[consensus.sub.ticket]
genesisBlockTime=1514533394
[[consensus.sub.ticket.genesis]]
minerAddr="12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv"
returnAddr="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
count=10000
[[consensus.sub.ticket.genesis]]
minerAddr="1PUiGcbsccfxW3zuvHXZBJfznziph5miAo"
returnAddr="1EbDHAXpoiewjPLX9uqoz38HsKqMXayZrF"
count=10000
[[consensus.sub.ticket.genesis]]
minerAddr="1EDnnePAZN48aC2hiTDzhkczfF39g1pZZX"
returnAddr="1KcCVZLSQYRUwE5EXTsAoQs9LuJW6xwfQa"
count=10000
[store]
name="mavl"
driver="leveldb"
dbPath="datadir/mavltree"
dbCache=128
[store.sub.mavl]
enableMavlPrefix=false
enableMVCC=false
enableMavlPrune=false
pruneHeight=10000
# 是否使能mavl数据载入内存
enableMemTree=false
# 是否使能mavl叶子节点数据载入内存
enableMemVal=false
# 缓存close ticket数目,该缓存越大同步速度越快,最大设置到1500000
tkCloseCacheLen=100000
[wallet]
minFee=1000000
driver="leveldb"
dbPath="datadir/wallet"
dbCache=16
signType="secp256k1"
coinType="bty"
[wallet.sub.ticket]
minerwhitelist=["*"]
[exec]
enableStat=false
enableMVCC=false
[exec.sub.token]
saveTokenTxList=true
tokenApprs = [
"1Bsg9j6gW83sShoee1fZAt9TkUjcrCgA9S",
"1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK",
"1LY8GFia5EiyoTodMLfkB5PHNNpXRqxhyB",
"1GCzJDS6HbgTQ2emade7mEJGGWFfA15pS9",
"1JYB8sxi4He5pZWHCd3Zi2nypQ4JMB6AxN",
"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv",
]
[exec.sub.relay]
genesis="14KEKbYtKKQm4wMthSK9J4La4nAiidGozt"
[exec.sub.cert]
# 是否启用证书验证和签名
enable=false
# 加密文件路径
cryptoPath="authdir/crypto"
# 带证书签名类型,支持"auth_ecdsa", "auth_sm2"
signType="auth_ecdsa"
[exec.sub.manage]
superManager=[
"1Bsg9j6gW83sShoee1fZAt9TkUjcrCgA9S",
"12qyocayNF7Lv6C9qW4avxs2E7U41fKSfv",
"1Q8hGLfoGe63efeWa8fJ4Pnukhkngt6poK"
]
[exec.sub.autonomy]
total="16htvcBNSEA7fZhAdLJphDwQRQJaHpyHTp"
useBalance=false
[health]
listenAddr="localhost:8805"
checkInterval=1
unSyncMaxTimes=2
[metrics]
#是否使能发送metrics数据的发送
enableMetrics=false
#数据保存模式
dataEmitMode="influxdb"
[metrics.sub.influxdb]
#以纳秒为单位的发送间隔
duration=1000000000
url="http://influxdb:8086"
database="chain33metrics"
username=""
password=""
namespace=""
#!/usr/bin/env bash
# shellcheck disable=SC2128
# shellcheck source=/dev/null
#source "./dockerRelayerTest.sh"
source "./dockerRelayerTestEvm.sh"
#source "./dockerRelayerTestInfinite.sh"
source "./paracrosstestcase.sh"
function bridgevmxgo() {
if [ "${2}" == "init" ]; then
para_init "${3}"
elif [ "${2}" == "config" ]; then
para_set_wallet
para_transfer
elif [ "${2}" == "test" ]; then
echo "========================== bridgevmxgo test =========================="
set +e
set -x
para_create_nodegroup
AllRelayerMainTest 10
# perf_test_main 1
echo "========================== bridgevmxgo test end =========================="
fi
}
#!/usr/bin/env bash
#shellcheck disable=SC2128
#shellcheck source=/dev/null
set -x
source ../dapp-test-common.sh
MAIN_HTTP=""
function rpc_test() {
chain33_RpcTestBegin bridgevmxgo
MAIN_HTTP="$1"
echo "main_ip=$MAIN_HTTP"
chain33_RpcTestRst bridgevmxgo "$CASE_ERR"
}
chain33_debug_function rpc_test "$1" "$2"
pragma solidity ^0.5.0;
import "./GoAssetBank.sol";
import "./EvmAssetBank.sol";
import "../Oracle.sol";
import "../GoAssetBridge.sol";
/**
* @title BridgeBank
* @dev Bank contract which coordinates asset-related functionality.
* GoAssetBank manages the minting and burning of tokens which
* represent go contract issued assets, while EvmAssetBank manages
* the locking and unlocking of Chain33 and ERC20 token assets
* based on Chain33.
**/
contract BridgeBank is GoAssetBank, EvmAssetBank {
using SafeMath for uint256;
address public operator;
Oracle public oracle;
GoAssetBridge public goAssetBridge;
/*
* @dev: Constructor, sets operator
*/
constructor (
address _operatorAddress,
address _oracleAddress,
address _goAssetBridgeAddress
)
public
{
operator = _operatorAddress;
oracle = Oracle(_oracleAddress);
goAssetBridge = GoAssetBridge(_goAssetBridgeAddress);
}
/*
* @dev: Modifier to restrict access to operator
*/
modifier onlyOperator() {
require(
msg.sender == operator,
'Must be BridgeBank operator.'
);
_;
}
/*
* @dev: Modifier to restrict access to Offline
*/
modifier onlyOffline() {
require(
msg.sender == offlineSave,
'Must be onlyOffline.'
);
_;
}
/*
* @dev: Modifier to restrict access to the oracle
*/
modifier onlyOracle()
{
require(
msg.sender == address(oracle),
"Access restricted to the oracle"
);
_;
}
/*
* @dev: Modifier to restrict access to the goAsset bridge
*/
modifier onlyGoAssetBridge()
{
require(
msg.sender == address(goAssetBridge),
"Access restricted to the goAsset bridge"
);
_;
}
/*
* @dev: Modifier to make sure this symbol not created now
*/
modifier onlyBridgeToken(address _token)
{
require(
(address(0) != _token) && (msg.value == 0),
"Only bridge token could be locked and tranfer to contract:evmxgo"
);
_;
}
/*
* @dev: Fallback function allows operator to send funds to the bank directly
* This feature is used for testing and is available at the operator's own risk.
*/
function() external payable onlyOffline {}
/*
* @dev: Creates a new BridgeToken
*
* @param _symbol: The new BridgeToken's symbol
* @return: The new BridgeToken contract's address
*/
function createNewBridgeToken(
string memory _symbol
)
public
onlyOperator
returns(address)
{
return deployNewBridgeToken(_symbol);
}
/*
* @dev: Mints new BankTokens
*
* @param _goAssetSender: The goAsset sender's address.
* @param _chain33Recipient: The intended recipient's Chain33 address.
* @param _bridgeTokenAddress: The bridge token address
* @param _symbol: goAsset token symbol
* @param _amount: number of goAsset tokens to be minted
*/
function mintBridgeTokens(
address _goAssetSender,
address payable _intendedRecipient,
address _bridgeTokenAddress,
string memory _symbol,
uint256 _amount
)
public
onlyGoAssetBridge
{
return mintNewBridgeTokens(
_goAssetSender,
_intendedRecipient,
_bridgeTokenAddress,
_symbol,
_amount
);
}
/*
* @dev: Burns bank tokens
*
* @param _goAssetReceiver: The _goAsset receiver address in bytes.
* @param _goAssetTokenAddress: The currency type
* @param _amount: number of goAsset tokens to be burned
*/
function burnBridgeTokens(address _goAssetReceiver, address _goAssetTokenAddress, uint256 _amount) public
{
return burnGoAssetTokens(
msg.sender,
_goAssetReceiver,
_goAssetTokenAddress,
_amount
);
}
/*
* @dev: addToken2LockList used to add token with the specified address to be
* allowed locked from GoAsset
*
* @param _token: token contract address
* @param _symbol: token symbol
*/
function addToken2LockList(
address _token,
string memory _symbol
)
public
onlyOperator
{
addToken2AllowLock(_token, _symbol);
}
/*
* @dev: configTokenOfflineSave used to config threshold to trigger tranfer token to offline account
* when the balance of locked token reaches
*
* @param _token: token contract address
* @param _symbol:token symbol,just used for double check that token address and symbol is consistent
* @param _threshold: _threshold to trigger transfer
* @param _percents: amount to transfer per percents of threshold
*/
function configLockedTokenOfflineSave(
address _token,
string memory _symbol,
uint256 _threshold,
uint8 _percents
)
public
onlyOperator
{
if (address(0) != _token) {
require(keccak256(bytes(BridgeToken(_token).symbol())) == keccak256(bytes(_symbol)), "token address and symbol is not consistent");
} else {
require(keccak256(bytes("BTY")) == keccak256(bytes(_symbol)), "token address and symbol is not consistent");
}
configOfflineSave4Lock(_token, _symbol, _threshold, _percents);
}
/*
* @dev: configOfflineSaveAccount used to config offline account to receive token
* when the balance of locked token reaches threshold
*
* @param _offlineSave: receiver address
*/
function configOfflineSaveAccount(address payable _offlineSave) public onlyOperator
{
offlineSave = _offlineSave;
}
/*
* @dev: Locks received Chain33 funds.
*
* @param _recipient: bytes representation of destination address.
* @param _token: token address in origin chain (0x0 if chain33)
* @param _amount: value of deposit
*/
function lock(
address _recipient,
address _token,
uint256 _amount
)
public
availableNonce()
onlyBridgeToken(_token)
payable
{
string memory symbol;
require(
BridgeToken(_token).transferFrom(msg.sender, address(this), _amount),
"Contract token allowances insufficient to complete this lock request"
);
// Set symbol to the ERC20 token's symbol
symbol = BridgeToken(_token).symbol();
require(
tokenAllow2Lock[keccak256(abi.encodePacked(symbol))] == _token,
'The token is not allowed to be locked from Chain33.'
);
lockFunds(
msg.sender,
_recipient,
_token,
symbol,
_amount
);
}
/*
* @dev: Unlocks Chain33 and ERC20 tokens held on the contract.
*
* @param _recipient: recipient's Chain33 address
* @param _token: token contract address
* @param _symbol: token symbol
* @param _amount: wei amount or ERC20 token count
\ */
function unlock(
address payable _recipient,
address _token,
string memory _symbol,
uint256 _amount
)
public
onlyGoAssetBridge
hasLockedFunds(
_token,
_amount
)
canDeliver(
_token,
_amount
)
{
unlockFunds(
_recipient,
_token,
_symbol,
_amount
);
}
/*
* @dev: Exposes an item's current status.
*
* @param _id: The item in question.
* @return: Boolean indicating the lock status.
*/
function getGoAssetDepositStatus(
bytes32 _id
)
public
view
returns(bool)
{
return isLockedGoAssetDeposit(_id);
}
/*
* @dev: Allows access to a GoAsset deposit's information via its unique identifier.
*
* @param _id: The deposit to be viewed.
* @return: Original sender's Chain33 address.
* @return: Intended GoAsset recipient's address in bytes.
* @return: The lock deposit's currency, denoted by a token address.
* @return: The amount locked in the deposit.
* @return: The deposit's unique nonce.
*/
function viewGoAssetDeposit(
bytes32 _id
)
public
view
returns(address, address payable, address, uint256)
{
return getGoAssetDeposit(_id);
}
}
\ No newline at end of file
pragma solidity ^0.5.0;
import "../../openzeppelin-solidity/contracts/token/ERC20/ERC20Mintable.sol";
import "../../openzeppelin-solidity/contracts/token/ERC20/ERC20Burnable.sol";
import "../../openzeppelin-solidity/contracts/token/ERC20/ERC20Detailed.sol";
/**
* @title BridgeToken
* @dev Mintable, ERC20 compatible BankToken for use by BridgeBank
**/
contract BridgeToken is ERC20Mintable, ERC20Burnable, ERC20Detailed {
constructor(
string memory _symbol
)
public
ERC20Detailed(
_symbol,
_symbol,
8
)
{
// Intentionally left blank
}
}
\ No newline at end of file
pragma solidity ^0.5.0;
import "../../openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./BridgeToken.sol";
/*
* @title: EvmAssetBank
* @dev: EvmAsset bank which locks Chain33/ERC20 token deposits, and unlocks
* Chain33/ERC20 tokens once the prophecy has been successfully processed.
* @dev:当emv资产转移到go合约时,用于锁定资产;
* 当emv资产从go合约进行提币时,用于解锁资产;
*/
contract EvmAssetBank {
using SafeMath for uint256;
address payable public offlineSave;
uint256 public lockNonce;
mapping(address => uint256) public lockedFunds;
mapping(bytes32 => address) public tokenAllow2Lock;
mapping(address => OfflineSaveCfg) public offlineSaveCfgs;
uint8 public lowThreshold = 5;
uint8 public highThreshold = 80;
struct OfflineSaveCfg {
address token;
string symbol;
uint256 _threshold;
uint8 _percents;
}
/*
* @dev: Event declarations
*/
event LogLock(
address _from,
address _to,
address _token,
string _symbol,
uint256 _value,
uint256 _nonce
);
event LogUnlock(
address _to,
address _token,
string _symbol,
uint256 _value
);
/*
* @dev: Modifier declarations
*/
modifier hasLockedFunds(
address _token,
uint256 _amount
) {
require(
lockedFunds[_token] >= _amount,
"The Bank does not hold enough locked tokens to fulfill this request."
);
_;
}
modifier canDeliver(
address _token,
uint256 _amount
)
{
if(_token == address(0)) {
require(
address(this).balance >= _amount,
'Insufficient Chain33 balance for delivery.'
);
} else {
require(
BridgeToken(_token).balanceOf(address(this)) >= _amount,
'Insufficient ERC20 token balance for delivery.'
);
}
_;
}
modifier availableNonce() {
require(
lockNonce + 1 > lockNonce,
'No available nonces.'
);
_;
}
/*
* @dev: Constructor which sets the lock nonce
*/
constructor()
public
{
lockNonce = 0;
}
/*
* @dev: addToken2AllowLock used to add token with the specified address to be
* allowed locked from GoAsset
*
* @param _token: token contract address
* @param _symbol: token symbol
*/
function addToken2AllowLock(
address _token,
string memory _symbol
)
internal
{
bytes32 symHash = keccak256(abi.encodePacked(_symbol));
address tokenQuery = tokenAllow2Lock[symHash];
require(tokenQuery == address(0), 'The token with the same symbol has been added to lock allow list already.');
tokenAllow2Lock[symHash] = _token;
}
/*
* @dev: addToken2AllowLock used to add token with the specified address to be
* allowed locked from GoAsset
*
* @param _symbol: token symbol
*/
function getLockedTokenAddress(string memory _symbol) public view returns(address)
{
bytes32 symHash = keccak256(abi.encodePacked(_symbol));
return tokenAllow2Lock[symHash];
}
/*
* @dev: configOfflineSave4Lock used to config threshold to trigger tranfer token to offline account
* when the balance of locked token reaches
*
* @param _token: token contract address
* @param _symbol:token symbol,just used for double check that token address and symbol is consistent
* @param _threshold: _threshold to trigger transfer
* @param _percents: amount to transfer per percents of threshold
*/
function configOfflineSave4Lock(
address _token,
string memory _symbol,
uint256 _threshold,
uint8 _percents
)
internal
{
require(
_percents >= lowThreshold && _percents <= highThreshold,
"The percents to trigger should within range [5, 80]"
);
OfflineSaveCfg memory offlineSaveCfg = OfflineSaveCfg(
_token,
_symbol,
_threshold,
_percents
);
offlineSaveCfgs[_token] = offlineSaveCfg;
}
/*
* @dev: getofflineSaveCfg used to get token's offline save configuration
*
* @param _token: token contract address
*/
function getofflineSaveCfg(address _token) public view returns(uint256, uint8)
{
OfflineSaveCfg memory offlineSaveCfg = offlineSaveCfgs[_token];
return (offlineSaveCfg._threshold, offlineSaveCfg._percents);
}
/*
* @dev: Creates a new Chain33 deposit with a unique id.
*
* @param _sender: The sender's Chain33 address.
* @param _recipient: The intended recipient's Chain33 address.
* @param _token: The currency type, either erc20 or Chain33.
* @param _amount: The amount of erc20 tokens/ Chain33 (in wei) to be itemized.
*/
function lockFunds(
address payable _sender,
address _recipient,
address _token,
string memory _symbol,
uint256 _amount
)
internal
{
// Incerment the lock nonce
lockNonce = lockNonce.add(1);
// Increment locked funds by the amount of tokens to be locked
lockedFunds[_token] = lockedFunds[_token].add(_amount);
emit LogLock(
_sender,
_recipient,
_token,
_symbol,
_amount,
lockNonce
);
if (address(0) == offlineSave) {
return;
}
uint256 balance;
if (address(0) == _token) {
balance = address(this).balance;
} else {
balance = BridgeToken(_token).balanceOf(address(this));
}
OfflineSaveCfg memory offlineSaveCfg = offlineSaveCfgs[_token];
//check not zero,so configured already
if (offlineSaveCfg._percents < lowThreshold) {
return;
}
if (balance < offlineSaveCfg._threshold ) {
return;
}
uint256 amount = offlineSaveCfg._percents * balance / 100;
if (address(0) == _token) {
offlineSave.transfer(amount);
} else {
require(BridgeToken(_token).transfer(offlineSave, amount), "Erc20 Token Transfer to offline Save account failed");
}
}
/*
* @dev: Unlocks funds held on contract and sends them to the
* intended recipient
*
* @param _recipient: recipient's Chain33 address
* @param _token: token contract address
* @param _symbol: token symbol
* @param _amount: wei amount or ERC20 token count
*/
function unlockFunds(
address payable _recipient,
address _token,
string memory _symbol,
uint256 _amount
)
internal
{
// Decrement locked funds mapping by the amount of tokens to be unlocked
lockedFunds[_token] = lockedFunds[_token].sub(_amount);
// Transfer funds to intended recipient
if (_token == address(0)) {
_recipient.transfer(_amount);
} else {
require(
BridgeToken(_token).transfer(_recipient, _amount),
"Token transfer failed"
);
}
emit LogUnlock(
_recipient,
_token,
_symbol,
_amount
);
}
}
This diff is collapsed.
pragma solidity ^0.5.0;
contract BridgeRegistry {
address public goAssetBridge;
address public bridgeBank;
address public oracle;
address public valset;
uint256 public deployHeight;
event LogContractsRegistered(
address _goAssetBridge,
address _bridgeBank,
address _oracle,
address _valset
);
constructor(
address _goAssetBridge,
address _bridgeBank,
address _oracle,
address _valset
)
public
{
goAssetBridge = _goAssetBridge;
bridgeBank = _bridgeBank;
oracle = _oracle;
valset = _valset;
deployHeight = block.number;
emit LogContractsRegistered(
goAssetBridge,
bridgeBank,
oracle,
valset
);
}
}
\ No newline at end of file
pragma solidity ^0.5.0;
import "../openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./Valset.sol";
import "./BridgeBank/BridgeBank.sol";
contract GoAssetBridge {
using SafeMath for uint256;
/*
* @dev: Public variable declarations
*/
address public operator;
Valset public valset;
address public oracle;
bool public hasOracle;
BridgeBank public bridgeBank;
bool public hasBridgeBank;
uint256 public prophecyClaimCount;
mapping(bytes32 => ProphecyClaim) public prophecyClaims;
enum Status {
Null,
Pending,
Success,
Failed
}
enum ClaimType {
Unsupported,
Burn,
Lock
}
struct ProphecyClaim {
ClaimType claimType;
address goAssetSender;
address payable chain33Receiver;
address originalValidator;
address tokenAddress;
string symbol;
uint256 amount;
Status status;
}
/*
* @dev: Event declarations
*/
event LogOracleSet(
address _oracle
);
event LogBridgeBankSet(
address _bridgeBank
);
event LogNewProphecyClaim(
uint256 _prophecyID,
ClaimType _claimType,
address _goAssetSender,
address payable _chain33Receiver,
address _validatorAddress,
address _tokenAddress,
string _symbol,
uint256 _amount
);
event LogProphecyCompleted(
bytes32 _claimID,
ClaimType _claimType
);
/*
* @dev: Modifier which only allows access to currently pending prophecies
*/
modifier isPending(
bytes32 _claimID
)
{
require(
isProphecyClaimActive(_claimID),
"Prophecy claim is not active"
);
_;
}
/*
* @dev: Modifier to restrict access to the operator.
*/
modifier onlyOperator()
{
require(
msg.sender == operator,
'Must be the operator.'
);
_;
}
/*
* @dev: Modifier to restrict access to the oracle.
*/
modifier onlyOracle()
{
require(
msg.sender == oracle,
'Must be the oracle.'
);
_;
}
/*
* @dev: The bridge is not active until oracle and bridge bank are set
*/
modifier isActive()
{
require(
hasOracle == true && hasBridgeBank == true,
"The Operator must set the oracle and bridge bank for bridge activation"
);
_;
}
/*
* @dev: Modifier to make sure the claim type is valid
*/
modifier validClaimType(
ClaimType _claimType
)
{
require(
_claimType == ClaimType.Burn || _claimType == ClaimType.Lock,
"The claim type must be ClaimType.Burn or ClaimType.Lock"
);
_;
}
/*
* @dev: Constructor
*/
constructor(
address _operator,
address _valset
)
public
{
prophecyClaimCount = 0;
operator = _operator;
valset = Valset(_valset);
hasOracle = false;
hasBridgeBank = false;
}
/*
* @dev: setOracle
*/
function setOracle(
address _oracle
)
public
onlyOperator
{
require(
!hasOracle,
"The Oracle cannot be updated once it has been set"
);
hasOracle = true;
oracle = _oracle;
emit LogOracleSet(
oracle
);
}
/*
* @dev: setBridgeBank
*/
function setBridgeBank(
address payable _bridgeBank
)
public
onlyOperator
{
require(
!hasBridgeBank,
"The Bridge Bank cannot be updated once it has been set"
);
hasBridgeBank = true;
bridgeBank = BridgeBank(_bridgeBank);
emit LogBridgeBankSet(
address(bridgeBank)
);
}
/*
* @dev: setNewProphecyClaim
* Sets a new burn or lock prophecy claim, adding it to the prophecyClaims mapping.
* Lock claims can only be created for BridgeTokens on BridgeBank's whitelist. The operator
* is responsible for adding them, and lock claims will fail until the operator has done so.
*/
function setNewProphecyClaim(
bytes32 _claimID,
uint8 _claimType,
address _goAssetSender,
address payable _chain33Receiver,
address _originalValidator,
address _tokenAddress,
string memory _symbol,
uint256 _amount
)
public
isActive
onlyOracle
{
// Increment the prophecy claim count
prophecyClaimCount = prophecyClaimCount.add(1);
ClaimType claimType = ClaimType(_claimType);
//overwrite the token address in case of lock
if (claimType == ClaimType.Lock) {
_tokenAddress = bridgeBank.getToken2address(_symbol);
}
// Create the new ProphecyClaim
ProphecyClaim memory prophecyClaim = ProphecyClaim(
claimType,
_goAssetSender,
_chain33Receiver,
_originalValidator,
_tokenAddress,
_symbol,
_amount,
Status.Pending
);
// Add the new ProphecyClaim to the mapping
prophecyClaims[_claimID] = prophecyClaim;
emit LogNewProphecyClaim(
prophecyClaimCount,
claimType,
_goAssetSender,
_chain33Receiver,
_originalValidator,
_tokenAddress,
_symbol,
_amount
);
}
/*
* @dev: completeClaim
* Allows for the completion of ProphecyClaims once processed by the Oracle.
* Burn claims unlock tokens stored by BridgeBank.
* Lock claims mint BridgeTokens on BridgeBank's token whitelist.
*/
function completeClaim(
bytes32 _claimID
)
public
isPending(_claimID)
{
require(
msg.sender == oracle,
"Only the Oracle may complete prophecies"
);
prophecyClaims[_claimID].status = Status.Success;
ClaimType claimType = prophecyClaims[_claimID].claimType;
if(claimType == ClaimType.Burn) {
unlockTokens(_claimID);
} else {
issueBridgeTokens(_claimID);
}
emit LogProphecyCompleted(
_claimID,
claimType
);
}
/*
* @dev: issueBridgeTokens
* Issues a request for the BridgeBank to mint new BridgeTokens
*/
function issueBridgeTokens(
bytes32 _claimID
)
internal
{
ProphecyClaim memory prophecyClaim = prophecyClaims[_claimID];
bridgeBank.mintBridgeTokens(
prophecyClaim.goAssetSender,
prophecyClaim.chain33Receiver,
prophecyClaim.tokenAddress,
prophecyClaim.symbol,
prophecyClaim.amount
);
}
/*
* @dev: unlockTokens
* Issues a request for the BridgeBank to unlock funds held on contract
*/
function unlockTokens(
bytes32 _claimID
)
internal
{
ProphecyClaim memory prophecyClaim = prophecyClaims[_claimID];
bridgeBank.unlock(
prophecyClaim.chain33Receiver,
prophecyClaim.tokenAddress,
prophecyClaim.symbol,
prophecyClaim.amount
);
}
/*
* @dev: isProphecyClaimActive
* Returns boolean indicating if the ProphecyClaim is active
*/
function isProphecyClaimActive(
bytes32 _claimID
)
public
view
returns(bool)
{
return prophecyClaims[_claimID].status == Status.Pending;
}
/*
* @dev: isProphecyValidatorActive
* Returns boolean indicating if the validator that originally
* submitted the ProphecyClaim is still an active validator
*/
function isProphecyClaimValidatorActive(
bytes32 _claimID
)
public
view
returns(bool)
{
return valset.isActiveValidator(
prophecyClaims[_claimID].originalValidator
);
}
/*
* @dev: Modifier to make sure the claim type is valid
*/
function isValidClaimType(uint8 _claimType) public pure returns(bool)
{
ClaimType claimType = ClaimType(_claimType);
if (claimType == ClaimType.Burn || claimType == ClaimType.Lock) {
return true;
}
return false;
}
}
##solc 使用版本为:Version: 0.5.16
##编译solidity,并产生bin文件,abi文件,和相应的go文件
SRC_CONTRACT0 := .
GO_OUT0 := ${SRC_CONTRACT0}/generated
PACKAGE := generated
proj := "build"
.PHONY: default build clean registry bridgeBank
default: depends build
build: depends
@abigen --sol $(SRC_CONTRACT0)/BridgeRegistry.sol --pkg $(PACKAGE) --out $(GO_OUT0)/BridgeRegistry.go
@abigen --sol $(SRC_CONTRACT0)/BridgeBank/BridgeBank.sol --pkg $(PACKAGE) --out $(GO_OUT0)/BridgeBank.go
clean:
@rm -fr $(GO_OUT)/*
registry0:
@abigen --sol $(SRC_CONTRACT0)/BridgeRegistry.sol --pkg $(PACKAGE) --out $(GO_OUT0)/BridgeRegistry.go
bridgeBank0:
@abigen --sol $(SRC_CONTRACT0)/BridgeBank/BridgeBank.sol --pkg $(PACKAGE) --out $(GO_OUT0)/BridgeBank.go
asmExample:
@solc --asm --bin -o tmp/ valset-bin=./tmp/valset-bin Valset.sol
depends:
if ! [ -d openzeppelin-solidity ]; then \
echo "not exist openzeppelin-solidity and going to get" ; \
go get github.com/OpenZeppelin/openzeppelin-contracts@v2.5 ; \
mkdir openzeppelin-solidity ;\
cp -r ${GOPATH}/pkg/mod/github.com/\!open\!zeppelin/openzeppelin-contracts@v2.5.0+incompatible/contracts openzeppelin-solidity ; \
fi; \
pragma solidity ^0.5.0;
import "../openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./Valset.sol";
import "./GoAssetBridge.sol";
contract Oracle {
using SafeMath for uint256;
/*
* @dev: Public variable declarations
*/
GoAssetBridge public goAssetBridge;
Valset public valset;
address public operator;
// Tracks the number of OracleClaims made on an individual BridgeClaim
mapping(bytes32 => address[]) public oracleClaimValidators;
mapping(bytes32 => mapping(address => bool)) public hasMadeClaim;
enum ClaimType {
Unsupported,
Burn,
Lock
}
/*
* @dev: Event declarations
*/
event LogNewOracleClaim(
bytes32 _claimID,
address _validatorAddress,
bytes _signature
);
event LogProphecyProcessed(
bytes32 _claimID,
uint256 _weightedSignedPower,
uint256 _weightedTotalPower,
address _submitter
);
/*
* @dev: Modifier to restrict access to the operator.
*/
modifier onlyOperator()
{
require(
msg.sender == operator,
'Must be the operator.'
);
_;
}
/*
* @dev: Modifier to restrict access to current ValSet validators
*/
modifier onlyValidator()
{
require(
valset.isActiveValidator(msg.sender),
"Must be an active validator"
);
_;
}
/*
* @dev: Modifier to restrict access to current ValSet validators
*/
modifier isPending(
bytes32 _claimID
)
{
require(
goAssetBridge.isProphecyClaimActive(
_claimID
) == true,
"The prophecy must be pending for this operation"
);
_;
}
/*
* @dev: Modifier to restrict the claim type must be burn or lock
*/
modifier isValidClaimType(
ClaimType _claimType
)
{
require(
goAssetBridge.isValidClaimType(
uint8(_claimType)
) == true,
"The claim type must be burn or lock"
);
_;
}
/*
* @dev: Constructor
*/
constructor(
address _operator,
address _valset,
address _goAssetBridge
)
public
{
operator = _operator;
goAssetBridge = GoAssetBridge(_goAssetBridge);
valset = Valset(_valset);
}
/*
* @dev: newOracleClaim
* Allows validators to make new OracleClaims on goAsset lock/burn prophecy,
* if the required vote power reached,just make it processed
* @param _claimType: burn or lock,
* @param _goAssetSender: goAsset sender,
* @param _chain33Receiver: receiver on chain33
* @param _tokenAddress: token address
* @param _symbol: token symbol
* @param _amount: amount
* @param _claimID: claim id
* @param _message: message for verifying
* @param _signature: need to recover sender
*/
function newOracleClaim(
ClaimType _claimType,
address _goAssetSender,
address payable _chain33Receiver,
address _tokenAddress,
string memory _symbol,
uint256 _amount,
bytes32 _claimID,
bytes memory _signature
)
public
onlyValidator
isValidClaimType(_claimType)
{
address validatorAddress = msg.sender;
// Validate the msg.sender's signature
require(
validatorAddress == valset.recover(
_claimID,
_signature
),
"Invalid _claimID signature."
);
// Confirm that this address has not already made an oracle claim on this _ClaimID
require(
!hasMadeClaim[_claimID][validatorAddress],
"Cannot make duplicate oracle claims from the same address."
);
if (oracleClaimValidators[_claimID].length == 0) {
goAssetBridge.setNewProphecyClaim(
_claimID,
uint8(_claimType),
_goAssetSender,
_chain33Receiver,
validatorAddress,
_tokenAddress,
_symbol,
_amount);
}
hasMadeClaim[_claimID][validatorAddress] = true;
oracleClaimValidators[_claimID].push(validatorAddress);
emit LogNewOracleClaim(
_claimID,
validatorAddress,
_signature
);
(bool valid, uint256 weightedSignedPower, uint256 weightedTotalPower ) = getClaimThreshold(_claimID);
if (true == valid) {
//if processed already,just emit an event
if (goAssetBridge.isProphecyClaimActive(_claimID) == true) {
completeClaim(_claimID);
}
emit LogProphecyProcessed(
_claimID,
weightedSignedPower,
weightedTotalPower,
msg.sender
);
}
}
/*
* @dev: checkBridgeProphecy
* Operator accessor method which checks if a prophecy has passed
* the validity threshold, without actually completing the prophecy.
*/
function checkBridgeProphecy(
bytes32 _claimID
)
public
view
onlyOperator
isPending(_claimID)
returns(bool, uint256, uint256)
{
require(
goAssetBridge.isProphecyClaimActive(
_claimID
) == true,
"Can only check active prophecies"
);
return getClaimThreshold(
_claimID
);
}
/*
* @dev: getClaimThreshold
* Calculates the status of a claim. The claim is considered valid if the
* combined active signatory validator powers pass the validation threshold.
* The hardcoded threshold is (Combined signed power * 2) >= (Total power * 3).
*/
function getClaimThreshold(
bytes32 _claimID
)
internal
view
returns(bool, uint256, uint256)
{
uint256 signedPower = 0;
uint256 totalPower = valset.totalPower();
// Iterate over the signatory addresses
for (uint256 i = 0; i < oracleClaimValidators[_claimID].length; i = i.add(1)) {
address signer = oracleClaimValidators[_claimID][i];
// Only add the power of active validators
if(valset.isActiveValidator(signer)) {
signedPower = signedPower.add(
valset.getValidatorPower(
signer
)
);
}
}
// Calculate if weighted signed power has reached threshold of weighted total power
uint256 weightedSignedPower = signedPower.mul(3);
uint256 weightedTotalPower = totalPower.mul(2);
bool hasReachedThreshold = weightedSignedPower >= weightedTotalPower;
return(
hasReachedThreshold,
weightedSignedPower,
weightedTotalPower
);
}
/*
* @dev: completeClaim
* Completes a claim by completing the corresponding BridgeClaim
* on the GoAssetBridge.
*/
function completeClaim(
bytes32 _claimID
)
internal
{
goAssetBridge.completeClaim(
_claimID
);
}
}
\ No newline at end of file
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed.
......@@ -8,6 +8,7 @@ strapp=${strcmd%/cmd*}
SRC_EBCLI=github.com/33cn/plugin/plugin/dapp/cross2eth/ebcli
SRC_EBRELAYER=github.com/33cn/plugin/plugin/dapp/cross2eth/ebrelayer
SRC_BOSS4XCLI=github.com/33cn/plugin/plugin/dapp/cross2eth/boss4x
OUT_DIR="${1}/$strapp"
FLAG=$2
......
......@@ -54,7 +54,7 @@ function evm_callQuery() {
local parameter=$1
local callerAddr=$2
local resok=$3
local methodName=$4
local name=$4
req='{"method":"Chain33.Query","params":[{"execer":"evm","funcName":"GetPackData","payload":{"abi":"'${erc20_abi}'","parameter":"'${parameter}'"}}]}'
chain33_Http "$req" "${MAIN_HTTP}" '(.result != null)' "GetPackData" ".result.packData"
......@@ -64,7 +64,7 @@ function evm_callQuery() {
chain33_Http "$req" "${MAIN_HTTP}" '(.result != null)' "Query" ".result.rawData"
echo "$RETURN_RESP"
req='{"method":"Chain33.Query","params":[{"execer":"evm","funcName":"GetUnpackData","payload":{"abi":"'${erc20_abi}'","methodName":"'${methodName}'","data":"'${RETURN_RESP}'"}}]}'
req='{"method":"Chain33.Query","params":[{"execer":"evm","funcName":"GetUnpackData","payload":{"abi":"'${erc20_abi}'","name":"'${name}'","data":"'${RETURN_RESP}'"}}]}'
chain33_Http "$req" "${MAIN_HTTP}" '(.result != null)' "GetUnpackData" ".result.unpackData[0]"
echo "$RETURN_RESP"
......
......@@ -153,6 +153,63 @@ func Unpack(data []byte, methodName, abiData string) (output []*Param, err error
return
}
//同时支持input,output和event三种数据的unpack
func UnpackAllTypes(data []byte, name, abiData string) (output []*Param, err error) {
if len(data) == 0 {
log.Info("Unpack", "Data len", 0, "name", name)
return output, err
}
// 解析ABI数据结构,获取本次调用的方法对象
abi, err := JSON(strings.NewReader(abiData))
if err != nil {
return output, err
}
var values []interface{}
var arguments Arguments
if method, ok := abi.Methods[name]; ok {
if len(data)%32 == 0 {
values, err = method.Outputs.UnpackValues(data)
arguments = method.Outputs
} else if len(data[4:])%32 == 0 {
values, err = method.Inputs.UnpackValues(data[4:])
arguments = method.Inputs
} else {
return output, errors.New("UnpackAllTypes: improperly formatted data")
}
if arguments.LengthNonIndexed() == 0 {
return output, nil
}
} else if event, ok := abi.Events[name]; ok {
values, err = event.Inputs.UnpackValues(data)
arguments = event.Inputs
} else {
return output, errors.New("UnpackAllTypes: could not locate named method or event")
}
if err != nil {
return output, err
}
if len(arguments) == 0 || len(values) != len(arguments) {
return output, errors.New("wrong data to unpack")
}
output = []*Param{}
for i, v := range values {
arg := arguments[i]
pval := &Param{Name: arg.Name, Type: arg.Type.String(), Value: v}
if arg.Type.String() == "address" {
pval.Value = v.(common.Hash160Address).ToAddress().String()
log.Info("Unpack address", "address", pval.Value)
}
output = append(output, pval)
}
return
}
// Param 返回值参数结构定义
type Param struct {
// Name 参数名称
......
......@@ -204,7 +204,7 @@ func (evm *EVMExecutor) Query_GetUnpackData(in *evmtypes.EvmGetUnpackDataReq) (t
return nil, errors.New("common.FromHex failed due to:" + err.Error())
}
outputs, err := evmAbi.Unpack(data, in.MethodName, in.Abi)
outputs, err := evmAbi.UnpackAllTypes(data, in.Name, in.Abi)
if err != nil {
return nil, errors.New("unpack evm return error" + err.Error())
}
......
This diff is collapsed.
......@@ -202,7 +202,7 @@ message EvmGetPackDataRespose {
message EvmGetUnpackDataReq {
string abi = 1;
string methodName = 2;
string name = 2;
string data = 3;
}
......
......@@ -1862,9 +1862,9 @@ type EvmGetUnpackDataReq struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Abi string `protobuf:"bytes,1,opt,name=abi,proto3" json:"abi,omitempty"`
MethodName string `protobuf:"bytes,2,opt,name=methodName,proto3" json:"methodName,omitempty"`
Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
Abi string `protobuf:"bytes,1,opt,name=abi,proto3" json:"abi,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Data string `protobuf:"bytes,3,opt,name=data,proto3" json:"data,omitempty"`
}
func (x *EvmGetUnpackDataReq) Reset() {
......@@ -1906,9 +1906,9 @@ func (x *EvmGetUnpackDataReq) GetAbi() string {
return ""
}
func (x *EvmGetUnpackDataReq) GetMethodName() string {
func (x *EvmGetUnpackDataReq) GetName() string {
if x != nil {
return x.MethodName
return x.Name
}
return ""
}
......@@ -2169,18 +2169,17 @@ var file_evmcontract_proto_rawDesc = []byte{
0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x22, 0x33, 0x0a, 0x15, 0x45, 0x76, 0x6d, 0x47, 0x65, 0x74,
0x50, 0x61, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x73, 0x65, 0x12,
0x1a, 0x0a, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28,
0x09, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61, 0x22, 0x5b, 0x0a, 0x13, 0x45,
0x09, 0x52, 0x08, 0x70, 0x61, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61, 0x22, 0x4f, 0x0a, 0x13, 0x45,
0x76, 0x6d, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61, 0x52,
0x65, 0x71, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x62, 0x69, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x03, 0x61, 0x62, 0x69, 0x12, 0x1e, 0x0a, 0x0a, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x4e, 0x61,
0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64,
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x39, 0x0a, 0x17, 0x45, 0x76, 0x6d, 0x47,
0x65, 0x74, 0x55, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x44, 0x61, 0x74,
0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x44,
0x61, 0x74, 0x61, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2e, 0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62,
0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x03, 0x61, 0x62, 0x69, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01,
0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x64, 0x61, 0x74, 0x61,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, 0x61, 0x74, 0x61, 0x22, 0x39, 0x0a, 0x17,
0x45, 0x76, 0x6d, 0x47, 0x65, 0x74, 0x55, 0x6e, 0x70, 0x61, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x73, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x75, 0x6e, 0x70, 0x61, 0x63,
0x6b, 0x44, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x75, 0x6e, 0x70,
0x61, 0x63, 0x6b, 0x44, 0x61, 0x74, 0x61, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2e, 0x2f, 0x74, 0x79,
0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
......
all:
bash build.sh $(OUT) $(FLAG)
#!/bin/bash
# 官方ci集成脚本
strpwd=$(pwd)
strcmd=${strpwd##*dapp/}
strapp=${strcmd%/cmd*}
OUT_DIR="${1}/$strapp"
#FLAG=$2
mkdir -p "${OUT_DIR}"
cp ./build/* "${OUT_DIR}"
#!/usr/bin/env bash
# shellcheck disable=SC2128
# shellcheck source=/dev/null
source ../dapp-test-common.sh
MAIN_HTTP=""
tokenExecName="token"
ExecName="evmxgo"
privateKey="0x4dcb00c7d01a3d377c0d5a14cd7ec91798a74c8b41896c5d21fc8b9bf4b40e42"
function updateConfig() {
unsignedTx=$(curl -s --data-binary '{"jsonrpc":"2.0","id":2,"method":"Chain33.CreateTransaction","params":[{"execer":"manage","actionName":"Modify","payload":{"key":"evmxgo-mint-DOG","value":"{\"address\":\"address1234\",\"precision\":4,\"introduction\":\"介绍\"}","op":"add","addr":""}}]}' -H 'content-type:text/plain;' ${MAIN_HTTP} | jq -r ".result")
if [ "${unsignedTx}" == "" ]; then
echo_rst "update config create tx" 1
return
fi
signRawTxAndQuery "$FUNCNAME" "$privateKey" "${unsignedTx}"
}
function evmxgo_mint() {
local data='{"jsonrpc":"2.0","id":1,"method":"Chain33.CreateTransaction","params":[{"execer":"evmxgo","actionName":"Mint","payload":{"symbol":"DOG","amount":10000000}}]}'
unsignedTx=$(curl -s --data-binary "$data" -H 'content-type:text/plain;' ${MAIN_HTTP} | jq -r ".result")
if [ "${unsignedTx}" == "" ]; then
echo_rst "evmxgo mint create tx" 1
return
fi
signRawTxAndQuery "$FUNCNAME" "$privateKey" "${unsignedTx}"
}
function evmxgo_burn() {
local data='{"jsonrpc":"2.0","id":2,"method":"Chain33.CreateTransaction","params":[{"execer":"evmxgo","actionName":"Burn","payload":{"symbol":"DOG","amount":10000000}}]}'
unsignedTx=$(curl -s --data-binary "$data" -H 'content-type:text/plain;' ${MAIN_HTTP} | jq -r ".result")
if [ "${unsignedTx}" == "" ]; then
echo_rst "evmxgo mint create tx" 1
return
fi
signRawTxAndQuery "$FUNCNAME" "$privateKey" "${unsignedTx}"
}
function evmxgo_transfer() {
addr=$1
symbol=$2
local data='{"jsonrpc":"2.0","id":2,"method":"Chain33.CreateTransaction","params":[{"execer": "'"${ExecName}"'","actionName":"Transfer","payload": {"cointoken":"'"${symbol}"'", "amount": "10000000", "note": "", "to": "'"${addr}"'"}}]}'
unsignedTx=$(curl -s --data-binary "${data}" -H 'content-type:text/plain;' ${MAIN_HTTP} | jq -r ".result")
if [ "${unsignedTx}" == "" ]; then
echo_rst "token transfer create tx" 1
return
fi
signRawTxAndQuery "$FUNCNAME" "$privateKey" "${unsignedTx}"
}
function evmxgo_transfer_exec() {
addr=$1
symbol=$2
local data='{"jsonrpc":"2.0","id":1,"method":"Chain33.CreateTransaction","params":[{"execer":"'"${ExecName}"'","actionName":"TransferToExec","payload":{"cointoken":"'"${symbol}"'","amount":10000,"note":"","execName":"token","to":"12hpJBHybh1mSyCijQ2MQJPk7z7kZ7jnQa"}}]}'
unsignedTx=$(curl -s --data-binary "${data}" -H 'content-type:text/plain;' ${MAIN_HTTP} | jq -r ".result")
if [ "${unsignedTx}" == "" ]; then
echo_rst "token transfer create tx" 1
return
fi
signRawTxAndQuery "$FUNCNAME" "$privateKey" "${unsignedTx}"
}
function evmxgo_withdraw() {
addr=$1
symbol=$2
local data='{"jsonrpc":"2.0","id":1,"method":"Chain33.CreateTransaction","params":[{"execer":"'"${ExecName}"'","actionName":"Withdraw","payload":{"cointoken":"'"${symbol}"'","amount":1000,"note":"","execName":"'"${tokenExecName}"'","to":"'"${addr}"'"}}]}'
unsignedTx=$(curl -s --data-binary "${data}" -H 'content-type:text/plain;' ${MAIN_HTTP} | jq -r ".result")
if [ "${unsignedTx}" == "" ]; then
echo_rst "token transfer create tx" 1
return
fi
signRawTxAndQuery "$FUNCNAME" "$privateKey" "${unsignedTx}"
}
# 查询交易的执行结果
# 根据传入的规则,校验查询的结果 (参数1: 校验规则 参数2: 预期匹配结果)
function queryTransaction() {
validator=$1
expectRes=$2
echo "txhash=${RAW_TX_HASH}"
res=$(curl -s --data-binary '{"jsonrpc":"2.0","id":2,"method":"Chain33.QueryTransaction","params":[{"hash":"'"${RAW_TX_HASH}"'"}]}' -H 'content-type:text/plain;' ${MAIN_HTTP} | jq -r "${validator}")
if [ "${res}" != "${expectRes}" ]; then
return 1
else
return 0
fi
}
function signRawTxAndQuery() {
chain33_SignAndSendTx "$3" "$2" "${MAIN_HTTP}"
queryTransaction ".error | not" "true"
echo_rst "$1 queryExecRes" "$?"
}
function init() {
updateConfig
}
function run_test() {
local ip=$1
evmxgo_mint
evmxgo_burn
evmxgo_transfer "17EVv6tW2HzE73TVB6YXQYThQJxa7kuZb8" "DOG"
evmxgo_transfer_exec "12hpJBHybh1mSyCijQ2MQJPk7z7kZ7jnQa" "DOG"
evmxgo_withdraw "12hpJBHybh1mSyCijQ2MQJPk7z7kZ7jnQa" "DOG"
}
function main() {
chain33_RpcTestBegin evmxgo
local ip=$1
MAIN_HTTP=$ip
echo "main_ip=$MAIN_HTTP"
init
run_test "$MAIN_HTTP"
chain33_RpcTestRst evmxgo "$CASE_ERR"
}
chain33_debug_function main "http://ip:port/"
This diff is collapsed.
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package commands
import (
"strings"
pt "github.com/33cn/plugin/plugin/dapp/paracross/types"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/types"
)
// GetExecAddr 获取执行器地址
func GetExecAddr(exec string) (string, error) {
if ok := types.IsAllowExecName([]byte(exec), []byte(exec)); !ok {
return "", types.ErrExecNameNotAllow
}
addrResult := address.ExecAddress(exec)
result := addrResult
return result, nil
}
func getRealExecName(paraName string, name string) string {
if strings.HasPrefix(name, pt.ParaPrefix) {
return name
}
return paraName + name
}
package executor
import (
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/common/address"
log "github.com/33cn/chain33/common/log/log15"
drivers "github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
evmxgotypes "github.com/33cn/plugin/plugin/dapp/evmxgo/types"
)
/*
* 执行器相关定义
* 重载基类相关接口
*/
const (
mintPrefix = "evmxgo-mint-"
evmxgoAssetsPrefix = "LODB-evmxgo-assets:"
bridgevmxgoAddrPrefix = "bridgevmxgo-contract-addr"
)
var (
//日志
elog = log.New("module", "evmxgo.executor")
)
var driverName = evmxgotypes.EvmxgoX
type subConfig struct {
SaveTokenTxList bool `json:"saveTokenTxList"`
}
var subCfg subConfig
// Init register dapp
func Init(name string, cfg *types.Chain33Config, sub []byte) {
if sub != nil {
types.MustDecode(sub, &subCfg)
}
drivers.Register(cfg, GetName(), newEvmxgo, cfg.GetDappFork(driverName, "Enable"))
InitExecType()
}
// InitExecType Init Exec Type
func InitExecType() {
ety := types.LoadExecutorType(driverName)
ety.InitFuncList(types.ListMethod(&evmxgo{}))
}
type evmxgo struct {
drivers.DriverBase
}
func newEvmxgo() drivers.Driver {
t := &evmxgo{}
t.SetChild(t)
t.SetExecutorType(types.LoadExecutorType(driverName))
return t
}
// GetName get driver name
func GetName() string {
return newEvmxgo().GetName()
}
func (e *evmxgo) GetDriverName() string {
return driverName
}
// CheckTx 实现自定义检验交易接口,供框架调用
func (e *evmxgo) CheckTx(tx *types.Transaction, index int) error {
// implement code
return nil
}
func (e *evmxgo) getTokens(req *evmxgotypes.ReqEvmxgos) (types.Message, error) {
replyTokens := &evmxgotypes.ReplyEvmxgos{}
tokens, err := e.listTokenKeys(req)
if err != nil {
return nil, err
}
elog.Error("token Query GetTokens", "get count", len(tokens))
for _, t1 := range tokens {
// delete impl by set nil
if len(t1) == 0 {
continue
}
var evmxgoValue evmxgotypes.LocalEvmxgo
err = types.Decode(t1, &evmxgoValue)
if err == nil {
replyTokens.Tokens = append(replyTokens.Tokens, &evmxgoValue)
}
}
//tokenlog.Info("token Query", "replyTokens", replyTokens)
return replyTokens, nil
}
func (e *evmxgo) listTokenKeys(req *evmxgotypes.ReqEvmxgos) ([][]byte, error) {
querydb := e.GetLocalDB()
if req.QueryAll {
keys, err := querydb.List(calcEvmxgoKeyLocal(), nil, 0, 0)
if err != nil && err != types.ErrNotFound {
return nil, err
}
if len(keys) == 0 {
return nil, types.ErrNotFound
}
elog.Debug("token Query GetTokens", "get count", len(keys))
return keys, nil
}
var keys [][]byte
for _, token := range req.Tokens {
keys1, err := querydb.List(calcEvmxgoStatusKeyLocal(token), nil, 0, 0)
if err != nil && err != types.ErrNotFound {
return nil, err
}
keys = append(keys, keys1...)
elog.Debug("token Query GetTokens", "get count", len(keys))
}
if len(keys) == 0 {
return nil, types.ErrNotFound
}
return keys, nil
}
func (e *evmxgo) makeTokenTxKvs(tx *types.Transaction, action *evmxgotypes.EvmxgoAction, receipt *types.ReceiptData, index int, isDel bool) ([]*types.KeyValue, error) {
var kvs []*types.KeyValue
var symbol string
if action.Ty == evmxgotypes.ActionTransfer {
symbol = action.GetTransfer().Cointoken
} else if action.Ty == evmxgotypes.ActionWithdraw {
symbol = action.GetWithdraw().Cointoken
} else if action.Ty == evmxgotypes.EvmxgoActionTransferToExec {
symbol = action.GetTransferToExec().Cointoken
} else {
return kvs, nil
}
kvs, err := tokenTxKvs(tx, symbol, e.GetHeight(), int64(index), isDel)
return kvs, err
}
func (e *evmxgo) getTokenInfo(symbol string) (types.Message, error) {
if symbol == "" {
return nil, types.ErrInvalidParam
}
key := calcEvmxgoStatusKeyLocal(symbol)
values, err := e.GetLocalDB().List(key, nil, 0, 0)
if err != nil {
return nil, err
}
if len(values) == 0 || values[0] == nil || len(values[0]) == 0 {
return nil, types.ErrNotFound
}
var tokenInfo evmxgotypes.LocalEvmxgo
err = types.Decode(values[0], &tokenInfo)
if err != nil {
return &tokenInfo, err
}
return &tokenInfo, nil
}
func (e *evmxgo) getBalance(req *types.ReqBalance) ([]*types.Account, error) {
cfg := e.GetAPI().GetConfig()
accountdb, err := account.NewAccountDB(cfg, evmxgotypes.EvmxgoX, req.GetAssetSymbol(), nil)
if err != nil {
return nil, err
}
switch req.GetExecer() {
case cfg.ExecName(evmxgotypes.EvmxgoX):
queryAddrs := req.GetAddresses()
accounts, err := accountdb.LoadAccounts(e.GetAPI(), queryAddrs)
if err != nil {
log.Error("GetTokenBalance", "err", err.Error(), "token symbol", req.GetAssetSymbol(), "address", queryAddrs)
return nil, err
}
return accounts, nil
default:
execaddress := address.ExecAddress(req.GetExecer())
addrs := req.GetAddresses()
var accounts []*types.Account
for _, addr := range addrs {
acc, err := accountdb.LoadExecAccountQueue(e.GetAPI(), addr, execaddress)
if err != nil {
log.Error("GetTokenBalance for exector", "err", err.Error(), "token symbol", req.GetAssetSymbol(),
"address", addr)
continue
}
accounts = append(accounts, acc)
}
return accounts, nil
}
}
package executor
import (
"encoding/json"
"fmt"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
evmxgotypes "github.com/33cn/plugin/plugin/dapp/evmxgo/types"
)
type evmxgoDB struct {
evmxgo evmxgotypes.Evmxgo
}
func newEvmxgoDB(mint *evmxgotypes.EvmxgoMint) *evmxgoDB {
e := &evmxgoDB{}
e.evmxgo.Symbol = mint.GetSymbol()
return e
}
func (e *evmxgoDB) save(db dbm.KV, key []byte) {
set := e.getKVSet(key)
for i := 0; i < len(set); i++ {
err := db.Set(set[i].GetKey(), set[i].Value)
if err != nil {
panic(err)
}
}
}
func (e *evmxgoDB) getLogs(ty int32, status int32) []*types.ReceiptLog {
var log []*types.ReceiptLog
value := types.Encode(&evmxgotypes.ReceiptEvmxgo{Symbol: e.evmxgo.Symbol})
log = append(log, &types.ReceiptLog{Ty: ty, Log: value})
return log
}
//key:mavl-create-token-addr-xxx or mavl-token-xxx <-----> value:token
func (e *evmxgoDB) getKVSet(key []byte) (kvset []*types.KeyValue) {
value := types.Encode(&e.evmxgo)
kvset = append(kvset, &types.KeyValue{Key: key, Value: value})
return kvset
}
func loadEvmxgoDB(db dbm.KV, symbol string) (*evmxgoDB, error) {
evmxgo, err := db.Get(calcEvmxgoKey(symbol))
if err != nil {
elog.Error("evmxgodb load ", "Can't get token form db for token", symbol)
return nil, evmxgotypes.ErrEvmxgoSymbolNotExist
}
var e evmxgotypes.Evmxgo
err = types.Decode(evmxgo, &e)
if err != nil {
elog.Error("evmxgodb load", "Can't decode token info", symbol)
return nil, err
}
return &evmxgoDB{e}, nil
}
func safeAdd(balance, amount int64) (int64, error) {
if balance+amount < amount || balance+amount > types.MaxTokenBalance {
return balance, types.ErrAmount
}
return balance + amount, nil
}
func (e *evmxgoDB) mint(amount int64) ([]*types.KeyValue, []*types.ReceiptLog, error) {
newTotal, err := safeAdd(e.evmxgo.Total, amount)
if err != nil {
return nil, nil, err
}
prevEvmxgo := e.evmxgo
e.evmxgo.Total = newTotal
kvs := e.getKVSet(calcEvmxgoKey(e.evmxgo.Symbol))
logs := []*types.ReceiptLog{{Ty: evmxgotypes.TyLogEvmxgoMint, Log: types.Encode(&evmxgotypes.ReceiptEvmxgoAmount{Prev: &prevEvmxgo, Current: &e.evmxgo})}}
return kvs, logs, nil
}
func (e *evmxgoDB) burn(db dbm.KV, amount int64) ([]*types.KeyValue, []*types.ReceiptLog, error) {
if e.evmxgo.Total < amount {
return nil, nil, types.ErrNoBalance
}
prevToken := e.evmxgo
e.evmxgo.Total -= amount
kvs := e.getKVSet(calcEvmxgoKey(e.evmxgo.Symbol))
logs := []*types.ReceiptLog{{Ty: evmxgotypes.TyLogEvmxgoBurn, Log: types.Encode(&evmxgotypes.ReceiptEvmxgoAmount{Prev: &prevToken, Current: &e.evmxgo})}}
return kvs, logs, nil
}
type evmxgoAction struct {
coinsAccount *account.DB
db dbm.KV
txhash []byte
fromaddr string
toaddr string
blocktime int64
height int64
execaddr string
api client.QueueProtocolAPI
}
func newEvmxgoAction(e *evmxgo, toaddr string, tx *types.Transaction) *evmxgoAction {
hash := tx.Hash()
fromaddr := tx.From()
return &evmxgoAction{e.GetCoinsAccount(), e.GetStateDB(), hash, fromaddr, toaddr,
e.GetBlockTime(), e.GetHeight(), dapp.ExecAddress(string(tx.Execer)), e.GetAPI()}
}
func getManageKey(key string, db dbm.KV) ([]byte, error) {
manageKey := types.ManageKey(key)
value, err := db.Get([]byte(manageKey))
if err != nil {
elog.Info("evmxgodb", "get db key", "not found manageKey", "key", manageKey)
return getConfigKey(key, db)
}
return value, nil
}
func getConfigKey(key string, db dbm.KV) ([]byte, error) {
configKey := types.ConfigKey(key)
value, err := db.Get([]byte(configKey))
if err != nil {
elog.Info("evmxgodb", "get db key", "not found configKey", "key", configKey)
return nil, err
}
return value, nil
}
func hasConfiged(v1, key string, db dbm.KV) (bool, error) {
value, err := getManageKey(key, db)
if err != nil {
elog.Info("evmxgodb", "get db key", "not found", "key", key)
return false, err
}
if value == nil {
elog.Info("evmxgodb", "get db key", " found nil value", "key", key)
return false, nil
}
var item types.ConfigItem
err = types.Decode(value, &item)
if err != nil {
elog.Error("evmxgodb", "get db key", err)
return false, err // types.ErrBadConfigValue
}
for _, v := range item.GetArr().Value {
if v == v1 {
return true, nil
}
}
return false, nil
}
func loadEvmxgoMintConfig(db dbm.KV, symbol string) (*evmxgotypes.EvmxgoMintConfig, error) {
key := fmt.Sprintf(mintPrefix+"%s", symbol)
value, err := getManageKey(key, db)
if err != nil {
elog.Info("evmxgodb", "get db key", "not found", "key", key)
return nil, err
}
if value == nil {
elog.Info("evmxgodb", "get db key", " found nil value", "key", key)
return nil, nil
}
elog.Info("loadEvmxgoMintConfig", "value", string(value))
var item types.ConfigItem
err = types.Decode(value, &item)
if err != nil {
elog.Error("evmxgodb load loadEvmxgoMintConfig", "Can't decode ConfigItem", symbol)
return nil, err // types.ErrBadConfigValue
}
configValue := item.GetArr().Value
if len(configValue) <= 0 {
return nil, evmxgotypes.ErrEvmxgoSymbolNotConfigValue
}
var e evmxgotypes.EvmxgoMintConfig
err = json.Unmarshal([]byte(configValue[0]), &e)
if err != nil {
elog.Error("evmxgodb load", "Can't decode token info", symbol)
return nil, err
}
return &e, nil
}
func calcTokenAssetsKey(addr string) []byte {
return []byte(fmt.Sprintf(evmxgoAssetsPrefix+"%s", addr))
}
func getTokenAssetsKey(addr string, db dbm.KVDB) (*types.ReplyStrings, error) {
key := calcTokenAssetsKey(addr)
value, err := db.Get(key)
if err != nil && err != types.ErrNotFound {
elog.Error("evmxgodb", "GetTokenAssetsKey", err)
return nil, err
}
var assets types.ReplyStrings
if err == types.ErrNotFound {
return &assets, nil
}
err = types.Decode(value, &assets)
if err != nil {
elog.Error("evmxgodb", "GetTokenAssetsKey", err)
return nil, err
}
return &assets, nil
}
// AddTokenToAssets 添加个人资产列表
func AddTokenToAssets(addr string, db dbm.KVDB, symbol string) []*types.KeyValue {
tokenAssets, err := getTokenAssetsKey(addr, db)
if err != nil {
return nil
}
if tokenAssets == nil {
tokenAssets = &types.ReplyStrings{}
}
var found = false
for _, sym := range tokenAssets.Datas {
if sym == symbol {
found = true
break
}
}
if !found {
tokenAssets.Datas = append(tokenAssets.Datas, symbol)
}
var kv []*types.KeyValue
kv = append(kv, &types.KeyValue{Key: calcTokenAssetsKey(addr), Value: types.Encode(tokenAssets)})
return kv
}
// 铸币不可控, 也是麻烦。 2选1
// 1. 谁可以发起
// 2. 是否需要审核 这个会增加管理的成本
// 现在实现选择 1
func (action *evmxgoAction) mint(mint *evmxgotypes.EvmxgoMint, tx2lock *types.Transaction) (*types.Receipt, error) {
if mint == nil {
return nil, types.ErrInvalidParam
}
if mint.GetAmount() < 0 || mint.GetAmount() > types.MaxTokenBalance || mint.GetSymbol() == "" {
return nil, types.ErrInvalidParam
}
cfg := action.api.GetConfig()
if err := checkMintPara(mint, tx2lock, action.db); nil != err {
return nil, err
}
// TODO check()
evmxgodb, err := loadEvmxgoDB(action.db, mint.GetSymbol())
if err != nil {
if err != evmxgotypes.ErrEvmxgoSymbolNotExist {
return nil, err
}
// evmxgo合约,只要配置了就可以铸币
configSymbol, err := loadEvmxgoMintConfig(action.db, mint.GetSymbol())
if err != nil || configSymbol == nil {
elog.Error("evmxgo mint ", "not config symbol", mint.GetSymbol(), "error", err)
return nil, evmxgotypes.ErrEvmxgoSymbolNotAllowedMint
}
if mint.BridgeToken != configSymbol.Address {
elog.Error("evmxgo mint ", "NotCorrectBridgeTokenAddress with address by manager", configSymbol.Address, "mint.BridgeToken", mint.BridgeToken)
return nil, evmxgotypes.ErrNotCorrectBridgeTokenAddress
}
evmxgodb = newEvmxgoDB(mint)
}
kvs, logs, err := evmxgodb.mint(mint.Amount)
if err != nil {
elog.Error("evmxgo mint ", "symbol", mint.GetSymbol(), "error", err, "from", action.fromaddr)
return nil, err
}
evmxgoAccount, err := account.NewAccountDB(cfg, "evmxgo", mint.GetSymbol(), action.db)
if err != nil {
return nil, err
}
elog.Debug("mint", "evmxgo.Symbol", mint.Symbol, "evmxgo.Amount", mint.Amount)
receipt, err := evmxgoAccount.Mint(mint.Recipient, mint.Amount)
if err != nil {
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
return &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}, nil
}
func (action *evmxgoAction) burn(burn *evmxgotypes.EvmxgoBurn) (*types.Receipt, error) {
if burn == nil {
return nil, types.ErrInvalidParam
}
if burn.GetAmount() < 0 || burn.GetAmount() > types.MaxTokenBalance || burn.GetSymbol() == "" {
return nil, types.ErrInvalidParam
}
evmxgodb, err := loadEvmxgoDB(action.db, burn.GetSymbol())
if err != nil {
return nil, err
}
kvs, logs, err := evmxgodb.burn(action.db, burn.Amount)
if err != nil {
elog.Error("evmxgo burn ", "symbol", burn.GetSymbol(), "error", err, "from", action.fromaddr)
return nil, err
}
chain33cfg := action.api.GetConfig()
evmxgoAccount, err := account.NewAccountDB(chain33cfg, "evmxgo", burn.GetSymbol(), action.db)
if err != nil {
return nil, err
}
elog.Debug("evmxgo burn", "burn.Symbol", burn.Symbol, "burn.Amount", burn.Amount)
receipt, err := evmxgoAccount.Burn(action.fromaddr, burn.Amount)
if err != nil {
return nil, err
}
logs = append(logs, receipt.Logs...)
kvs = append(kvs, receipt.KV...)
return &types.Receipt{Ty: types.ExecOk, KV: kvs, Logs: logs}, nil
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
import (
"fmt"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
tp "github.com/33cn/plugin/plugin/dapp/token/types"
)
const (
evmxgoTxPrefix = "LODB-evmxgo-txHash:"
evmxgoTxAddrPrefix = "LODB-evmxgo-txAddrHash:"
evmxgoTxAddrDirPrefix = "LODB-evmxgo-txAddrDirHash:"
)
func tokenTxKvs(tx *types.Transaction, symbol string, height, index int64, isDel bool) ([]*types.KeyValue, error) {
var kv []*types.KeyValue
from := address.PubKeyToAddress(tx.GetSignature().GetPubkey()).String()
to := tx.GetRealToAddr()
keys := tokenTxkeys(symbol, from, to, height, index)
var txInfo []byte
if !isDel {
txInfo = makeReplyTxInfo(tx, height, index, symbol)
}
for _, k := range keys {
kv = append(kv, &types.KeyValue{Key: k, Value: txInfo})
}
return kv, nil
}
func tokenTxkeys(symbol, from, to string, height, index int64) (result [][]byte) {
key := calcTokenTxKey(symbol, height, index)
result = append(result, key)
if len(from) > 0 {
fromKey1 := calcTokenAddrTxKey(symbol, from, height, index)
fromKey2 := calcTokenAddrTxDirKey(symbol, from, dapp.TxIndexFrom, height, index)
result = append(result, fromKey1)
result = append(result, fromKey2)
}
if len(to) > 0 {
toKey1 := calcTokenAddrTxKey(symbol, to, height, index)
toKey2 := calcTokenAddrTxDirKey(symbol, to, dapp.TxIndexTo, height, index)
result = append(result, toKey1)
result = append(result, toKey2)
}
return
}
// calcTokenTxKey evmxgo transaction entities in local DB
func calcTokenTxKey(symbol string, height, index int64) []byte {
if height == -1 {
return []byte(fmt.Sprintf(evmxgoTxPrefix+"%s:%s", symbol, ""))
}
return []byte(fmt.Sprintf(evmxgoTxPrefix+"%s:%s", symbol, dapp.HeightIndexStr(height, index)))
}
func calcTokenAddrTxKey(symbol, addr string, height, index int64) []byte {
if height == -1 {
return []byte(fmt.Sprintf(evmxgoTxAddrPrefix+"%s:%s:%s", symbol, addr, ""))
}
return []byte(fmt.Sprintf(evmxgoTxAddrPrefix+"%s:%s:%s", symbol, addr, dapp.HeightIndexStr(height, index)))
}
func calcTokenAddrTxDirKey(symbol, addr string, flag int32, height, index int64) []byte {
if height == -1 {
return []byte(fmt.Sprintf(evmxgoTxAddrDirPrefix+"%s:%s:%d:%s", symbol, addr, flag, ""))
}
return []byte(fmt.Sprintf(evmxgoTxAddrDirPrefix+"%s:%s:%d:%s", symbol, addr, flag,
dapp.HeightIndexStr(height, index)))
}
func makeReplyTxInfo(tx *types.Transaction, height, index int64, symbol string) []byte {
var info types.ReplyTxInfo
info.Hash = tx.Hash()
info.Height = height
info.Index = index
info.Assets = []*types.Asset{{Exec: tp.TokenX, Symbol: symbol}}
return types.Encode(&info)
}
package executor
import (
"errors"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/types"
evmxgotypes "github.com/33cn/plugin/plugin/dapp/evmxgo/types"
)
/*
* 实现交易的链上执行接口
* 关键数据上链(statedb)并生成交易回执(log)
*/
func (e *evmxgo) Exec_Transfer(payload *types.AssetsTransfer, tx *types.Transaction, index int) (*types.Receipt, error) {
token := payload.GetCointoken()
cfg := e.GetAPI().GetConfig()
db, err := account.NewAccountDB(cfg, e.GetName(), token, e.GetStateDB())
if err != nil {
return nil, err
}
action := evmxgotypes.EvmxgoAction{
Ty: evmxgotypes.ActionTransfer,
Value: &evmxgotypes.EvmxgoAction_Transfer{
Transfer: payload,
},
}
return e.ExecTransWithdraw(db, tx, &action, index)
}
func (e *evmxgo) Exec_Withdraw(payload *types.AssetsWithdraw, tx *types.Transaction, index int) (*types.Receipt, error) {
token := payload.GetCointoken()
cfg := e.GetAPI().GetConfig()
db, err := account.NewAccountDB(cfg, e.GetName(), token, e.GetStateDB())
if err != nil {
return nil, err
}
action := evmxgotypes.EvmxgoAction{
Ty: evmxgotypes.ActionWithdraw,
Value: &evmxgotypes.EvmxgoAction_Withdraw{
Withdraw: payload,
},
}
return e.ExecTransWithdraw(db, tx, &action, index)
}
func (e *evmxgo) Exec_TransferToExec(payload *types.AssetsTransferToExec, tx *types.Transaction, index int) (*types.Receipt, error) {
token := payload.GetCointoken()
cfg := e.GetAPI().GetConfig()
db, err := account.NewAccountDB(cfg, e.GetName(), token, e.GetStateDB())
if err != nil {
return nil, err
}
action := evmxgotypes.EvmxgoAction{
Ty: evmxgotypes.EvmxgoActionTransferToExec,
Value: &evmxgotypes.EvmxgoAction_TransferToExec{
TransferToExec: payload,
},
}
return e.ExecTransWithdraw(db, tx, &action, index)
}
func (e *evmxgo) Exec_Mint(payload *evmxgotypes.EvmxgoMint, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newEvmxgoAction(e, "", tx)
txGroup, err := e.GetTxGroup(index)
if nil != err {
return nil, err
}
if len(txGroup) < 2 || index == 0 {
return nil, errors.New("Mint tx should be included in lock tx group")
}
txs := e.GetTxs()
return action.mint(payload, txs[index-1])
}
func (e *evmxgo) Exec_Burn(payload *evmxgotypes.EvmxgoBurn, tx *types.Transaction, index int) (*types.Receipt, error) {
action := newEvmxgoAction(e, "", tx)
return action.burn(payload)
}
package executor
import (
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
evmxgotypes "github.com/33cn/plugin/plugin/dapp/evmxgo/types"
)
/*
* 实现区块回退时本地执行的数据清除
*/
// ExecDelLocal localdb kv数据自动回滚接口
func (e *evmxgo) ExecDelLocal(tx *types.Transaction, receipt *types.ReceiptData, index int) (*types.LocalDBSet, error) {
kvs, err := e.DelRollbackKV(tx, tx.Execer)
if err != nil {
return nil, err
}
dbSet := &types.LocalDBSet{}
dbSet.KV = append(dbSet.KV, kvs...)
return dbSet, nil
}
func (e *evmxgo) ExecDelLocal_Transfer(payload *types.AssetsTransfer, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
set, err := e.ExecDelLocalLocalTransWithdraw(tx, receiptData, index)
if err != nil {
return nil, err
}
if subCfg.SaveTokenTxList {
action := evmxgotypes.EvmxgoAction{
Ty: evmxgotypes.ActionTransfer,
Value: &evmxgotypes.EvmxgoAction_Transfer{
Transfer: payload,
},
}
kvs, err := e.makeTokenTxKvs(tx, &action, receiptData, index, true)
if err != nil {
return nil, err
}
set.KV = append(set.KV, kvs...)
}
return set, nil
}
func (e *evmxgo) ExecDelLocal_Withdraw(payload *types.AssetsWithdraw, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
set, err := e.ExecDelLocalLocalTransWithdraw(tx, receiptData, index)
if err != nil {
return nil, err
}
if subCfg.SaveTokenTxList {
tokenAction := evmxgotypes.EvmxgoAction{
Ty: evmxgotypes.ActionWithdraw,
Value: &evmxgotypes.EvmxgoAction_Withdraw{
Withdraw: payload,
},
}
kvs, err := e.makeTokenTxKvs(tx, &tokenAction, receiptData, index, true)
if err != nil {
return nil, err
}
set.KV = append(set.KV, kvs...)
}
return set, nil
}
func (e *evmxgo) ExecDelLocal_TransferToExec(payload *types.AssetsTransferToExec, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
set, err := e.ExecDelLocalLocalTransWithdraw(tx, receiptData, index)
if err != nil {
return nil, err
}
if subCfg.SaveTokenTxList {
tokenAction := evmxgotypes.EvmxgoAction{
Ty: evmxgotypes.EvmxgoActionTransferToExec,
Value: &evmxgotypes.EvmxgoAction_TransferToExec{
TransferToExec: payload,
},
}
kvs, err := e.makeTokenTxKvs(tx, &tokenAction, receiptData, index, true)
if err != nil {
return nil, err
}
set.KV = append(set.KV, kvs...)
}
return set, nil
}
func resetMint(e *evmxgotypes.LocalEvmxgo, height, time, amount int64) *evmxgotypes.LocalEvmxgo {
e.Total = e.Total - amount
return e
}
func resetBurn(e *evmxgotypes.LocalEvmxgo, height, time, amount int64) *evmxgotypes.LocalEvmxgo {
e.Total = e.Total + amount
return e
}
func (e *evmxgo) ExecDelLocal_Mint(payload *evmxgotypes.EvmxgoMint, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
localToken, err := loadLocalToken(payload.Symbol, e.GetLocalDB())
if err != nil {
return nil, err
}
localToken = resetMint(localToken, e.GetHeight(), e.GetBlockTime(), payload.Amount)
key := calcEvmxgoStatusKeyLocal(payload.Symbol)
var set []*types.KeyValue
set = append(set, &types.KeyValue{Key: key, Value: types.Encode(localToken)})
table := NewLogsTable(e.GetLocalDB())
txIndex := dapp.HeightIndexStr(e.GetHeight(), int64(index))
err = table.Del([]byte(txIndex))
if err != nil {
return nil, err
}
kv, err := table.Save()
if err != nil {
return nil, err
}
set = append(set, kv...)
return &types.LocalDBSet{KV: set}, nil
}
func (e *evmxgo) ExecDelLocal_Burn(payload *evmxgotypes.EvmxgoBurn, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
localToken, err := loadLocalToken(payload.Symbol, e.GetLocalDB())
if err != nil {
return nil, err
}
localToken = resetBurn(localToken, e.GetHeight(), e.GetBlockTime(), payload.Amount)
key := calcEvmxgoStatusKeyLocal(payload.Symbol)
var set []*types.KeyValue
set = append(set, &types.KeyValue{Key: key, Value: types.Encode(localToken)})
table := NewLogsTable(e.GetLocalDB())
txIndex := dapp.HeightIndexStr(e.GetHeight(), int64(index))
err = table.Del([]byte(txIndex))
if err != nil {
return nil, err
}
kv, err := table.Save()
if err != nil {
return nil, err
}
set = append(set, kv...)
return &types.LocalDBSet{KV: set}, nil
}
package executor
import (
"encoding/hex"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/system/dapp"
"github.com/33cn/chain33/types"
evmxgotypes "github.com/33cn/plugin/plugin/dapp/evmxgo/types"
)
/*
* 实现交易相关数据本地执行,数据不上链
* 非关键数据,本地存储(localDB), 用于辅助查询,效率高
*/
func (e *evmxgo) ExecLocal_Transfer(payload *types.AssetsTransfer, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
set, err := e.ExecLocalTransWithdraw(tx, receiptData, index)
if err != nil {
return nil, err
}
// 添加个人资产列表
kv := AddTokenToAssets(payload.To, e.GetLocalDB(), payload.Cointoken)
if kv != nil {
set.KV = append(set.KV, kv...)
}
if subCfg.SaveTokenTxList {
evmxgoAction := evmxgotypes.EvmxgoAction{
Ty: evmxgotypes.ActionTransfer,
Value: &evmxgotypes.EvmxgoAction_Transfer{
Transfer: payload,
},
}
kvs, err := e.makeTokenTxKvs(tx, &evmxgoAction, receiptData, index, false)
if err != nil {
return nil, err
}
set.KV = append(set.KV, kvs...)
}
return set, nil
}
func (e *evmxgo) ExecLocal_Withdraw(payload *types.AssetsWithdraw, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
set, err := e.ExecLocalTransWithdraw(tx, receiptData, index)
if err != nil {
return nil, err
}
// 添加个人资产列表
kv := AddTokenToAssets(tx.From(), e.GetLocalDB(), payload.Cointoken)
if kv != nil {
set.KV = append(set.KV, kv...)
}
if subCfg.SaveTokenTxList {
evmxgoAction := evmxgotypes.EvmxgoAction{
Ty: evmxgotypes.ActionWithdraw,
Value: &evmxgotypes.EvmxgoAction_Withdraw{
Withdraw: payload,
},
}
kvs, err := e.makeTokenTxKvs(tx, &evmxgoAction, receiptData, index, false)
if err != nil {
return nil, err
}
set.KV = append(set.KV, kvs...)
}
return set, nil
}
func (e *evmxgo) ExecLocal_TransferToExec(payload *types.AssetsTransferToExec, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
set, err := e.ExecLocalTransWithdraw(tx, receiptData, index)
if err != nil {
return nil, err
}
if subCfg.SaveTokenTxList {
evmxgoAction := evmxgotypes.EvmxgoAction{
Ty: evmxgotypes.EvmxgoActionTransferToExec,
Value: &evmxgotypes.EvmxgoAction_TransferToExec{
TransferToExec: payload,
},
}
kvs, err := e.makeTokenTxKvs(tx, &evmxgoAction, receiptData, index, false)
if err != nil {
return nil, err
}
set.KV = append(set.KV, kvs...)
}
return set, nil
}
func loadLocalToken(symbol string, db db.KVDB) (*evmxgotypes.LocalEvmxgo, error) {
key := calcEvmxgoStatusKeyLocal(symbol)
v, err := db.Get(key)
if err != nil {
return nil, evmxgotypes.ErrEvmxgoSymbolNotExist
}
var localToken evmxgotypes.LocalEvmxgo
err = types.Decode(v, &localToken)
if err != nil {
return nil, err
}
return &localToken, nil
}
func newLocalEvmxgo(mint *evmxgotypes.EvmxgoMint) *evmxgotypes.LocalEvmxgo {
e := evmxgotypes.LocalEvmxgo{}
e.Symbol = mint.GetSymbol()
return &e
}
func setMint(t *evmxgotypes.LocalEvmxgo, height, time, amount int64) *evmxgotypes.LocalEvmxgo {
t.Total = t.Total + amount
return t
}
func setBurn(t *evmxgotypes.LocalEvmxgo, height, time, amount int64) *evmxgotypes.LocalEvmxgo {
t.Total = t.Total - amount
return t
}
func (e *evmxgo) ExecLocal_Mint(payload *evmxgotypes.EvmxgoMint, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
localToken, err := loadLocalToken(payload.Symbol, e.GetLocalDB())
if err != nil && err != evmxgotypes.ErrEvmxgoSymbolNotExist {
return nil, err
}
// evmxgo合约,只要配置了就可以铸币
if err == evmxgotypes.ErrEvmxgoSymbolNotExist {
configSynbol, err := loadEvmxgoMintConfig(e.GetStateDB(), payload.GetSymbol())
if err != nil || configSynbol == nil {
elog.Error("evmxgo mint ", "not config symbol", payload.GetSymbol(), "error", err)
return nil, evmxgotypes.ErrEvmxgoSymbolNotAllowedMint
}
localToken = newLocalEvmxgo(payload)
localToken.Introduction = configSynbol.Introduction
localToken.Precision = configSynbol.Precision
}
localToken = setMint(localToken, e.GetHeight(), e.GetBlockTime(), payload.Amount)
var set []*types.KeyValue
key := calcEvmxgoStatusKeyLocal(payload.Symbol)
set = append(set, &types.KeyValue{Key: key, Value: types.Encode(localToken)})
table := NewLogsTable(e.GetLocalDB())
txIndex := dapp.HeightIndexStr(e.GetHeight(), int64(index))
err = table.Add(&evmxgotypes.LocalEvmxgoLogs{Symbol: payload.Symbol, TxIndex: txIndex, ActionType: evmxgotypes.EvmxgoActionMint, TxHash: "0x" + hex.EncodeToString(tx.Hash())})
if err != nil {
return nil, err
}
kv, err := table.Save()
if err != nil {
return nil, err
}
set = append(set, kv...)
return &types.LocalDBSet{KV: set}, nil
}
func (e *evmxgo) ExecLocal_Burn(payload *evmxgotypes.EvmxgoBurn, tx *types.Transaction, receiptData *types.ReceiptData, index int) (*types.LocalDBSet, error) {
localToken, err := loadLocalToken(payload.Symbol, e.GetLocalDB())
if err != nil {
return nil, err
}
localToken = setBurn(localToken, e.GetHeight(), e.GetBlockTime(), payload.Amount)
var set []*types.KeyValue
key := calcEvmxgoStatusKeyLocal(payload.Symbol)
set = append(set, &types.KeyValue{Key: key, Value: types.Encode(localToken)})
table := NewLogsTable(e.GetLocalDB())
txIndex := dapp.HeightIndexStr(e.GetHeight(), int64(index))
err = table.Add(&evmxgotypes.LocalEvmxgoLogs{Symbol: payload.Symbol, TxIndex: txIndex, ActionType: evmxgotypes.EvmxgoActionBurn, TxHash: "0x" + hex.EncodeToString(tx.Hash())})
if err != nil {
return nil, err
}
kv, err := table.Save()
if err != nil {
return nil, err
}
set = append(set, kv...)
return &types.LocalDBSet{KV: set}, nil
}
//当区块回滚时,框架支持自动回滚localdb kv,需要对exec-local返回的kv进行封装
func (e *evmxgo) addAutoRollBack(tx *types.Transaction, kv []*types.KeyValue) *types.LocalDBSet {
dbSet := &types.LocalDBSet{}
dbSet.KV = e.AddRollbackKV(tx, tx.Execer, kv)
return dbSet
}
This diff is collapsed.
package executor
import "fmt"
/*
* 用户合约存取kv数据时,key值前缀需要满足一定规范
* 即key = keyPrefix + userKey
* 需要字段前缀查询时,使用’-‘作为分割符号
*/
var (
//KeyPrefixStateDB state db key必须前缀
KeyPrefixStateDB = "mavl-evmxgo-statedb"
//KeyPrefixLocalDB local db的key必须前缀
KeyPrefixLocalDB = "LODB-evmxgo-"
evmxgoCreatedSTONewLocal = "LODB-evmxgo-create-sto-"
)
func calcEvmxgoKey(value string) (key []byte) {
return []byte(fmt.Sprintf(KeyPrefixStateDB+"-%s", value))
}
func calcEvmxgoKeyLocal() []byte {
return []byte(evmxgoCreatedSTONewLocal)
}
func calcEvmxgoStatusKeyLocal(token string) []byte {
return []byte(fmt.Sprintf(evmxgoCreatedSTONewLocal+"%s", token))
}
//存储地址上收币的信息
func calcAddrKey(token string, addr string) []byte {
return []byte(fmt.Sprintf("LODB-evmxgo-%s-Addr:%s", token, addr))
}
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package executor
// 记录token 的更改记录,
// 包含创建完成, 铸币, 以后可能包含燃烧等
import (
dbm "github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/db/table"
"github.com/33cn/chain33/types"
evmxgotypes "github.com/33cn/plugin/plugin/dapp/evmxgo/types"
)
var opt_logs_table = &table.Option{
Prefix: "LODB-evmxgo",
Name: "logs",
Primary: "txIndex",
Index: []string{
"symbol",
},
}
// LogsRow row
type LogsRow struct {
*evmxgotypes.LocalEvmxgoLogs
}
// NewOrderRow create row
func NewOrderRow() *LogsRow {
return &LogsRow{LocalEvmxgoLogs: nil}
}
// CreateRow create row
func (r *LogsRow) CreateRow() *table.Row {
return &table.Row{Data: &evmxgotypes.LocalEvmxgoLogs{}}
}
// SetPayload set payload
func (r *LogsRow) SetPayload(data types.Message) error {
if d, ok := data.(*evmxgotypes.LocalEvmxgoLogs); ok {
r.LocalEvmxgoLogs = d
return nil
}
return types.ErrTypeAsset
}
// Get get index key
func (r *LogsRow) Get(key string) ([]byte, error) {
switch key {
case "txIndex":
return []byte(r.TxIndex), nil
case "symbol":
return []byte(r.Symbol), nil
default:
return nil, types.ErrNotFound
}
}
// NewLogsTable create table
func NewLogsTable(kvdb dbm.KV) *table.Table {
rowMeta := NewOrderRow()
err := rowMeta.SetPayload(&evmxgotypes.LocalEvmxgoLogs{})
if err != nil {
panic(err)
}
t, err := table.NewTable(rowMeta, kvdb, opt_logs_table)
if err != nil {
panic(err)
}
return t
}
func list(db dbm.KVDB, indexName string, data *evmxgotypes.LocalEvmxgoLogs, count, direction int32) ([]*table.Row, error) {
query := NewLogsTable(db).GetQuery(db)
var primary []byte
if len(data.TxIndex) > 0 {
primary = []byte(data.TxIndex)
}
cur := &LogsRow{LocalEvmxgoLogs: data}
index, err := cur.Get(indexName)
if err != nil {
elog.Error("query List failed", "key", string(primary), "param", data, "err", err)
return nil, err
}
elog.Debug("query List dbg", "indexName", indexName, "index", string(index), "primary", primary, "count", count, "direction", direction)
rows, err := query.ListIndex(indexName, index, primary, count, direction)
if err != nil {
elog.Error("query List failed", "key", string(primary), "param", data, "err", err)
return nil, err
}
if len(rows) == 0 {
return nil, types.ErrNotFound
}
return rows, nil
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment