Step 1 - Setup Gas wallet Allowance
To initiate an ERC20 approve transaction, replace the token, source wallet, gas wallet, bearer token, vault ID and run the following code:
from web3 import Web3
import requests
bearer_token = "YOUR_BEARER_TOKEN" # Replace with an updated token
vault_id = "YOUR_VAULT_ID" # Replace with the actual vault ID
token_address = "0x1c7D4B196Cb0C7B01d743Fbc6116a902379C7238" # approval token smart contract address (USDC Sepolia)
source_wallet_address = "0xB70e07bAc842d9547C1d56AB7eF5e27021024f23" # Source Wallet
gas_wallet_address = "0x968284717EcdB5696c03e842A5aFa3d1F0333bBd" # Gas Wallet
amount = 1 * (10 ** 6) # Amount to approve (1 USDC = 1 * 10^6 because USDC has 6 decimals)
Prepare the ERC20 call data:
# ABI for approve function
approve_abi =[{
"constant": False,
"inputs": [
{"name": "spender", "type": "address"},
{"name": "amount", "type": "uint256"}
],
"name": "approve",
"outputs": [{"name": "", "type": "bool"}],
"stateMutability": "nonpayable",
"type": "function"
}]
# Connect to the Sepolia network
rpc_url = "https://ethereum-sepolia-rpc.publicnode.com" # Replace with a valid Polygon RPC URL if needed
web3 = Web3(Web3.HTTPProvider(rpc_url))
# Encode function call data
contract = web3.eth.contract(address=token_address, abi=approve_abi)
calldata = contract.functions.approve(gas_wallet_address, amount).build_transaction({"from": source_wallet_address})["data"]
Initiate an EVM Transaction:
url = f"https://api.utila.io/v2/vaults/{vault_id}/transactions:initiate"
approve_payload = {
"details": {
"evmTransaction": {
"network": "networks/ethereum-testnet-sepolia",
"fromAddress": "{0}".format(source_wallet_address),
"toAddress": "{0}".format(token_address),
"data": "{0}".format(calldata), # Replace with actual calldata
},
},
"note": "Token Approval",
"includeReferencedResources": True
}
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer {0}".format(bearer_token) # If authentication is required
}
response = requests.post(url, json=approve_payload, headers=headers)
print(response.status_code)
print(response.json()) # If the response is in JSON format
After internal approval and signing, the transaction will appear in the console as:

Step 2 - Initiate transferFrom by the Gas wallet
Similarly, set a destination wallet address and initiate an ERC20 transferFrom transaction :
destination_address = "0x9e21BF0F214cD33b2DC3Bfd49301E86d62b564Dc"
amount = int(0.05 * (10 ** 6)) # Amount to approve (1 USDC = 1 * 10^6 because USDC has 6 decimals)
transfer_from_abi = [{
"constant": False,
"inputs": [
{"name": "from", "type": "address"},
{"name": "to", "type": "address"},
{"name": "value", "type": "uint256"}
],
"name": "transferFrom",
"outputs": [{"name": "", "type": "bool"}],
"stateMutability": "nonpayable",
"type": "function"
}]
# Connect to the Sepolia network
rpc_url = "https://ethereum-sepolia-rpc.publicnode.com" # Replace with a valid Polygon RPC URL if needed
web3 = Web3(Web3.HTTPProvider(rpc_url))
# Encode function call data
contract = web3.eth.contract(address=token_address, abi=transfer_from_abi)
calldata = contract.functions.transferFrom(
source_wallet_address, # The owner of the USDC
destination_address, # The recipient of USDC
amount # Amount to transfer
).build_transaction({
"from": gas_wallet_address, # The approved spender (gas wallet)
"gas": 100000,
"gasPrice": web3.to_wei("50", "gwei"),
"nonce": web3.eth.get_transaction_count(gas_wallet_address),
})["data"]
url = f"https://api.utila.io/v1alpha2/vaults/{vault_id}/transactions:initiate" # Replace with the correct API endpoint
transferFrom_payload = {
"details": {
"evmTransaction": {
"network": "networks/ethereum-testnet-sepolia".format(token_address),
"fromAddress": "{0}".format(gas_wallet_address),
"toAddress": "{0}".format(token_address),
"data": "{0}".format(calldata), # Replace with actual calldata
},
},
"note": "Transfer USDC using transferFrom",
"includeReferencedResources": True
}
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer {0}".format(bearer_token) # If authentication is required
}
response = requests.post(url, json=transferFrom_payload, headers=headers)
print(response.status_code)
print(response.json()) # If the response is in JSON format
After internal approval and signing, the transaction will appear in the console as:
