Case
Suppose you hold $GALA and want to put it to work earning yield in a lending protocol, specifically by converting it into interest bearing $aETHWETH in a single atomic transaction. With GlueX’s unified Router API and smart contract integrations, you can swap one token and deposit the proceeds into a lending vault atomically, without juggling approvals or multiple onchain calls. In this guide, we’ll walk through exactly how to:- Build a swap quote to convert $GALA into $WETH
- Bundle that quote into a Zap that deposits directly into the Aave vault to receive $aETHWETH
- Submit the transaction and verify the resulting vault deposit
Transaction hash: 0xd0c48d25ac3e0ab111b3ab401903d4a357baa22ee9c9efb832e0b80278ba5ba3

How It Works
- Transfer $GALA from the user’s wallet
- Swap $GALA for $WETH via Uniswap V3
- Receive $aETHWETH via Aave V3
- Start earning yield automatically
Why This Matters?
Moving from a regular token to a yield bearing asset usually requires multiple platforms, manual steps and higher fees. GlueX removes these barriers, bringing: ✅ Time efficiency - One transaction instead of many ✅ Cost savings - Lesser gas fees ✅ Simplicity - No manual interactions with multiple protocols This tutorial uses $GALA → $aETHWETH as an example, but GlueX allows you to swap any token to any yield generating token in a single transactionImplementation
Prerequisites
Before running the script, ensure you have the following installed: Python:- Python 3.10
- Web3 (
pip install web3) - Requests (
pip install requests)
- Node.js 18+
- TypeScript (
npm install -g typescript) - Web3 (
npm install web3) - Axios (
npm install axios)
- Node.js 18+
- Web3 (
npm install web3) - Axios (
npm install axios)
Setup and Configuration
Copy
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
GALA_ADDRESS = "0xd1d2Eb1B1e90B638588728b4130137D262C87cae"
AETHWETH_ADDRESS = "0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8"
# Input amount (in decimals)
INPUT_AMOUNT = 2000000000000 # 2,000,000 GALA (including 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 RouterCopy
def fetch_quote():
"""Fetch a quote from the GlueX Router for $GALA to $aETHWETH swap"""
headers = {"x-api-key": API_KEY}
body = {
"chainID": "ethereum",
"userAddress": account.address,
"outputReceiver": account.address,
"uniquePID": UNIQUE_PID,
"inputToken": GALA_ADDRESS,
"outputToken": AETHWETH_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 GALA tokensCopy
def approve_spender(spender, amount, token_address):
"""Approve the router contract to spend $GALA"""
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 quoteCopy
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
Copy
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 GALA...")
txn_hash = approve_spender(router_address, INPUT_AMOUNT, GALA_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
Complete Python Implementation
Complete Python Implementation
Copy
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
GALA_ADDRESS = "0xd1d2Eb1B1e90B638588728b4130137D262C87cae"
AETHWETH_ADDRESS = "0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8"
# Input amount (in decimals)
INPUT_AMOUNT = 2000000000000 # 2,000,000 GALA (including 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 $GALA to $aETHWETH swap"""
headers = {"x-api-key": API_KEY}
body = {
"chainID": "ethereum",
"userAddress": account.address,
"outputReceiver": account.address,
"uniquePID": UNIQUE_PID,
"inputToken": GALA_ADDRESS,
"outputToken": AETHWETH_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 $GALA"""
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 GALA...")
txn_hash = approve_spender(router_address, INPUT_AMOUNT, GALA_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 TypeScript Implementation
Complete TypeScript Implementation
Copy
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 GALA_ADDRESS = "0xd1d2Eb1B1e90B638588728b4130137D262C87cae";
const AETHWETH_ADDRESS = "0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8";
// Input amount (in decimals)
const INPUT_AMOUNT = BigInt("2000000000000"); // 2,000,000 GALA (including 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 $GALA to $aETHWETH 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: "ethereum",
userAddress: account.address,
outputReceiver: account.address,
uniquePID: UNIQUE_PID,
inputToken: GALA_ADDRESS,
outputToken: AETHWETH_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 GALA...");
const txnHash = await approveSpender(routerAddress, INPUT_AMOUNT, GALA_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);
Complete JavaScript Implementation
Complete JavaScript Implementation
Copy
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 GALA_ADDRESS = "0xd1d2Eb1B1e90B638588728b4130137D262C87cae";
const AETHWETH_ADDRESS = "0x4d5F47FA6A74757f35C14fD3a6Ef8E3C9BC514E8";
// Input amount (in decimals)
const INPUT_AMOUNT = BigInt("2000000000000"); // 2,000,000 GALA (including 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 $GALA to $aETHWETH 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: "ethereum",
userAddress: account.address,
outputReceiver: account.address,
uniquePID: UNIQUE_PID,
inputToken: GALA_ADDRESS,
outputToken: AETHWETH_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 GALA...");
const txnHash = await approveSpender(routerAddress, INPUT_AMOUNT, GALA_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 deposit, run the script as follows:Copy
python deposit_to_lending_vault.py
Conclusion
With GlueX, moving from $GALA to a yield generating asset like $aETHWETH takes just one transaction. This tutorial demonstrates:- Fetching a swap quote
- Approving the router contract to spend $GALA
- Executing the transaction to swap and deposit smoothly