Skip to main content

Prerequisites

Before running the script, ensure you have the following installed: Python:
  • Python 3.10
  • Web3 (pip install web3)
  • Requests (pip install requests)
TypeScript:
  • Node.js 18+
  • TypeScript (npm install -g typescript)
  • Web3 (npm install web3)
  • Axios (npm install axios)
JavaScript:
  • Node.js 18+
  • Web3 (npm install web3)
  • Axios (npm install axios)
Additionally, you need access to an Ethereum compatible blockchain node, such as an Infura or Tenderly RPC endpoint.

Setup and Configuration

from web3 import Web3
import requests
import json
import time

# Configuration
API_KEY = "your_api_key"
UNIQUE_PID = "your_unique_pid"
QUOTE_ENDPOINT = "https://router.gluex.xyz/v1/quote"
RPC_URL = "https://mainnet.gateway.tenderly.co/your_rpc_url"
PRIVATE_KEY = "your_private_key"

# Token Addresses
USDC_ADDRESS = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"  # USDC on Ethereum
ETH_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"    # ETH on Ethereum
INPUT_AMOUNT = 1000000  # 1 USDC (6 decimals)

# Initialize Web3
web3 = Web3(Web3.HTTPProvider(RPC_URL))
account = web3.eth.account.from_key(PRIVATE_KEY)
COMPUTATION_UNITS = 1000000
COMPUTATION_COST = web3.eth.gas_price

Fetching a Swap Quote

Before executing the transaction, fetch a quote from the GlueX Router
def fetch_quote():
    """Fetch a quote from the GlueX Router for $USDC to $ETH swap"""
    headers = {"x-api-key": API_KEY}
    body = {
        "chainID": "1",  # Ethereum Mainnet
        "userAddress": account.address,
        "outputReceiver": account.address,
        "uniquePID": UNIQUE_PID,
        "inputToken": USDC_ADDRESS,
        "outputToken": ETH_ADDRESS,
        "inputAmount": INPUT_AMOUNT,
        "isPermit2": False
    }

    response = requests.post(QUOTE_ENDPOINT, json=body, headers=headers)

    return response.json()

Approving the Router Contract

Before executing the swap, the router contract needs permission to spend the user’s USDC tokens
def approve_spender(spender, amount, token_address):
    """Approve the router contract to spend $USDC"""
    signature = "0x095ea7b3"
    padded_spender = Web3.to_checksum_address(spender)[2:].zfill(64)
    calldata = f"{signature}{padded_spender}{int(amount):064x}"

    txn = {
        "from": account.address,
        "to": Web3.to_checksum_address(token_address),
        "data": calldata,
        "gas": COMPUTATION_UNITS,
        "gasPrice": web3.eth.gas_price,
        "nonce": web3.eth.get_transaction_count(account.address),
        "chainId": 1,  # Ethereum mainnet
    }

    signed_txn = web3.eth.account.sign_transaction(txn, account.key)
    txn_hash = web3.eth.send_raw_transaction(signed_txn.raw_transaction)
    print(f"Approval Transaction Hash: {web3.to_hex(txn_hash)}")

    return txn_hash

Executing the Transaction

After approval, we execute the transaction using the calldata from the quote
def execute_transaction(calldata, router_address):
    """Execute the swap transaction on GlueX Router"""
    txn = {
        "from": account.address,
        "to": Web3.to_checksum_address(router_address),
        "data": calldata,
        "gas": COMPUTATION_UNITS,
        "gasPrice": web3.eth.gas_price,
        "nonce": web3.eth.get_transaction_count(account.address),
        "chainId": 1,  # Ethereum mainnet
    }

    signed_txn = web3.eth.account.sign_transaction(txn, account.key)

    try:
        txn_hash = web3.eth.send_raw_transaction(signed_txn.raw_transaction)
    except Web3RPCError as err:
        time.sleep(5)
        txn["nonce"] = web3.eth.get_transaction_count(account.address)
        signed_txn = web3.eth.account.sign_transaction(txn, account.key)
        txn_hash = web3.eth.send_raw_transaction(signed_txn.raw_transaction)

    print(f"Transaction Hash: {web3.to_hex(txn_hash)}")

    return txn_hash

