Skip to content

Commit

Permalink
Merge branch 'main' into woz/ci
Browse files Browse the repository at this point in the history
  • Loading branch information
adamewozniak authored Jul 18, 2024
2 parents de45d61 + 37218d4 commit 794c226
Show file tree
Hide file tree
Showing 16 changed files with 456 additions and 168 deletions.
8 changes: 3 additions & 5 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
PRIVATE_KEY=yourprivatekeyhere
CONTRACT_KEY=yourkeyhere
MAINNET=FALSE
OJO_CONTRACT_ADDRESS=0x0
AXELAR_GAS_RECEIVER_ADDRESS=0x2d5d7d31F671F86C782533cc367F14109a082712
CREATE2_DEPLOYER_ADDRESS=0x98b2920d53612483f91f12ed7754e51b4a77919e
EVM_CHAINS=["Ethereum"]
OJO_CHAIN=ojo
OJO_ADDRESS=ojo1es9mhmnunh208ucwq8rlrl97hqulxrz8k37dcu
RESOLVE_WINDOW=7200
ASSET_LIMIT=5
PRICE_FEED_IMPLEMENTATION_CONTRACT_ADDRESS=0xD1077c12ba7C0ED41d288F5505af2Cb23bBD680a
CLONE_FACTORY_CONTRACT_ADDRESS=0x9AaE2ac2637B9f441d1537bBdCEB712854dd426B
PRICE_FEED_DECIMALS=9
PRICE_FEED_DESCRIPTIONS=["steakLRT", "Re7LRT", "amphrETH", "rstETH"]
33 changes: 30 additions & 3 deletions mainnet_chains.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,47 @@
"chainId": 42161,
"gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31",
"rpc": "https://arbitrum-mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161",
"tokenSymbol": "ETH"
"tokenSymbol": "ETH",
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712",
"ojoContract": "0x5BB3E85f91D08fe92a3D123EE35050b763D6E6A7",
"create2Deployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e",
"priceFeedImplementation": "0xa1aB70C0F3725AcA1D1e85Bd4402Dd2d5F6AFf19",
"cloneFactory": "0xd285A4F0Ad1BB6b1Db8cD3dD839E9f423938ef9E"
},
{
"name": "Optimism",
"chainId": 10,
"gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31",
"rpc": "https://optimism-mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161",
"tokenSymbol": "ETH"
"tokenSymbol": "ETH",
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712",
"ojoContract": "0x5BB3E85f91D08fe92a3D123EE35050b763D6E6A7",
"create2Deployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e",
"priceFeedImplementation": "0xfaC9d315b9b558e10eBdb0462aA42577aADe6601",
"cloneFactory": "0x02Ed15B70D4dE1209c3Dd5a75195CB3f3dDB8B07"
},
{
"name": "Base",
"chainId": 8453,
"gateway": "0xe432150cce91c13a887f7D836923d5597adD8E31",
"rpc": "https://developer-access-mainnet.base.org",
"tokenSymbol": "ETH"
"tokenSymbol": "ETH",
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712",
"ojoContract": "0x5BB3E85f91D08fe92a3D123EE35050b763D6E6A7",
"create2Deployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e",
"priceFeedImplementation": "0x09d43904C8ABd470df1B793df68904A9714558CF",
"cloneFactory": "0xfaC9d315b9b558e10eBdb0462aA42577aADe6601"
},
{
"name": "Ethereum",
"chainId": 1,
"gateway": "0x4F4495243837681061C4743b74B3eEdf548D56A5",
"rpc": "https://mainnet.infura.io/v3/9aa3d95b3bc440fa88ea12eaa4456161",
"tokenSymbol": "ETH",
"gasReceiver": "0x2d5d7d31F671F86C782533cc367F14109a082712",
"ojoContract": "0x5BB3E85f91D08fe92a3D123EE35050b763D6E6A7",
"create2Deployer": "0x98b2920d53612483f91f12ed7754e51b4a77919e",
"priceFeedImplementation": "0xde471274F1B684476d341eB131224F389AD4A270",
"cloneFactory": "0x710C8a3c8CB393cA24748849de3585b5C48D4D0c"
}
]
24 changes: 15 additions & 9 deletions relayer/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,15 @@ var (
type (
// Config defines all necessary configuration parameters.
Config struct {
ConfigDir string `mapstructure:"config_dir"`
Account Account `mapstructure:"account" validate:"required,gt=0,dive,required"`
Keyring Keyring `mapstructure:"keyring" validate:"required,gt=0,dive,required"`
RPC RPC `mapstructure:"rpc" validate:"required,gt=0,dive,required"`
Gas uint64 `mapstructure:"gas"`
GasPrices string `mapstructure:"gas_prices"`
Relayer Relayer `mapstructure:"relayer" validate:"required,gt=0,dive,required"`
Assets []Assets `mapstructure:"assets" validate:"required,gt=0,dive,required"`
ConfigDir string `mapstructure:"config_dir"`
Account Account `mapstructure:"account" validate:"required,gt=0,dive,required"`
Keyring Keyring `mapstructure:"keyring" validate:"required,gt=0,dive,required"`
RPC RPC `mapstructure:"rpc" validate:"required,gt=0,dive,required"`
Gas uint64 `mapstructure:"gas"`
GasPrices string `mapstructure:"gas_prices"`
Relayer Relayer `mapstructure:"relayer" validate:"required,gt=0,dive,required"`
Assets []Assets `mapstructure:"assets" validate:"required,gt=0,dive,required"`
AxelarGas AxelarGas `mapstructure:"axelar_gas" validate:"required,gt=0,dive,required"`
}

// Account defines account related configuration that is related to the Ojo
Expand Down Expand Up @@ -56,7 +57,12 @@ type (
Deviation float64 `mapstructure:"deviation" validate:"required"`
Destination string `mapstructure:"destination" validate:"required"`
Contract string `mapstructure:"contract" validate:"required"`
Tokens string `mapstructure:"tokens" validate:"required"`
}

AxelarGas struct {
Denom string `mapstructure:"denom" validate:"required"`
Multiplier string `mapstructure:"multiplier" validate:"required"`
Default string `mapstructure:"default" validate:"required"`
}

Assets struct {
Expand Down
7 changes: 6 additions & 1 deletion relayer/relayer.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ interval = "24h"
deviation = "0.05"
destination = "Arbitrum"
contract = "0x001"
tokens = "100ibc/xyz"

# These are the assets we want to periodically push:
[[assets]]
denom = "BTC"
[[assets]]
denom = "ETH"

# This struct is used to estimate the gas prices to pay axelar
[axelar_gas]
denom = "ibc/xyz"
multiplier = "1.2"
default = "1000000"
5 changes: 4 additions & 1 deletion relayer/relayer/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,10 @@ func (rc RelayerClient) BroadcastTx(nextBlockHeight, timeoutHeight int64, msgs .
resp, err := BroadcastTx(clientCtx, factory, msgs...)
if resp != nil && resp.Code != 0 {
telemetry.IncrCounter(1, "failure", "tx", "code")
err = fmt.Errorf("invalid response code from tx: %d", resp.Code)
err = fmt.Errorf("invalid response code from tx: %d. msg: %s",
resp.Code,
resp.RawLog,
)
}
if err != nil {
var (
Expand Down
100 changes: 100 additions & 0 deletions relayer/relayer/client/gas_estimate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package client

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"

math "cosmossdk.io/math"
)

// Assuming the endpoint URL is something like this
const (
endpointURL = "https://api.axelarscan.io/gmp/estimateGasFee"
sourceChain = "ojo"
)

// executeData is an example value used to estimate
// the cost of a GMP relay. In practice, this value is constructed
// by the Ojo validators dynamically.
// Ref: https://github.com/ojo-network/ojo/blob/2965d45976ea63053dc84b910b37ea46a06730b5/x/gmp/keeper/keeper.go#L88
// nolint: lll
const executeData = "0x00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000b20000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b60000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000205245374c52540000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003a2642918000000000000000000000000000000000000000000000000000000000066960af100000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000006a0000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000005eebff00000000000000000000000000000000000000000000000000000000005ee4f700000000000000000000000000000000000000000000000000000000005eddef00000000000000000000000000000000000000000000000000000000005ed6e700000000000000000000000000000000000000000000000000000000005ecfdf00000000000000000000000000000000000000000000000000000000005ec8d700000000000000000000000000000000000000000000000000000000005ec1cf00000000000000000000000000000000000000000000000000000000005ebac700000000000000000000000000000000000000000000000000000000005eb3bf00000000000000000000000000000000000000000000000000000000005eacb700000000000000000000000000000000000000000000000000000000005ea5af00000000000000000000000000000000000000000000000000000000005e9ea700000000000000000000000000000000000000000000000000000000005e979f00000000000000000000000000000000000000000000000000000000005e909700000000000000000000000000000000000000000000000000000000005e898f00000000000000000000000000000000000000000000000000000000005e828700000000000000000000000000000000000000000000000000000000005e7b7f00000000000000000000000000000000000000000000000000000000005e747700000000000000000000000000000000000000000000000000000000005e6d6f00000000000000000000000000000000000000000000000000000000005f0f2700000000000000000000000000000000000000000000000000000000005f081f00000000000000000000000000000000000000000000000000000000005f011700000000000000000000000000000000000000000000000000000000005efa0f00000000000000000000000000000000000000000000000000000000005ef307000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000396fb886e0000000000000000000000000000000000000000000000000000000390b235200000000000000000000000000000000000000000000000000000000392e8739f000000000000000000000000000000000000000000000000000000039341dbce000000000000000000000000000000000000000000000000000000038de6f3a8000000000000000000000000000000000000000000000000000000037fb311860000000000000000000000000000000000000000000000000000000376da178a00000000000000000000000000000000000000000000000000000003677c2f7600000000000000000000000000000000000000000000000000000003674094ac0000000000000000000000000000000000000000000000000000000365daf3f000000000000000000000000000000000000000000000000000000003693b3861000000000000000000000000000000000000000000000000000000036cd7179c0000000000000000000000000000000000000000000000000000000368e1d032000000000000000000000000000000000000000000000000000000036386e80c0000000000000000000000000000000000000000000000000000000364b0edfe00000000000000000000000000000000000000000000000000000003632d7fdd000000000000000000000000000000000000000000000000000000035f383873000000000000000000000000000000000000000000000000000000035d01f9f4000000000000000000000000000000000000000000000000000000035cc65f2a00000000000000000000000000000000000000000000000000000003b1dfde9100000000000000000000000000000000000000000000000000000003b46f853f00000000000000000000000000000000000000000000000000000003b522559d00000000000000000000000000000000000000000000000000000003a61dd5b8000000000000000000000000000000000000000000000000000000039e15797f000000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000029baff41400000000000000000000000000000000000000000000000000000001b79f446d000000000000000000000000000000000000000000000000000000025c7afe17000000000000000000000000000000000000000000000000000000026b4946bc000000000000000000000000000000000000000000000000000000016f821e43000000000000000000000000000000000000000000000000000000062b0deeee00000000000000000000000000000000000000000000000000000002882b577e00000000000000000000000000000000000000000000000000000003cf8ec3f800000000000000000000000000000000000000000000000000000000da9873a400000000000000000000000000000000000000000000000000000000fe66049e000000000000000000000000000000000000000000000000000000014fadc3c300000000000000000000000000000000000000000000000000000001912acb0e00000000000000000000000000000000000000000000000000000000ecec7ca600000000000000000000000000000000000000000000000000000002ffe0015500000000000000000000000000000000000000000000000000000001919cfdd300000000000000000000000000000000000000000000000000000003b249cbd0000000000000000000000000000000000000000000000000000000011c81159200000000000000000000000000000000000000000000000000000000d5a49cb800000000000000000000000000000000000000000000000000000000f1dedade00000000000000000000000000000000000000000000000000000001e84f443f00000000000000000000000000000000000000000000000000000001b9921fc6000000000000000000000000000000000000000000000000000000071e341559000000000000000000000000000000000000000000000000000000043b0ba83e000000000000000000000000000000000000000000000000000000021ec0616700000000000000000000000000000000000000000000000000000000000000015245374c525400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

// RequestBody defines the structure of the request body.
// Adjust the fields according to the actual API requirements.
type RequestBody struct {
DestinationChain string `json:"destinationChain"`
ExecuteData string `json:"executeData"`
DestinationAddress string `json:"destinationAddress"`
GasLimit string `json:"gasLimit"`
SourceChain string `json:"sourceChain"`
ShowDetailedFees bool `json:"showDetailedFees"`
}
type ResponseBody struct {
TotalFee string `json:"totalFee"`
Message string `json:"message"`
Error bool `json:"error"`
}

// EstimateGasFee performs a JSON POST request to estimate gas fee on Axelar.
// Its output is a math.Int representing the total fee
// denominated in uaxl.
func EstimateGasFee(
destinationChain,
destinationAddress,
gasLimit,
multiplier string,
) (math.Int, error) {
// construct and perform request
body := RequestBody{
DestinationChain: destinationChain,
ExecuteData: executeData,
DestinationAddress: destinationAddress,
GasLimit: gasLimit,
SourceChain: sourceChain,
ShowDetailedFees: true,
}
jsonBody, err := json.Marshal(body)
if err != nil {
return math.ZeroInt(), err
}
req, err := http.NewRequest("POST", endpointURL, bytes.NewBuffer(jsonBody))
if err != nil {
return math.ZeroInt(), err
}
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return math.ZeroInt(), err
}
defer resp.Body.Close()

// parse response
responseBody := &ResponseBody{}
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return math.ZeroInt(), err
}
err = json.Unmarshal(respBody, responseBody)
if err != nil {
return math.ZeroInt(), err
}
if responseBody.Error {
return math.ZeroInt(), fmt.Errorf(responseBody.Message)
}

// execute multiplier
fee, ok := math.NewIntFromString(responseBody.TotalFee)
if !ok {
return math.ZeroInt(), fmt.Errorf("failed to convert total fee to int")
}
m, ok := math.NewIntFromString(multiplier)
if !ok {
return fee, nil
}
return fee.Mul(m), nil
}
30 changes: 21 additions & 9 deletions relayer/relayer/relayer.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@ package relayer

import (
"context"
"strings"
"fmt"
"time"

"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
"github.com/ojo-network/ojo-evm/relayer/config"
"github.com/ojo-network/ojo-evm/relayer/relayer/client"
gmptypes "github.com/ojo-network/ojo/x/gmp/types"
pfsync "github.com/ojo-network/price-feeder/pkg/sync"
"github.com/rs/zerolog"

math "cosmossdk.io/math"
)

const (
Expand Down Expand Up @@ -198,7 +199,7 @@ func (r *Relayer) tick(ctx context.Context) error {
}
r.updateMemory(ctx, batch)
} else {
r.logger.Info().Msg("no relays necessary")
r.logger.Debug().Msg("no relays necessary")
}

return nil
Expand Down Expand Up @@ -229,15 +230,26 @@ func deviated(existingPrice float64, newestPrice float64, threshold float64) (fl
// relay sends a relay message to the Ojo node.
func (r Relayer) relay(denoms []string) error {
r.logger.Info().Strs("denoms", denoms).Msg("submitting relay tx")
// normalize the coin denom
coins, err := sdk.ParseCoinNormalized(r.cfg.Relayer.Tokens)

gasFee, err := client.EstimateGasFee(
r.cfg.Relayer.Destination,
r.cfg.Relayer.Contract,
r.cfg.AxelarGas.Default,
r.cfg.AxelarGas.Multiplier,
)
if err != nil {
return err
r.logger.Err(err).Str("default", r.cfg.AxelarGas.Default).Msg("unable to estimate gas fee")
defaultGasFee, ok := math.NewIntFromString(r.cfg.AxelarGas.Default)
if !ok {
return fmt.Errorf("unable to convert default gas fee to int")
}
gasFee = defaultGasFee
}
if !strings.HasPrefix(coins.Denom, "ibc/") {
denomTrace := ibctransfertypes.ParseDenomTrace(coins.Denom)
coins.Denom = denomTrace.IBCDenom()
coins := sdk.Coin{
Denom: r.cfg.AxelarGas.Denom,
Amount: gasFee,
}
r.logger.Info().Strs("gas_fee", []string{coins.String()}).Msg("estimated gas fee")

msg := gmptypes.NewMsgRelay(
r.cfg.Account.Address,
Expand Down
37 changes: 0 additions & 37 deletions scripts/createPriceFeed.ts

This file was deleted.

50 changes: 50 additions & 0 deletions scripts/createPriceFeeds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Wallet, ethers } from "ethers";
import CloneFactory from '../artifacts/contracts/pricefeed/CloneFactory.sol/CloneFactory.json';
import testnet_chains from '../testnet_chains.json';
import mainnet_chains from '../mainnet_chains.json';

async function main() {
const evmChains = JSON.parse(process.env.EVM_CHAINS!);
const priceFeedDecimals = process.env.PRICE_FEED_DECIMALS as any;
const priceFeedDescriptions = JSON.parse(process.env.PRICE_FEED_DESCRIPTIONS!);

const privateKey = process.env.PRIVATE_KEY;

if (!privateKey) {
throw new Error('Invalid private key. Make sure the PRIVATE_KEY environment variable is set.');
}

const mainnet = process.env.MAINNET as string
let chains = testnet_chains.map((chain) => ({ ...chain }));
if (mainnet === "TRUE") {
chains = mainnet_chains.map((chain) => ({ ...chain }));
}

for (const chain of chains) {
if (evmChains.includes(chain.name)) {
const provider = new ethers.JsonRpcProvider(chain.rpc)
const wallet = new Wallet(privateKey, provider);
const balance = await provider.getBalance(wallet.address)
console.log(`${chain.name} wallet balance: ${ethers.formatEther(balance.toString())} ${chain.tokenSymbol}`);

const cloneFactoryContract = new ethers.Contract(chain.cloneFactory, CloneFactory.abi, wallet)
for (const priceFeedDescription of priceFeedDescriptions) {
console.log(`Deploying ${priceFeedDescription} price feed on ${chain.name}`);
try {
const tx = await cloneFactoryContract.createPriceFeed(priceFeedDecimals, priceFeedDescription);
console.log(`Transaction sent: ${tx.hash}`);

const receipt = await tx.wait();
console.log(`Transaction mined: ${receipt.transactionHash}`);
} catch (error) {
console.error(`Failed to deploy ${priceFeedDescription} on ${chain.name}:`, error);
}
}
}
}
}

main().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Loading

0 comments on commit 794c226

Please sign in to comment.