#!/usr/bin/env bash
# shellcheck disable=SC2128
# shellcheck source=/dev/null
source ../dapp-test-common.sh

set -x
set +e

# shellcheck disable=SC2089
erc20_abi='[{\"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\"}]'
erc20_code=" "
evm_creatorAddr="1JcF5wH8PuQHHcDQECaGoqxegPc2kZcKcn"
evm_creatorAddr_key="0x238905271d330592886f8b30bef8f95fa66c87023c96b9a59638a080f7503c67"
evm_contractAddr=""
evm_addr=""
evm_transferAddr="169Ld7r2QCt9nXE9EUJpL12DhtBJwCYoyD"
#evm_transferKey="0x847d767fa4973c5386adbe9e3e9a3c01e096c54b7b12ab01fd8c469579bc2632"
txHash=""
MAIN_HTTP=""
paraName=""
gas=0

evm_SignTxAndEstimate() {
    gas=0
    local txHex="$1"
    local from=$2
    local MAIN_HTTP=$3

    req='{"method":"Chain33.Query","params":[{"execer":"evm","funcName":"EstimateGas","payload":{"tx":"'${txHex}'", "from":"'${from}'"}}]}'
    chain33_Http "$req" "${MAIN_HTTP}" '(.result != null)' "EstimateGas" ".result.gas"
    gas=$((RETURN_RESP + 10000))
    echo "the estimate gas is = ${gas}"
}

#上述未签名交易使用以下指令进行创建
#./chain33-cli evm create -b '[{"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"}]' -c " " -n "deploy erc20" -p "constructor(zbc, zbc,3300, 14KEKbYtKKQm4wMthSK9J4La4nAiidGozt)" -s erc20 -f 1 --chainID 33 --paraName user.p.para.
function evm_createContract() {
    expire="120s"
    tx=$(curl -ksd '{"method":"evm.CreateDeployTx","params":[{"code":"'${erc20_code}'", "abi":"'"${erc20_abi}"'", "note": "deploy erc20", "alias": "zbc", "parameter": "constructor(zbc, zbc, 3300, '${evm_creatorAddr}')", "expire":"'${expire}'", "paraName":"'"${paraName}"'", "amount":0}]}' "${MAIN_HTTP}" | jq -r ".result")
    evm_SignTxAndEstimate "${tx}" "${evm_creatorAddr}" "$MAIN_HTTP"

    echo "evm_createContract :: the estimate gas is = ${gas}"
    tx=$(curl -ksd '{"method":"evm.CreateDeployTx","params":[{"code":"'${erc20_code}'", "abi":"'"${erc20_abi}"'", "fee":'${gas}', "note": "deploy erc20", "alias": "zbc", "parameter": "constructor(zbc, zbc, 3300, '${evm_creatorAddr}')", "expire":"'${expire}'", "paraName":"'"${paraName}"'", "amount":0}]}' "${MAIN_HTTP}" | jq -r ".result")
    chain33_SignAndSendTx "${tx}" "${evm_creatorAddr_key}" "$MAIN_HTTP" "${expire}" "${gas}"
    txHash=$RAW_TX_HASH

    queryTransaction "jq -r .result.receipt.tyName" "ExecOk"
    echo "CreateContract queryExecRes end"
    chain33_BlockWait 1 "$MAIN_HTTP"
}

# $1 parameter; $2 caller; $3 resok unpackData 匹配的数据
function evm_callQuery() {
    local parameter=$1
    local callerAddr=$2
    local resok=$3

    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"
    echo "$RETURN_RESP"

    req='{"method":"Chain33.Query","params":[{"execer":"evm","funcName":"Query","payload":{"address":"'${evm_contractAddr}'","input":"'${RETURN_RESP}'","caller":"'${callerAddr}'"}}]}'
    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}'","parameter":"'${parameter}'","data":"'${RETURN_RESP}'"}}]}'
    chain33_Http "$req" "${MAIN_HTTP}" '(.result != null)' "GetUnpackData" ".result.unpackData[0]"
    echo "$RETURN_RESP"

    [ "${RETURN_RESP}" == "${resok}" ]
    rst=$?
    echo_rst "$parameter query" "$rst"
}

function evm_addressCheck() {
    req='{"method":"Chain33.Query","params":[{"execer":"evm","funcName":"CheckAddrExists","payload":{"addr":"'${evm_contractAddr}'"}}]}'
    resok='(.result.contract == true) and (.result.contractAddr == "'"$evm_contractAddr"'")'
    chain33_Http "$req" "${MAIN_HTTP}" "${resok}" "CheckAddrExists"

    evm_callQuery "symbol()" "${evm_creatorAddr}" "zbc"
}