Putting Everything Together

def main():
    # Fetch the quote
    quote_data = fetch_quote()
    if quote_data.get('statusCode') != 200:
        print("Error fetching quote:", quote_data)
        return

    print("Quote received successfully:", quote_data)
    router_address = quote_data["result"]["router"]
    calldata = quote_data["result"]["calldata"]

    # Approve the router contract
    print("Approving router contract to spend USDC...")
    txn_hash = approve_spender(router_address, INPUT_AMOUNT, USDC_ADDRESS)
    print("Waiting for approval transaction confirmation...")
    approval_receipt = web3.eth.wait_for_transaction_receipt(txn_hash)
    if approval_receipt.status != 1:
        print("Approval failed. Aborting.")
        return

    # Execute the transaction
    print("Executing transaction...")
    execute_txn = execute_transaction(calldata, router_address)

    receipt = web3.eth.wait_for_transaction_receipt(execute_txn)
    print("Transaction confirmed. Receipt:")
    print(receipt)


if __name__ == "__main__":
    main()

Complete Code Implementation

from web3 import Web3
from web3.exceptions import Web3RPCError
import requests
import json
import time

# Configuration
API_KEY = "your_api_key"
UNIQUE_PID = "your_unique_pid"
QUOTE_ENDPOINT = "https://router.gluex.xyz/v1/quote"
RPC_URL = "https://mainnet.gateway.tenderly.co/your_rpc_url"
PRIVATE_KEY = "your_private_key"

# Token Addresses
USDC_ADDRESS = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"  # USDC on Ethereum
ETH_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"    # ETH on Ethereum
INPUT_AMOUNT = 1000000  # 1 USDC (6 decimals)

# Initialize Web3
web3 = Web3(Web3.HTTPProvider(RPC_URL))
account = web3.eth.account.from_key(PRIVATE_KEY)
COMPUTATION_UNITS = 1000000
COMPUTATION_COST = web3.eth.gas_price

def fetch_quote():
    """Fetch a quote from the GlueX Router for $USDC to $ETH swap"""
    headers = {"x-api-key": API_KEY}
    body = {
        "chainID": "1",  # Ethereum Mainnet
        "userAddress": account.address,
        "outputReceiver": account.address,
        "uniquePID": UNIQUE_PID,
        "inputToken": USDC_ADDRESS,
        "outputToken": ETH_ADDRESS,
        "inputAmount": INPUT_AMOUNT,
        "isPermit2": False
    }

    response = requests.post(QUOTE_ENDPOINT, json=body, headers=headers)

    return response.json()

def approve_spender(spender, amount, token_address):
    """Approve the router contract to spend $USDC"""
    signature = "0x095ea7b3"
    padded_spender = Web3.to_checksum_address(spender)[2:].zfill(64)
    calldata = f"{signature}{padded_spender}{int(amount):064x}"

    txn = {
        "from": account.address,
        "to": Web3.to_checksum_address(token_address),
        "data": calldata,
        "gas": COMPUTATION_UNITS,
        "gasPrice": web3.eth.gas_price,
        "nonce": web3.eth.get_transaction_count(account.address),
        "chainId": 1,  # Ethereum mainnet
    }

    signed_txn = web3.eth.account.sign_transaction(txn, account.key)
    txn_hash = web3.eth.send_raw_transaction(signed_txn.raw_transaction)
    print(f"Approval Transaction Hash: {web3.to_hex(txn_hash)}")

    return txn_hash

def execute_transaction(calldata, router_address):
    """Execute the swap transaction on GlueX Router"""
    txn = {
        "from": account.address,
        "to": Web3.to_checksum_address(router_address),
        "data": calldata,
        "gas": COMPUTATION_UNITS,
        "gasPrice": web3.eth.gas_price,
        "nonce": web3.eth.get_transaction_count(account.address),
        "chainId": 1,  # Ethereum mainnet
    }

    signed_txn = web3.eth.account.sign_transaction(txn, account.key)

    try:
        txn_hash = web3.eth.send_raw_transaction(signed_txn.raw_transaction)
    except Web3RPCError as err:
        time.sleep(5)
        txn["nonce"] = web3.eth.get_transaction_count(account.address)
        signed_txn = web3.eth.account.sign_transaction(txn, account.key)
        txn_hash = web3.eth.send_raw_transaction(signed_txn.raw_transaction)

    print(f"Transaction Hash: {web3.to_hex(txn_hash)}")

    return txn_hash

