Skip to content

Commit

Permalink
Feature: add gas price estimation feature to zcnbridge (0chain#1428)
Browse files Browse the repository at this point in the history
* feature: added gas price estimation with the usage of Alchemy provider

* fix: fixed bugs

* fix: fixed bugs

* feature: updated go version in a workflow

* fix: fixed bugs

* fix: fixed bridge tests

* fix: fixed bugs

* feature: updated go version

* fix: fixed bugs

* fix: fixed bugs

* fix: fixed bugs

* feature: avoided linting for function in wasmsdk

* fix: fixed bridge tests

* fix: fixed bugs

* fix: fixed bugs

* fix: fixed bugs

* fix: fixed bridge tests

* fix: fixed bugs

* fix: fixed bugs
  • Loading branch information
YarikRevich authored Mar 17, 2024
1 parent cfe9bea commit 973aeb0
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 24 deletions.
4 changes: 0 additions & 4 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ jobs:
run: |
sudo apt update -y
sudo apt -y install build-essential nghttp2 libnghttp2-dev libssl-dev wget
# - uses: actions/setup-go@v3
# with:
# go-version: '1.20'
- name: "Setup Go"
shell: 'script --return --quiet --command "bash {0}"'
Expand Down
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/shopspring/decimal v1.3.1
github.com/spf13/viper v1.15.0
github.com/stretchr/testify v1.8.1
github.com/stretchr/testify v1.8.4
github.com/tyler-smith/go-bip39 v1.1.0
github.com/uptrace/bunrouter v1.0.20
go.dedis.ch/kyber/v3 v3.1.0
Expand All @@ -46,7 +46,7 @@ require (
require (
github.com/hashicorp/golang-lru v0.5.5-0.20210104140557-80c98217689d
github.com/minio/sha256-simd v1.0.1
github.com/valyala/fasthttp v1.51.0
github.com/ybbus/jsonrpc/v3 v3.1.5
)

require (
Expand Down Expand Up @@ -116,6 +116,7 @@ require (
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/urfave/cli/v2 v2.17.2-0.20221006022127-8f469abc00aa // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.51.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.dedis.ch/fixbuf v1.0.3 // indirect
go.opencensus.io v0.24.0 // indirect
Expand Down
11 changes: 4 additions & 7 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -299,12 +299,6 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/herumi/bls-go-binary v1.31.0 h1:L1goQ2tMtGgpXCg5AwHAdJQpLs/pfnWWEc3Wog6OhmI=
github.com/herumi/bls-go-binary v1.31.0/go.mod h1:O4Vp1AfR4raRGwFeQpr9X/PQtncEicMoOe6BQt1oX0Y=
github.com/hitenjain14/fasthttp v0.0.0-20240201092245-8e4835c0e974 h1:oEjH9SSKBlzwDyYjzZaqRpxo7GlfUJCyRoOk7QHKSDs=
github.com/hitenjain14/fasthttp v0.0.0-20240201092245-8e4835c0e974/go.mod h1:RZMcXy7u4S+E97IXYTe7WHZ3+mCYOh4vys8PkIGZeXk=
github.com/hitenjain14/fasthttp v0.0.0-20240223160417-7458814cf3d0 h1:XCrNCir8+zDo+Ku7B+AXhzFnsJvSelx1YbQQTNpxtqI=
github.com/hitenjain14/fasthttp v0.0.0-20240223160417-7458814cf3d0/go.mod h1:RZMcXy7u4S+E97IXYTe7WHZ3+mCYOh4vys8PkIGZeXk=
github.com/hitenjain14/fasthttp v0.0.0-20240228200624-800f4e3a9663 h1:OS1ehSzPOz32fw+mgLL6f2dHXweh4sEB62jyLVwT7NI=
github.com/hitenjain14/fasthttp v0.0.0-20240228200624-800f4e3a9663/go.mod h1:RZMcXy7u4S+E97IXYTe7WHZ3+mCYOh4vys8PkIGZeXk=
github.com/hitenjain14/fasthttp v0.0.0-20240229173600-722723e15e17 h1:FbyIK0BfvXVZTOxKOe2dlxJqSPSF2ZXOv2Mc7dvS7sc=
github.com/hitenjain14/fasthttp v0.0.0-20240229173600-722723e15e17/go.mod h1:RZMcXy7u4S+E97IXYTe7WHZ3+mCYOh4vys8PkIGZeXk=
github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao=
Expand Down Expand Up @@ -517,8 +511,9 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
Expand Down Expand Up @@ -546,6 +541,8 @@ github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6Ut
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/ybbus/jsonrpc/v3 v3.1.5 h1:0cC/QzS8OCuXYqqDbYnKKhsEe+IZLrNlDx8KPCieeW0=
github.com/ybbus/jsonrpc/v3 v3.1.5/go.mod h1:U1QbyNfL5Pvi2roT0OpRbJeyvGxfWYSgKJHjxWdAEeE=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
18 changes: 18 additions & 0 deletions wasmsdk/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func initBridge(
tokenAddress,
authorizersAddress,
ethereumAddress,
ethereumNodeURL,
"",
gasLimit,
consensusThreshold,
Expand Down Expand Up @@ -169,3 +170,20 @@ func getNotProcessedZCNBurnTickets() string {

return string(result)
}

// estimateGasPrice performs gas estimation for the given transaction using Alchemy enhanced API returning
// approximate final gas fee.
func estimateGasPrice(from, to string, value int64) string { // nolint:golint,unused
estimateGasPriceResponse, err := bridge.EstimateGasPrice(context.Background(), from, to, value)
if err != nil {
return errors.Wrap("estimateGasPrice", "failed to estimate gas price", err).Error()
}

var result []byte
result, err = json.Marshal(estimateGasPriceResponse)
if err != nil {
return errors.Wrap("estimateGasPrice", "failed to marshal gas price estimation result", err).Error()
}

return string(result)
}
1 change: 1 addition & 0 deletions wasmsdk/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ func main() {
"getMintWZCNPayload": getMintWZCNPayload,
"getNotProcessedWZCNBurnEvents": getNotProcessedWZCNBurnEvents,
"getNotProcessedZCNBurnTickets": getNotProcessedZCNBurnTickets,
"estimateGasPrice": estimateGasPrice,

//zcn
"getWalletBalance": getWalletBalance,
Expand Down
70 changes: 69 additions & 1 deletion zcnbridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ import (
"encoding/hex"
"encoding/json"
"fmt"
"github.com/0chain/gosdk/zcnbridge/ethereum/bancortoken"
"io"
"math/big"
"strconv"
"strings"
"time"

"github.com/ybbus/jsonrpc/v3"

"github.com/0chain/gosdk/zcnbridge/ethereum/bancortoken"

"github.com/0chain/common/core/currency"
"github.com/0chain/gosdk/zcnbridge/ethereum/bancornetwork"
"github.com/0chain/gosdk/zcnbridge/ethereum/zcntoken"
Expand Down Expand Up @@ -993,3 +997,67 @@ func (b *BridgeClient) prepareBridge(ctx context.Context, ethereumAddress, metho

return bridgeInstance, transactOpts, nil
}

// isEstimateGasPriceAvailable checks if currently selected ethereum node url can be used for gas estimation.
func (b *BridgeClient) isEstimateGasPriceAvailable() bool {
return strings.Contains(b.EthereumNodeURL, "eth-mainnet.g.alchemy.com")
}

// EstimateGasPrice performs gas estimation for the given transaction using Alchemy enhanced API returning
// approximate final gas fee.
func (b *BridgeClient) EstimateGasPrice(ctx context.Context, from, to string, value int64) (*GasPriceEstimationResult, error) {
if !b.isEstimateGasPriceAvailable() {
return nil, errors.New("used json-rpc does not allow to estimate gas price")
}

client := jsonrpc.NewClient(b.EthereumNodeURL)

valueHex := ConvertIntToHex(value)

resp, err := client.Call(ctx, "eth_estimateGas", &GasEstimationRequest{
From: from, To: to, Value: valueHex})
if err != nil {
return nil, errors.Wrap(err, "gas price estimation failed")
}

if resp.Error != nil {
return nil, errors.Wrap(errors.New(resp.Error.Error()), "gas price estimation failed")
}

gasAmountRaw, ok := resp.Result.(string)
if !ok {
return nil, errors.New("failed to parse gas amount")
}

gasAmountInt := new(big.Float)
gasAmountInt.SetString(gasAmountRaw)

gasAmountFloat, _ := gasAmountInt.Float64()

fmt.Println(gasAmountFloat)

resp, err = client.Call(ctx, "eth_gasPrice")
if err != nil {
return nil, errors.Wrap(err, "gas price estimation failed")
}

if resp.Error != nil {
return nil, errors.Wrap(errors.New(resp.Error.Error()), "gas price estimation failed")
}

var gasPriceRaw string
gasPriceRaw, ok = resp.Result.(string)
if !ok {
return nil, errors.New("failed to parse gas price")
}

gasPriceInt := new(big.Float)
gasPriceInt.SetString(gasPriceRaw)

gasPriceFloat, _ := gasPriceInt.Float64()

fmt.Println(gasPriceFloat)

return &GasPriceEstimationResult{
Value: gasPriceFloat * gasAmountFloat}, nil
}
17 changes: 17 additions & 0 deletions zcnbridge/bridge_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@ import (
"github.com/pkg/errors"
)

// GasEstimationRequest describes request used for Alchemy enhanced JSON-RPC API.
type GasEstimationRequest struct {
From string `json:"from"`
To string `json:"to"`
Value string `json:"value"`
}

// GasPriceEstimationResult represents result of the gas price estimation operation execution.
type GasPriceEstimationResult struct {
Value float64 `json:"value"`
}

// BancorTokenDetails describes Bancor ZCN zcntoken pool details
type BancorTokenDetails struct {
Data struct {
Expand Down Expand Up @@ -74,3 +86,8 @@ func addPercents(gasLimitUnits uint64, percents int) *big.Int {

return gasLimitBig
}

// ConvertIntToHex converts given int value to hex string.
func ConvertIntToHex(value int64) string {
return fmt.Sprintf("%#x", value)
}
31 changes: 26 additions & 5 deletions zcnbridge/bridge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/0chain/gosdk/zcnbridge/ethereum/bancornetwork"
"github.com/0chain/gosdk/zcnbridge/ethereum/zcntoken"
"log"
"math/big"
"net/http"
Expand All @@ -18,6 +16,9 @@ import (
"testing"
"time"

"github.com/0chain/gosdk/zcnbridge/ethereum/bancornetwork"
"github.com/0chain/gosdk/zcnbridge/ethereum/zcntoken"

sdkcommon "github.com/0chain/gosdk/core/common"
"github.com/0chain/gosdk/zcnbridge/ethereum"
"github.com/0chain/gosdk/zcnbridge/ethereum/authorizers"
Expand All @@ -39,7 +40,12 @@ import (

const (
ethereumAddress = "0xD8c9156e782C68EE671C09b6b92de76C97948432"
password = "02289b9"

alchemyEthereumNodeURL = "https://eth-mainnet.g.alchemy.com/v2/9VanLUbRE0pLmDHwCHGJlhs9GHosrfD9"
infuraEthereumNodeURL = "https://mainnet.infura.io/v3/7238211010344719ad14a89db874158c"
value = 1e+10

password = "02289b9"

authorizerDelegatedAddress = "0xa149B58b7e1390D152383BB03dBc79B390F648e2"

Expand Down Expand Up @@ -216,7 +222,7 @@ func getEthereumClient(t mock.TestingT) *bridgemocks.EthereumClient {
return bridgemocks.NewEthereumClient(&ethereumClientMock{t})
}

func getBridgeClient(bancorAPIURL string, ethereumClient EthereumClient, transactionProvider transaction.TransactionProvider, keyStore KeyStore) *BridgeClient {
func getBridgeClient(bancorAPIURL, ethereumNodeURL string, ethereumClient EthereumClient, transactionProvider transaction.TransactionProvider, keyStore KeyStore) *BridgeClient {
cfg := viper.New()

tempConfigFile, err := os.CreateTemp(".", "config.yaml")
Expand Down Expand Up @@ -246,6 +252,7 @@ func getBridgeClient(bancorAPIURL string, ethereumClient EthereumClient, transac
cfg.GetString("bridge.token_address"),
cfg.GetString("bridge.authorizers_address"),
cfg.GetString("bridge.ethereum_address"),
ethereumNodeURL,
cfg.GetString("bridge.password"),
cfg.GetUint64("bridge.gas_limit"),
cfg.GetFloat64("bridge.consensus_threshold"),
Expand Down Expand Up @@ -349,7 +356,7 @@ func Test_ZCNBridge(t *testing.T) {

bancorMockServerURL := prepareBancorMockServer()

bridgeClient := getBridgeClient(bancorMockServerURL, ethereumClient, transactionProvider, keyStore)
bridgeClient := getBridgeClient(bancorMockServerURL, alchemyEthereumNodeURL, ethereumClient, transactionProvider, keyStore)

t.Run("should update authorizer config.", func(t *testing.T) {
source := &authorizerNodeSource{
Expand Down Expand Up @@ -620,4 +627,18 @@ func Test_ZCNBridge(t *testing.T) {
time.Second*2,
))
})

t.Run("should check if gas price estimation works with correct ethereum node url", func(t *testing.T) {
bridgeClient = getBridgeClient(bancorMockServerURL, alchemyEthereumNodeURL, ethereumClient, transactionProvider, keyStore)

_, err := bridgeClient.EstimateGasPrice(context.Background(), tokenAddress, bridgeAddress, value)
require.Contains(t, err.Error(), "Must be authenticated!")
})

t.Run("should check if gas price estimation works with incorrect ethereum node url", func(t *testing.T) {
bridgeClient = getBridgeClient(bancorMockServerURL, infuraEthereumNodeURL, ethereumClient, transactionProvider, keyStore)

_, err := bridgeClient.EstimateGasPrice(context.Background(), tokenAddress, bridgeAddress, value)
require.Error(t, err)
})
}
11 changes: 9 additions & 2 deletions zcnbridge/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package zcnbridge
import (
"context"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"math/big"
"path"

"github.com/ethereum/go-ethereum/accounts/abi/bind"

"github.com/0chain/gosdk/zcnbridge/log"
"github.com/0chain/gosdk/zcnbridge/transaction"
"github.com/ethereum/go-ethereum/ethclient"
Expand Down Expand Up @@ -55,6 +56,7 @@ type BridgeClient struct {
AuthorizersAddress,
NFTConfigAddress,
EthereumAddress,
EthereumNodeURL,
Password string

BancorAPIURL string
Expand All @@ -69,6 +71,7 @@ func NewBridgeClient(
tokenAddress,
authorizersAddress,
ethereumAddress,
ethereumNodeURL,
password string,
gasLimit uint64,
consensusThreshold float64,
Expand All @@ -81,6 +84,7 @@ func NewBridgeClient(
TokenAddress: tokenAddress,
AuthorizersAddress: authorizersAddress,
EthereumAddress: ethereumAddress,
EthereumNodeURL: ethereumNodeURL,
Password: password,
GasLimit: gasLimit,
ConsensusThreshold: consensusThreshold,
Expand Down Expand Up @@ -120,7 +124,9 @@ func SetupBridgeClientSDK(cfg *BridgeSDKConfig) *BridgeClient {

chainCfg := initChainConfig(cfg)

ethereumClient, err := ethclient.Dial(chainCfg.GetString("ethereum_node_url"))
ethereumNodeURL := chainCfg.GetString("ethereum_node_url")

ethereumClient, err := ethclient.Dial(ethereumNodeURL)
if err != nil {
Logger.Error(err)
}
Expand All @@ -139,6 +145,7 @@ func SetupBridgeClientSDK(cfg *BridgeSDKConfig) *BridgeClient {
chainCfg.GetString("bridge.token_address"),
chainCfg.GetString("bridge.authorizers_address"),
chainCfg.GetString("bridge.ethereum_address"),
ethereumNodeURL,
chainCfg.GetString("bridge.password"),
chainCfg.GetUint64("bridge.gas_limit"),
chainCfg.GetFloat64("bridge.consensus_threshold"),
Expand Down
8 changes: 5 additions & 3 deletions znft/example/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
module example

go 1.18
go 1.21

toolchain go1.21.0

require github.com/0chain/gosdk v1.8.9

Expand All @@ -23,8 +25,8 @@ require (
github.com/tklauser/numcpus v0.6.0 // indirect
github.com/tyler-smith/go-bip39 v1.1.0 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.6.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/sys v0.15.0 // indirect
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
Expand Down
2 changes: 2 additions & 0 deletions znft/example/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg=
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
Expand All @@ -159,6 +160,7 @@ golang.org/x/sys v0.1.0 h1:kunALQeHf1/185U1i0GOB/fy1IPRDDpuoOOqRReG57U=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
Expand Down

0 comments on commit 973aeb0

Please sign in to comment.