diff --git a/examples/01_external_match/01_external_match b/examples/01_external_match/01_external_match new file mode 100755 index 0000000..d15c6e8 Binary files /dev/null and b/examples/01_external_match/01_external_match differ diff --git a/examples/01_external_match/main.go b/examples/01_external_match/main.go index 37f5653..01b7338 100644 --- a/examples/01_external_match/main.go +++ b/examples/01_external_match/main.go @@ -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(). @@ -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...") @@ -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) @@ -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") -} diff --git a/examples/02_external_quote_validation/02_external_quote_validation b/examples/02_external_quote_validation/02_external_quote_validation new file mode 100755 index 0000000..51e59b7 Binary files /dev/null and b/examples/02_external_quote_validation/02_external_quote_validation differ diff --git a/examples/03_external_match_with_receiver/03_external_match_with_receiver b/examples/03_external_match_with_receiver/03_external_match_with_receiver new file mode 100755 index 0000000..7659096 Binary files /dev/null and b/examples/03_external_match_with_receiver/03_external_match_with_receiver differ diff --git a/examples/03_external_match_with_receiver/main.go b/examples/03_external_match_with_receiver/main.go index 8da8b48..9fa03e0 100644 --- a/examples/03_external_match_with_receiver/main.go +++ b/examples/03_external_match_with_receiver/main.go @@ -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) } @@ -60,7 +39,7 @@ func main() { panic(err) } - if err := getQuoteAndSubmitWithReceiver(order, externalMatchClient); err != nil { + if err := getQuoteAndSubmitWithReceiver(order, client); err != nil { panic(err) } } @@ -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 } @@ -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") -} diff --git a/examples/04_modify_quoted_order/04_modify_quoted_order b/examples/04_modify_quoted_order/04_modify_quoted_order new file mode 100755 index 0000000..aa28175 Binary files /dev/null and b/examples/04_modify_quoted_order/04_modify_quoted_order differ diff --git a/examples/04_modify_quoted_order/main.go b/examples/04_modify_quoted_order/main.go index f3b187d..1be2623 100644 --- a/examples/04_modify_quoted_order/main.go +++ b/examples/04_modify_quoted_order/main.go @@ -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) } @@ -60,7 +39,7 @@ func main() { panic(err) } - if err := getQuoteAndSubmitWithReceiver(order, externalMatchClient); err != nil { + if err := getQuoteAndSubmitWithReceiver(order, client); err != nil { panic(err) } } @@ -79,10 +58,10 @@ func getQuoteAndSubmitWithReceiver(order *api_types.ApiExternalOrder, client *ex return nil } - // 2. Assemble the bundle with a separate receiver address + // 2. Assemble the bundle with a modified order fmt.Println("Assembling bundle...") newOrder := order - newOrder.QuoteAmount = api_types.NewAmount(19_000_000) + newOrder.QuoteAmount = api_types.NewAmount(19_000_000) // Modify to 19 USDC receiverAddress := "0xC5fE800A3D92112473e4E811296F194DA7b26BA7" options := external_match_client.NewAssembleExternalMatchOptions(). WithReceiverAddress(&receiverAddress). @@ -100,98 +79,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") -} diff --git a/examples/05_gas_sponsored_match/05_gas_sponsored_match b/examples/05_gas_sponsored_match/05_gas_sponsored_match new file mode 100755 index 0000000..b68b4de Binary files /dev/null and b/examples/05_gas_sponsored_match/05_gas_sponsored_match differ diff --git a/examples/05_gas_sponsored_match/main.go b/examples/05_gas_sponsored_match/main.go index 444a404..bcf1b85 100644 --- a/examples/05_gas_sponsored_match/main.go +++ b/examples/05_gas_sponsored_match/main.go @@ -1,48 +1,30 @@ 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" + "github.com/renegade-fi/golang-sdk/examples/common" ) const ( - darkpoolAddress = "0x9af58f1ff20ab22e819e40b57ffd784d115a9ef5" - chainId = 421614 // Testnet gasRefundAddress = "0x99D9133afE1B9eC1726C077cA2b79Dcbb5969707" ) 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) } @@ -61,7 +43,7 @@ func main() { panic(err) } - if err := getQuoteAndSubmitWithGasSponsorship(order, externalMatchClient); err != nil { + if err := getQuoteAndSubmitWithGasSponsorship(order, client); err != nil { panic(err) } } @@ -90,7 +72,6 @@ func getQuoteAndSubmitWithGasSponsorship( WithRequestGasSponsorship(true). WithGasRefundAddress(&refundAddr) - // Build the full path with query parameters bundle, err := client.AssembleExternalMatchWithOptions(quote, options) if err != nil { return err @@ -108,98 +89,10 @@ func getQuoteAndSubmitWithGasSponsorship( // 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") -} diff --git a/examples/06_exact_amount_out/06_exact_amount_out b/examples/06_exact_amount_out/06_exact_amount_out new file mode 100755 index 0000000..e82874b Binary files /dev/null and b/examples/06_exact_amount_out/06_exact_amount_out differ diff --git a/examples/06_exact_amount_out/main.go b/examples/06_exact_amount_out/main.go index 3098590..f1130c4 100644 --- a/examples/06_exact_amount_out/main.go +++ b/examples/06_exact_amount_out/main.go @@ -1,36 +1,27 @@ +// Package main provides an example of how to get a quote for an exact amount out package main import ( "fmt" "math/big" - "os" "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" + "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) } @@ -49,12 +40,12 @@ func main() { panic(err) } - if err := getQuoteWithExactAmount(order, externalMatchClient); err != nil { + if err := getQuoteWithExactAmount(order, client); err != nil { panic(err) } } -// getQuoteAndSubmit gets a quote, assembles it, then submits the bundle +// getQuoteWithExactAmount gets a quote and prints the details func getQuoteWithExactAmount(order *api_types.ApiExternalOrder, client *external_match_client.ExternalMatchClient) error { // 1. Get a quote from the relayer fmt.Println("Getting quote...") diff --git a/examples/07_get_fees/07_get_fees b/examples/07_get_fees/07_get_fees new file mode 100755 index 0000000..ee9d44c Binary files /dev/null and b/examples/07_get_fees/07_get_fees differ diff --git a/examples/07_get_fees/main.go b/examples/07_get_fees/main.go index b3ba4ed..4f1cdc3 100644 --- a/examples/07_get_fees/main.go +++ b/examples/07_get_fees/main.go @@ -3,30 +3,24 @@ package main import ( "fmt" - "os" - external_match_client "github.com/renegade-fi/golang-sdk/client/external_match_client" - "github.com/renegade-fi/golang-sdk/wallet" + "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") + client, err := common.CreateExternalMatchClient() + if err != nil { + panic(err) } - apiSecretKey, err := new(wallet.HmacKey).FromBase64String(apiSecret) + // Get WETH address + wethAddr, err := common.FindTokenAddr("WETH", client) if err != nil { panic(err) } // Get fees for WETH - externalMatchClient := external_match_client.NewTestnetExternalMatchClient(apiKey, &apiSecretKey) - - mint := "0xc3414a7ef14aaaa9c4522dfc00a4e66e74e9c25a" // Testnet WETH - fees, err := externalMatchClient.GetFeeForAsset(&mint) + fees, err := client.GetFeeForAsset(&wethAddr) if err != nil { panic(err) } diff --git a/examples/common/client.go b/examples/common/client.go new file mode 100644 index 0000000..e2f1ad3 --- /dev/null +++ b/examples/common/client.go @@ -0,0 +1,42 @@ +// Package common contains common functions for the examples +package common + +import ( + "fmt" + "os" + + external_match_client "github.com/renegade-fi/golang-sdk/client/external_match_client" + "github.com/renegade-fi/golang-sdk/wallet" +) + +// CreateExternalMatchClient creates a new external match client using environment variables +func CreateExternalMatchClient() (*external_match_client.ExternalMatchClient, error) { + apiKey := os.Getenv("EXTERNAL_MATCH_KEY") + apiSecret := os.Getenv("EXTERNAL_MATCH_SECRET") + if apiKey == "" || apiSecret == "" { + return nil, fmt.Errorf("EXTERNAL_MATCH_KEY and EXTERNAL_MATCH_SECRET must be set") + } + + apiSecretKey, err := new(wallet.HmacKey).FromBase64String(apiSecret) + if err != nil { + return nil, fmt.Errorf("failed to parse API secret: %w", err) + } + + return external_match_client.NewTestnetExternalMatchClient(apiKey, &apiSecretKey), nil +} + +// FindTokenAddr fetches the address of a token from the relayer +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 %s not found", symbol) +} diff --git a/examples/common/eth.go b/examples/common/eth.go new file mode 100644 index 0000000..9e57fde --- /dev/null +++ b/examples/common/eth.go @@ -0,0 +1,87 @@ +package common + +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" + + external_match_client "github.com/renegade-fi/golang-sdk/client/external_match_client" +) + +const ( + // ChainID is the chain ID for the testnet + ChainID = 421614 +) + +// SubmitBundle submits the bundle to the sequencer +func SubmitBundle(bundle external_match_client.ExternalMatchBundle) error { + ethClient, err := GetEthClient() + if err != nil { + return fmt.Errorf("failed to create eth client: %w", err) + } + + privateKey, err := GetPrivateKey() + if err != nil { + return fmt.Errorf("failed to get private key: %w", err) + } + + gasPrice, err := ethClient.SuggestGasPrice(context.Background()) + if err != nil { + return fmt.Errorf("failed to get gas price: %w", err) + } + + nonce, err := ethClient.PendingNonceAt(context.Background(), crypto.PubkeyToAddress(privateKey.PublicKey)) + if err != nil { + return fmt.Errorf("failed to get nonce: %w", 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 { + return fmt.Errorf("failed to sign transaction: %w", err) + } + + err = ethClient.SendTransaction(context.Background(), signedTx) + if err != nil { + return fmt.Errorf("failed to send transaction: %w", err) + } + + fmt.Printf("Transaction submitted! Hash: %s\n", signedTx.Hash().Hex()) + return nil +} + +// GetEthClient creates a new Ethereum client +func GetEthClient() (*ethclient.Client, error) { + rpcURL := os.Getenv("RPC_URL") + if rpcURL == "" { + return nil, fmt.Errorf("RPC_URL environment variable not set") + } + return ethclient.Dial(rpcURL) +} + +// GetPrivateKey gets the private key from environment variables +func GetPrivateKey() (*ecdsa.PrivateKey, error) { + privKeyHex := os.Getenv("PKEY") + if privKeyHex == "" { + return nil, fmt.Errorf("PKEY environment variable not set") + } + + return crypto.HexToECDSA(privKeyHex) +}