def main():
    # Fetch the quote
    quote_data = fetch_quote()
    if quote_data.get('statusCode') != 200:
        print("Error fetching quote:", quote_data)
        return

    print("Quote received successfully:", quote_data)
    router_address = quote_data["result"]["router"]
    calldata = quote_data["result"]["calldata"]

    # Approve the router contract
    print("Approving router contract to spend USDC...")
    txn_hash = approve_spender(router_address, INPUT_AMOUNT, USDC_ADDRESS)
    print("Waiting for approval transaction confirmation...")
    approval_receipt = web3.eth.wait_for_transaction_receipt(txn_hash)
    if approval_receipt.status != 1:
        print("Approval failed. Aborting.")
        return

    # Execute the transaction
    print("Executing transaction...")
    execute_txn = execute_transaction(calldata, router_address)

    receipt = web3.eth.wait_for_transaction_receipt(execute_txn)
    print("Transaction confirmed. Receipt:")
    print(receipt)


if __name__ == "__main__":
    main()
import { Web3 } from 'web3';
import axios from 'axios';

// Configuration
const API_KEY = "your_api_key";
const UNIQUE_PID = "your_unique_pid";
const QUOTE_ENDPOINT = "https://router.gluex.xyz/v1/quote";
const RPC_URL = "https://mainnet.gateway.tenderly.co/your_rpc_url";
const PRIVATE_KEY = "your_private_key";

// Token Addresses
const USDC_ADDRESS = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"; // USDC on Ethereum
const ETH_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";   // ETH on Ethereum
const INPUT_AMOUNT = BigInt("1000000"); // 1 USDC (6 decimals)

// Initialize Web3
const web3 = new Web3(RPC_URL);
const account = web3.eth.accounts.privateKeyToAccount(PRIVATE_KEY);
const COMPUTATION_UNITS = 1000000;

// Types
interface QuoteBody {
    chainID: string;
    userAddress: string;
    outputReceiver: string;
    uniquePID: string;
    inputToken: string;
    outputToken: string;
    inputAmount: bigint;
    isPermit2: boolean;
}

interface QuoteRequestBody {
    chainID: string;
    userAddress: string;
    outputReceiver: string;
    uniquePID: string;
    inputToken: string;
    outputToken: string;
    inputAmount: string;
    isPermit2: boolean;
}

interface QuoteResponse {
    statusCode: number;
    result?: {
        router: string;
        calldata: string;
    };
}

const fetchQuote = async (body: QuoteRequestBody, headers: { [key: string]: string }): Promise<QuoteResponse> => {
    console.log("Fetch a quote from the GlueX Router for $USDC to $ETH swap");
    const response = await axios.post(QUOTE_ENDPOINT, body, { headers });
    return response.data;
};

const approveSpender = async (
    spender: string,
    amount: bigint,
    tokenAddress: string
): Promise<string> => {
    const signature = "0x095ea7b3";
    const paddedSpender = web3.utils.toChecksumAddress(spender).slice(2).padStart(64, '0');
    const calldata = `${signature}${paddedSpender}${amount.toString(16).padStart(64, '0')}`;

    const txn = {
        from: account.address,
        to: web3.utils.toChecksumAddress(tokenAddress),
        data: calldata,
        gas: COMPUTATION_UNITS,
        gasPrice: await web3.eth.getGasPrice(),
        nonce: await web3.eth.getTransactionCount(account.address),
        chainId: 1, // Ethereum mainnet
    };

    const signedTxn = await account.signTransaction(txn);
    const receipt = await web3.eth.sendSignedTransaction(signedTxn.rawTransaction);
    const txHash = web3.utils.toHex(receipt.transactionHash);
    console.log(`Approval Transaction Hash: ${txHash}`);
    return txHash;
};

