Skip to content

Commit

Permalink
examples: common: Break out shared helpers into common package (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
joeykraut authored Feb 15, 2025
1 parent 2abb908 commit b8d9bb2
Show file tree
Hide file tree
Showing 15 changed files with 180 additions and 511 deletions.
Binary file added examples/01_external_match/01_external_match
Binary file not shown.
142 changes: 10 additions & 132 deletions examples/01_external_match/main.go
Original file line number Diff line number Diff line change
@@ -1,56 +1,31 @@
package main

import (
"context"
"crypto/ecdsa"
"fmt"
"math/big"
"os"

"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"

"github.com/renegade-fi/golang-sdk/client/api_types"
external_match_client "github.com/renegade-fi/golang-sdk/client/external_match_client"
"github.com/renegade-fi/golang-sdk/wallet"
)

const (
darkpoolAddress = "0x9af58f1ff20ab22e819e40b57ffd784d115a9ef5"
chainId = 421614 // Testnet
"github.com/renegade-fi/golang-sdk/client/external_match_client"
"github.com/renegade-fi/golang-sdk/examples/common"
)

func main() {
// ... Token Approvals to Darkpool ... //

// Get API credentials from environment
apiKey := os.Getenv("EXTERNAL_MATCH_KEY")
apiSecret := os.Getenv("EXTERNAL_MATCH_SECRET")
if apiKey == "" || apiSecret == "" {
panic("EXTERNAL_MATCH_KEY and EXTERNAL_MATCH_SECRET must be set")
}

apiSecretKey, err := new(wallet.HmacKey).FromBase64String(apiSecret)
client, err := common.CreateExternalMatchClient()
if err != nil {
panic(err)
}

externalMatchClient := external_match_client.NewTestnetExternalMatchClient(apiKey, &apiSecretKey)

// You can fetch token mappings from the relayer using the client
quoteMint, err := findTokenAddr("USDC", externalMatchClient)
// Fetch token mappings from the relayer
quoteMint, err := common.FindTokenAddr("USDC", client)
if err != nil {
panic(err)
}
baseMint, err := findTokenAddr("WETH", externalMatchClient)
baseMint, err := common.FindTokenAddr("WETH", client)
if err != nil {
panic(err)
}

// Request an external match
// We can denominate the order size in either the quote or base token with
// `WithQuoteAmount` or `WithBaseAmount` respectively.
// Create order for 20 USDC worth of WETH
quoteAmount := new(big.Int).SetUint64(20_000_000) // $20 USDC
minFillSize := big.NewInt(0)
order, err := api_types.NewExternalOrderBuilder().
Expand All @@ -64,12 +39,11 @@ func main() {
panic(err)
}

if err := getQuoteAndSubmit(order, externalMatchClient); err != nil {
if err := getQuoteAndSubmit(order, client); err != nil {
panic(err)
}
}

// getQuoteAndSubmit gets a quote, assembled is, then submits the bundle
func getQuoteAndSubmit(order *api_types.ApiExternalOrder, client *external_match_client.ExternalMatchClient) error {
// 1. Get a quote from the relayer
fmt.Println("Getting quote...")
Expand All @@ -83,8 +57,6 @@ func getQuoteAndSubmit(order *api_types.ApiExternalOrder, client *external_match
return nil
}

// ... Check if the quote is acceptable ... //

// 2. Assemble the bundle
fmt.Println("Assembling bundle...")
bundle, err := client.AssembleExternalQuote(quote)
Expand All @@ -99,104 +71,10 @@ func getQuoteAndSubmit(order *api_types.ApiExternalOrder, client *external_match

// 3. Submit the bundle
fmt.Println("Submitting bundle...")
if err := submitBundle(*bundle); err != nil {
return err
if err := common.SubmitBundle(*bundle); err != nil {
return fmt.Errorf("failed to submit bundle: %w", err)
}

fmt.Print("Bundle submitted successfully!\n\n")
return nil
}

// submitBundle submits the bundle to the sequencer
func submitBundle(bundle external_match_client.ExternalMatchBundle) error {
// Initialize eth client
ethClient, err := getEthClient()
if err != nil {
panic(err)
}

privateKey, err := getPrivateKey()
if err != nil {
panic(err)
}

// Send the transaction to the sequencer
gasPrice, err := ethClient.SuggestGasPrice(context.Background())
if err != nil {
panic(err)
}

nonce, err := ethClient.PendingNonceAt(context.Background(), crypto.PubkeyToAddress(privateKey.PublicKey))
if err != nil {
panic(err)
}

ethTx := types.NewTx(&types.DynamicFeeTx{
ChainID: big.NewInt(chainId), // Sepolia chain ID
Nonce: nonce,
GasTipCap: gasPrice, // Use suggested gas price as tip cap
GasFeeCap: new(big.Int).Mul(gasPrice, big.NewInt(2)), // Fee cap at 2x gas price
Gas: uint64(10_000_000), // Gas limit
To: &bundle.SettlementTx.To, // Contract address
Value: bundle.SettlementTx.Value, // No ETH transfer
Data: []byte(bundle.SettlementTx.Data), // Contract call data
})

// Sign and send transaction
signer := types.LatestSignerForChainID(big.NewInt(chainId))
signedTx, err := types.SignTx(ethTx, signer, privateKey)
if err != nil {
panic(err)
}

err = ethClient.SendTransaction(context.Background(), signedTx)
if err != nil {
panic(err)
}

fmt.Printf("Transaction submitted! Hash: %s\n", signedTx.Hash().Hex())
return nil
}

// -----------
// | Helpers |
// -----------

func getRpcUrl() string {
rpcUrl := os.Getenv("RPC_URL")
if rpcUrl == "" {
panic("RPC_URL environment variable not set")
}
return rpcUrl
}

func getEthClient() (*ethclient.Client, error) {
return ethclient.Dial(getRpcUrl())
}

func getPrivateKey() (*ecdsa.PrivateKey, error) {
privKeyHex := os.Getenv("PKEY")
if privKeyHex == "" {
return nil, fmt.Errorf("PKEY environment variable not set")
}

return crypto.HexToECDSA(privKeyHex)
}

// findTokenAddr fetches the address of a token from the relayer
func findTokenAddr(symbol string, client *external_match_client.ExternalMatchClient) (string, error) {
// Fetch the list of supported tokens from the relayer
tokens, err := client.GetSupportedTokens()
if err != nil {
return "", err
}

// Find the token with the matching symbol
for _, token := range tokens {
if token.Symbol == symbol {
return token.Address, nil
}
}

return "", fmt.Errorf("token not found")
}
Binary file not shown.
Binary file not shown.
130 changes: 12 additions & 118 deletions examples/03_external_match_with_receiver/main.go
Original file line number Diff line number Diff line change
@@ -1,47 +1,26 @@
package main

import (
"context"
"crypto/ecdsa"
"fmt"
"math/big"
"os"

"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethclient"

"github.com/renegade-fi/golang-sdk/client/api_types"
external_match_client "github.com/renegade-fi/golang-sdk/client/external_match_client"
"github.com/renegade-fi/golang-sdk/wallet"
)

const (
darkpoolAddress = "0x9af58f1ff20ab22e819e40b57ffd784d115a9ef5"
chainId = 421614 // Testnet
"github.com/renegade-fi/golang-sdk/examples/common"
)

func main() {
// Get API credentials from environment
apiKey := os.Getenv("EXTERNAL_MATCH_KEY")
apiSecret := os.Getenv("EXTERNAL_MATCH_SECRET")
if apiKey == "" || apiSecret == "" {
panic("EXTERNAL_MATCH_KEY and EXTERNAL_MATCH_SECRET must be set")
}

apiSecretKey, err := new(wallet.HmacKey).FromBase64String(apiSecret)
client, err := common.CreateExternalMatchClient()
if err != nil {
panic(err)
}

externalMatchClient := external_match_client.NewTestnetExternalMatchClient(apiKey, &apiSecretKey)

// Fetch token mappings from the relayer
quoteMint, err := findTokenAddr("USDC", externalMatchClient)
quoteMint, err := common.FindTokenAddr("USDC", client)
if err != nil {
panic(err)
}
baseMint, err := findTokenAddr("WETH", externalMatchClient)
baseMint, err := common.FindTokenAddr("WETH", client)
if err != nil {
panic(err)
}
Expand All @@ -60,7 +39,7 @@ func main() {
panic(err)
}

if err := getQuoteAndSubmitWithReceiver(order, externalMatchClient); err != nil {
if err := getQuoteAndSubmitWithReceiver(order, client); err != nil {
panic(err)
}
}
Expand All @@ -80,9 +59,12 @@ func getQuoteAndSubmitWithReceiver(order *api_types.ApiExternalOrder, client *ex
}

// 2. Assemble the bundle with a separate receiver address
fmt.Println("Assembling bundle...")
receiverAddress := "0xC5fE800A3D92112473e4E811296F194DA7b26BA7"
fmt.Println("Assembling bundle with receiver address:", receiverAddress)
bundle, err := client.AssembleExternalQuoteWithReceiver(quote, &receiverAddress)
options := external_match_client.NewAssembleExternalMatchOptions().
WithReceiverAddress(&receiverAddress)

bundle, err := client.AssembleExternalMatchWithOptions(quote, options)
if err != nil {
return err
}
Expand All @@ -94,98 +76,10 @@ func getQuoteAndSubmitWithReceiver(order *api_types.ApiExternalOrder, client *ex

// 3. Submit the bundle
fmt.Println("Submitting bundle...")
if err := submitBundle(*bundle); err != nil {
return err
if err := common.SubmitBundle(*bundle); err != nil {
return fmt.Errorf("failed to submit bundle: %w", err)
}

fmt.Print("Bundle submitted successfully!\n\n")
return nil
}

// submitBundle submits the bundle to the sequencer
func submitBundle(bundle external_match_client.ExternalMatchBundle) error {
ethClient, err := getEthClient()
if err != nil {
panic(err)
}

privateKey, err := getPrivateKey()
if err != nil {
panic(err)
}

gasPrice, err := ethClient.SuggestGasPrice(context.Background())
if err != nil {
panic(err)
}

nonce, err := ethClient.PendingNonceAt(context.Background(), crypto.PubkeyToAddress(privateKey.PublicKey))
if err != nil {
panic(err)
}

ethTx := types.NewTx(&types.DynamicFeeTx{
ChainID: big.NewInt(chainId),
Nonce: nonce,
GasTipCap: gasPrice,
GasFeeCap: new(big.Int).Mul(gasPrice, big.NewInt(2)),
Gas: uint64(10_000_000),
To: &bundle.SettlementTx.To,
Value: bundle.SettlementTx.Value,
Data: []byte(bundle.SettlementTx.Data),
})

signer := types.LatestSignerForChainID(big.NewInt(chainId))
signedTx, err := types.SignTx(ethTx, signer, privateKey)
if err != nil {
panic(err)
}

err = ethClient.SendTransaction(context.Background(), signedTx)
if err != nil {
panic(err)
}

fmt.Printf("Transaction submitted! Hash: %s\n", signedTx.Hash().Hex())
return nil
}

// -----------
// | Helpers |
// -----------

func getRpcUrl() string {
rpcUrl := os.Getenv("RPC_URL")
if rpcUrl == "" {
panic("RPC_URL environment variable not set")
}
return rpcUrl
}

func getEthClient() (*ethclient.Client, error) {
return ethclient.Dial(getRpcUrl())
}

func getPrivateKey() (*ecdsa.PrivateKey, error) {
privKeyHex := os.Getenv("PKEY")
if privKeyHex == "" {
return nil, fmt.Errorf("PKEY environment variable not set")
}

return crypto.HexToECDSA(privKeyHex)
}

func findTokenAddr(symbol string, client *external_match_client.ExternalMatchClient) (string, error) {
tokens, err := client.GetSupportedTokens()
if err != nil {
return "", err
}

for _, token := range tokens {
if token.Symbol == symbol {
return token.Address, nil
}
}

return "", fmt.Errorf("token not found")
}
Binary file not shown.
Loading

0 comments on commit b8d9bb2

Please sign in to comment.