Skip to content

Commit

Permalink
fix: lower default pricing and check LP balance (#403)
Browse files Browse the repository at this point in the history
* patch: use latest version of nitro node when running local chain

* chore: add alvin to clabot

* fix: lower default instruction price and check LP balance

* use faucet address for unit test

* added no lp balance check

* add return on token contract call
  • Loading branch information
alvin-reyes authored Oct 14, 2024
1 parent edb8fe8 commit cccc033
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 1 deletion.
14 changes: 13 additions & 1 deletion pkg/solver/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ type SolverController struct {
// reacts to events in the system - this 10 second background
// loop is just for in case we miss any events
const CONTROL_LOOP_INTERVAL = 10 * time.Second
const REQUIRED_BALANCE_IN_WEI = 0.0006

func NewSolverController(
web3SDK *web3.Web3SDK,
Expand Down Expand Up @@ -332,12 +333,23 @@ func (controller *SolverController) addResourceOffer(resourceOffer data.Resource
return nil, fmt.Errorf("failed to retrieve ETH balance for resource provider: %v", err)
}
// Convert InstructionPrice from ETH to Wei
requiredBalanceWei := web3.EtherToWei(float64(resourceOffer.DefaultPricing.InstructionPrice))
requiredBalanceWei := web3.EtherToWei(REQUIRED_BALANCE_IN_WEI) // 0.0006 based on the required balance for a job

// If the balance is less than the required balance, don't add the resource offer
if balance.Cmp(requiredBalanceWei) < 0 {
return nil, fmt.Errorf("address %s doesn't have enough funds. required balance is %s but expected balance is %s", resourceOffer.ResourceProvider, requiredBalanceWei, balance)
}

// required LP balance
requiredBalanceLp := web3.EtherToWei(float64(resourceOffer.DefaultPricing.InstructionPrice)) // based on the required LP balance for a job
balanceLp, err := controller.web3SDK.GetLPBalance(resourceOffer.ResourceProvider)
if err != nil {
return nil, fmt.Errorf("failed to retrieve LP balance for resource provider: %v", err)
}
if balanceLp.Cmp(requiredBalanceLp) < 0 {
return nil, fmt.Errorf("address %s doesn't have enough LP balance. required balance is %s but expected balance is %s", resourceOffer.ResourceProvider, requiredBalanceLp, balanceLp)
}

controller.log.Info("add resource offer", resourceOffer)

metricsDashboard.TrackNodeInfo(resourceOffer)
Expand Down
34 changes: 34 additions & 0 deletions pkg/web3/sdk.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"crypto/ecdsa"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/accounts/abi"
"math/big"
"net/url"
"strconv"
Expand All @@ -29,6 +30,9 @@ import (
"go.opentelemetry.io/otel/trace"
)

// LP token ABI
const erc20ABI = `[{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256","internalType": "uint256"}],"type":"function"}]`

// these are the go-binding wrappers for the various deployed contracts
type Contracts struct {
Token *token.Token
Expand Down Expand Up @@ -308,3 +312,33 @@ func (sdk *Web3SDK) GetBalance(address string) (*big.Int, error) {
}
return balance, nil
}

func (sdk *Web3SDK) GetLPBalance(address string) (*big.Int, error) {
// Convert the string address to common.Address
client := sdk.Client
ethAddress := common.HexToAddress(address)
lpToken := common.HexToAddress(sdk.Options.TokenAddress) // LP Token Address

// Get the balance using the converted address
erc20ABIObj, err := abi.JSON(strings.NewReader(erc20ABI))
if err != nil {
log.Error().Msgf("error parsing ABI: %s", err)
return nil, err
}
tokenContract := bind.NewBoundContract(lpToken, erc20ABIObj, client, client, client)

var out []interface{}
err = tokenContract.Call(nil, &out, "balanceOf", ethAddress)
if err != nil {
log.Error().Msgf("error calling balanceOf: %s", err)
return nil, err
}

lpBalance := *abi.ConvertType(out[0], new(big.Int)).(*big.Int)

if err != nil {
log.Error().Msgf("error for GetBalance: %s", err.Error())
return nil, err
}
return &lpBalance, nil
}
67 changes: 67 additions & 0 deletions pkg/web3/sdk_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,13 @@ package web3_test

import (
"context"
"crypto/ecdsa"
"errors"
"fmt"
"github.com/ethereum/go-ethereum/crypto"
"golang.org/x/crypto/sha3"
"log"
"math/big"
"os"
"testing"

Expand Down Expand Up @@ -48,6 +53,8 @@ func CreateTestWeb3SDK() (*web3.Web3SDK, error) {
JobCreatorAddress: config.Web3.JobCreatorAddress,
}

fmt.Println("options: ", options)

noopTracer := noop.NewTracerProvider().Tracer(system.GetOTelServiceName(system.DefaultService))
sdk, err := web3.NewContractSDK(context.Background(), options, noopTracer)
if err != nil {
Expand All @@ -70,6 +77,42 @@ func TestGetBalance(t *testing.T) {
t.Logf("Balance: %d\n", balance)
}

func TestGetLPBalance(t *testing.T) {
sdk, err := CreateTestWeb3SDK()
if err != nil {
t.Fatalf("Failed to create Web3SDK: %v", err)
}
balance, err := sdk.GetLPBalance("0x9162B48910E12079c089477DeF4384312f0a6E00") // faucet address
if err != nil {
t.Fatalf("Failed to get LP balance: %v", err)
}
t.Logf("LP Balance: %d\n", balance)
}

func TestGetLPBalanceNoBalance(t *testing.T) {
sdk, err := CreateTestWeb3SDK()
noBalanceInt := big.NewInt(0)
if err != nil {
t.Fatalf("Failed to create Web3SDK: %v", err)
}

// generate new address with no balance
newAddress := generateNewAddressWoLp()

t.Logf("newAddress to check no LP balance: %s\n", newAddress)

balance, err := sdk.GetLPBalance(newAddress) // randomly generated address (100% no LP balance)
if err != nil {
t.Fatalf("Failed to get LP balance: %v", err)
}

if balance.Cmp(noBalanceInt) > 0 {
t.Fatalf("Balance should be nil")
}

t.Logf("LP Balance: %d\n", balance)
}

func TestGetBlockNumber(t *testing.T) {
sdk, err := CreateTestWeb3SDK()
if err != nil {
Expand All @@ -83,3 +126,27 @@ func TestGetBlockNumber(t *testing.T) {

t.Logf("Block number: %s\n", blockNumberHex)
}

func generateNewAddressWoLp() string {
privateKey, err := crypto.GenerateKey()
if err != nil {
log.Fatal(err)
}

publicKey := privateKey.Public()
publicKeyECDSA, ok := publicKey.(*ecdsa.PublicKey)
if !ok {
log.Fatal("error casting public key to ECDSA")
}

publicKeyBytes := crypto.FromECDSAPub(publicKeyECDSA)

address := crypto.PubkeyToAddress(*publicKeyECDSA).Hex()
fmt.Println(address)

hash := sha3.NewLegacyKeccak256()
hash.Write(publicKeyBytes[1:])

return address

}

0 comments on commit cccc033

Please sign in to comment.