const executeTransaction = async (
    calldata: string,
    routerAddress: string
): Promise<string> => {
    const txn = {
        from: account.address,
        to: web3.utils.toChecksumAddress(routerAddress),
        data: calldata,
        gas: COMPUTATION_UNITS,
        gasPrice: await web3.eth.getGasPrice(),
        nonce: await web3.eth.getTransactionCount(account.address),
        chainId: 1, // Ethereum mainnet
    };

    try {
        const signedTxn = await account.signTransaction(txn);
        const receipt = await web3.eth.sendSignedTransaction(signedTxn.rawTransaction);
        const txHash = web3.utils.toHex(receipt.transactionHash);
        console.log(`Transaction Hash: ${txHash}`);
        return txHash;
    } catch (err) {
        await new Promise(resolve => setTimeout(resolve, 5000));
        txn.nonce = await web3.eth.getTransactionCount(account.address);
        const signedTxn = await account.signTransaction(txn);
        const receipt = await web3.eth.sendSignedTransaction(signedTxn.rawTransaction);
        const txHash = web3.utils.toHex(receipt.transactionHash);
        console.log(`Transaction Hash: ${txHash}`);
        return txHash;
    }
};

const main = async (): Promise<void> => {
    const headers = { "x-api-key": API_KEY };
    const body: QuoteBody = {
        chainID: "1", // Ethereum Mainnet
        userAddress: account.address,
        outputReceiver: account.address,
        uniquePID: UNIQUE_PID,
        inputToken: USDC_ADDRESS,
        outputToken: ETH_ADDRESS,
        inputAmount: INPUT_AMOUNT,
        isPermit2: false
    };

    // Convert BigInt to string for axios serialization
    const requestBody = {
        ...body,
        inputAmount: body.inputAmount.toString()
    };

    console.log("Fetching swap quote...");
    const quoteData = await fetchQuote(requestBody, headers);

    if (quoteData.statusCode !== 200) {
        console.log("Error fetching quote:", quoteData);
        return;
    }

    console.log("Quote received successfully:", quoteData);
    const routerAddress = quoteData.result!.router;
    const calldata = quoteData.result!.calldata;

    // Approve the router contract
    console.log("Approving router contract to spend USDC...");
    const txnHash = await approveSpender(routerAddress, INPUT_AMOUNT, USDC_ADDRESS);
    console.log("Waiting for approval transaction confirmation...");
    const approvalReceipt = await web3.eth.getTransactionReceipt(txnHash);
    if (!approvalReceipt || !approvalReceipt.status) {
        console.log("Approval failed. Aborting.");
        return;
    }

    // Execute the transaction
    console.log("Executing transaction...");
    const executeTxn = await executeTransaction(calldata, routerAddress);

    const receipt = await web3.eth.getTransactionReceipt(executeTxn);
    console.log("Transaction confirmed. Receipt:");
    console.log(receipt);
};

// Run the main function
main().catch(console.error);
import { Web3 } from 'web3';
import axios from 'axios';

// Configuration
const API_KEY = "your_api_key";
const UNIQUE_PID = "your_unique_pid";
const QUOTE_ENDPOINT = "https://router.gluex.xyz/v1/quote";
const RPC_URL = "https://mainnet.gateway.tenderly.co/your_rpc_url";
const PRIVATE_KEY = "your_private_key";

// Token Addresses
const USDC_ADDRESS = "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"; // USDC on Ethereum
const ETH_ADDRESS = "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee";   // ETH on Ethereum
const INPUT_AMOUNT = BigInt("1000000"); // 1 USDC (6 decimals)

// Initialize Web3
const web3 = new Web3(RPC_URL);
const account = web3.eth.accounts.privateKeyToAccount(PRIVATE_KEY);
const COMPUTATION_UNITS = 1000000;

const fetchQuote = async (body, headers) => {
    console.log("Fetch a quote from the GlueX Router for $USDC to $ETH swap");
    const response = await axios.post(QUOTE_ENDPOINT, body, { headers });
    return response.data;
};