function evm_transfer() {
    expire="120s"

    tx=$(curl -ksd '{"method":"evm.CreateCallTx","params":[{"abi":"'"${erc20_abi}"'", "note": "evm transfer rpc test", "parameter": "transfer('${evm_transferAddr}', 20)", "expire":"'${expire}'", "contractAddr":"'"${evm_contractAddr}"'", "paraName":"'"${paraName}"'"}]}' "${MAIN_HTTP}" | jq -r ".result")
    evm_SignTxAndEstimate "${tx}" "${evm_creatorAddr}" "$MAIN_HTTP"

    # shellcheck disable=SC2090
    tx=$(curl -ksd '{"method":"evm.CreateCallTx","params":[{"abi":"'"${erc20_abi}"'", "fee":'${gas}', "note": "evm transfer rpc test", "parameter": "transfer('${evm_transferAddr}', 20)", "expire":"'${expire}'", "contractAddr":"'"${evm_contractAddr}"'", "paraName":"'"${paraName}"'"}]}' "${MAIN_HTTP}" | jq -r ".result")
    chain33_SignAndSendTx "${tx}" "${evm_creatorAddr_key}" "$MAIN_HTTP" "${expire}" "${gas}"

    evm_callQuery "balanceOf(${evm_creatorAddr})" "${evm_creatorAddr}" "3280"
    evm_callQuery "balanceOf(${evm_transferAddr})" "${evm_transferAddr}" "20"
}

# 查询交易的执行结果
# 根据传入的规则，校验查询的结果 （参数1: 校验规则 参数2: 预期匹配结果）
function queryTransaction() {
    validators=$1
    expectRes=$2
    echo "txHash=${txHash}"

    res=$(curl -s --data-binary '{"jsonrpc":"2.0","id":2,"method":"Chain33.QueryTransaction","params":[{"hash":"'"${txHash}"'"}]}' -H 'content-type:text/plain;' "${MAIN_HTTP}")

    times=$(echo "${validators}" | awk -F '|' '{print NF}')
    for ((i = 1; i <= times; i++)); do
        validator=$(echo "${validators}" | awk -F '|' '{print $'"$i"'}')
        res=$(echo "${res}" | ${validator})
    done

    if [ "${res}" != "${expectRes}" ]; then
        return 1
    else
        res=$(curl -s --data-binary '{"jsonrpc":"2.0","id":2,"method":"Chain33.QueryTransaction","params":[{"hash":"'"${txHash}"'"}]}' -H 'content-type:text/plain;' "${MAIN_HTTP}")
        if [ "${evm_addr}" == "" ]; then
            if [ "$ispara" == false ]; then
                evm_addr="user.evm.${txHash}"
            else
                evm_addr="user.p.para.user.evm.${txHash}"
            fi
        fi

        if [ "${evm_contractAddr}" == "" ]; then
            # 去掉 hash 前面的 0x
            txhash=${txHash:2}
            evm_contractAddr=$(curl -ksd '{"method":"evm.CalcNewContractAddr","params":[{"caller":"'"${evm_creatorAddr}"'","txhash":"'"${txhash}"'"}]}' "${MAIN_HTTP}" | jq -r ".result")
        fi
        return 0
    fi
}

function init() {
    ispara=$(echo '"'"${MAIN_HTTP}"'"' | jq '.|contains("8901")')
    echo "ipara=$ispara"

    local main_ip=${MAIN_HTTP//8901/8801}
    chain33_ImportPrivkey "${evm_creatorAddr_key}" "${evm_creatorAddr}" "evm_test" "${main_ip}"

    local from="${evm_creatorAddr}"
    local evm_addr=""

    if [ "$ispara" == false ]; then
        chain33_applyCoins "$from" 12000000000 "${main_ip}"
        chain33_QueryBalance "${from}" "$main_ip"

        evm_addr=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"evm"}]}' "${MAIN_HTTP}" | jq -r ".result")
    else
        paraName="user.p.para."

        chain33_applyCoins "$from" 1000000000 "${main_ip}"
        chain33_QueryBalance "${from}" "$main_ip"

        local para_ip="${MAIN_HTTP}"
        chain33_ImportPrivkey "${evm_creatorAddr_key}" "${evm_creatorAddr}" "evm_para_test" "$para_ip"

        chain33_applyCoins "$from" 12000000000 "${para_ip}"
        chain33_QueryBalance "${from}" "$para_ip"

        evm_addr=$(curl -ksd '{"method":"Chain33.ConvertExectoAddr","params":[{"execname":"user.p.para.evm"}]}' "${MAIN_HTTP}" | jq -r ".result")
        chain33_SendToAddress "$from" "$evm_addr" 10000000000 "$MAIN_HTTP"
    fi

    echo "evm=$evm_addr"
    chain33_SendToAddress "$from" "$evm_addr" 10000000000 "$MAIN_HTTP"
}

function run_test() {
    # 部署合约
    evm_createContract

    # 检查合约地址是否存在
    evm_addressCheck

    # 转帐
    evm_transfer
}

function main() {
    chain33_RpcTestBegin evm

    MAIN_HTTP=$1
    echo "main_ip=$MAIN_HTTP"

    init
    run_test

    chain33_RpcTestRst evm "$CASE_ERR"
}

chain33_debug_function main "$1"