const approveSpender = async (spender, amount, tokenAddress) => {
    const signature = "0x095ea7b3";
    const paddedSpender = web3.utils.toChecksumAddress(spender).slice(2).padStart(64, '0');
    const calldata = `${signature}${paddedSpender}${amount.toString(16).padStart(64, '0')}`;

    const txn = {
        from: account.address,
        to: web3.utils.toChecksumAddress(tokenAddress),
        data: calldata,
        gas: COMPUTATION_UNITS,
        gasPrice: await web3.eth.getGasPrice(),
        nonce: await web3.eth.getTransactionCount(account.address),
        chainId: 1, // Ethereum mainnet
    };

    const signedTxn = await account.signTransaction(txn);
    const receipt = await web3.eth.sendSignedTransaction(signedTxn.rawTransaction);
    const txHash = web3.utils.toHex(receipt.transactionHash);
    console.log(`Approval Transaction Hash: ${txHash}`);
    return txHash;
};

const executeTransaction = async (calldata, routerAddress) => {
    const txn = {
        from: account.address,
        to: web3.utils.toChecksumAddress(routerAddress),
        data: calldata,
        gas: COMPUTATION_UNITS,
        gasPrice: await web3.eth.getGasPrice(),
        nonce: await web3.eth.getTransactionCount(account.address),
        chainId: 1, // Ethereum mainnet
    };

    try {
        const signedTxn = await account.signTransaction(txn);
        const receipt = await web3.eth.sendSignedTransaction(signedTxn.rawTransaction);
        const txHash = web3.utils.toHex(receipt.transactionHash);
        console.log(`Transaction Hash: ${txHash}`);
        return txHash;
    } catch (err) {
        await new Promise(resolve => setTimeout(resolve, 5000));
        txn.nonce = await web3.eth.getTransactionCount(account.address);
        const signedTxn = await account.signTransaction(txn);
        const receipt = await web3.eth.sendSignedTransaction(signedTxn.rawTransaction);
        const txHash = web3.utils.toHex(receipt.transactionHash);
        console.log(`Transaction Hash: ${txHash}`);
        return txHash;
    }
};

const main = async () => {
    const headers = { "x-api-key": API_KEY };
    const body = {
        chainID: "1", // Ethereum Mainnet
        userAddress: account.address,
        outputReceiver: account.address,
        uniquePID: UNIQUE_PID,
        inputToken: USDC_ADDRESS,
        outputToken: ETH_ADDRESS,
        inputAmount: INPUT_AMOUNT,
        isPermit2: false
    };

    // Convert BigInt to string for axios serialization
    const requestBody = {
        ...body,
        inputAmount: body.inputAmount.toString()
    };

    console.log("Fetching swap quote...");
    const quoteData = await fetchQuote(requestBody, headers);

    if (quoteData.statusCode !== 200) {
        console.log("Error fetching quote:", quoteData);
        return;
    }

    console.log("Quote received successfully:", quoteData);
    const routerAddress = quoteData.result.router;
    const calldata = quoteData.result.calldata;

    // Approve the router contract
    console.log("Approving router contract to spend USDC...");
    const txnHash = await approveSpender(routerAddress, INPUT_AMOUNT, USDC_ADDRESS);
    console.log("Waiting for approval transaction confirmation...");
    const approvalReceipt = await web3.eth.getTransactionReceipt(txnHash);
    if (!approvalReceipt || !approvalReceipt.status) {
        console.log("Approval failed. Aborting.");
        return;
    }

    // Execute the transaction
    console.log("Executing transaction...");
    const executeTxn = await executeTransaction(calldata, routerAddress);

    const receipt = await web3.eth.getTransactionReceipt(executeTxn);
    console.log("Transaction confirmed. Receipt:");
    console.log(receipt);
};

// Run the main function
main().catch(console.error);

Running the Script

To execute the swap, run the script as follows:
python dex-transaction.py

Conclusion

By following this tutorial, users can seamlessly swap USDC for ETH using the GlueX Router. The script automates fetching quotes, handling approvals, and executing swaps securely. Users can modify this script to suit their specific needs, such as swapping different tokens, changing input amounts, or integrating it into larger applications.

Opportunities

🔹 Instant access to best swap rates across DEXs 🔹 Seamless token swaps with proper approval handling 🔹 Cost savings by reducing gas fees across multiple steps With GlueX, DeFi becomes as easy as sending an email 🚀