Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,7 @@ next-env.d.ts

.next/

**/dist/
**/dist/
**/__pycache__/
**/*.egg-info/
**/node_modules/
5 changes: 5 additions & 0 deletions v2/gas_sponsorship/python/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
COMPASS_API_KEY=your_api_key_here
WALLET_ADDRESS=0xYourOwnerWalletAddress
OWNER_PRIVATE_KEY=your_owner_private_key_here
SENDER_PRIVATE_KEY=your_sender_private_key_here
BASE_RPC_URL=https://mainnet.base.org
93 changes: 93 additions & 0 deletions v2/gas_sponsorship/python/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Gas Sponsorship - Python Example

This example demonstrates two gas sponsorship use cases using the Compass API Python SDK:

1. **Fund Earn Account with Gas Sponsorship**: Approve and transfer tokens from your wallet to your Earn Account, with gas paid by a sponsor
2. **Manage Earn Position with Gas Sponsorship**: Deposit into a Morpho vault from your Earn Account, with gas paid by a sponsor

## Prerequisites

- Python 3.8+ installed
- A Compass API key ([Get one here](https://auth-compasslabs-ai.auth.eu-west-2.amazoncognito.com/login?client_id=2l366l2b3dok7k71nbnu8r1u36&redirect_uri=https://api.compasslabs.ai/auth/callback&response_type=code&scope=openid+email+profile))
- Two wallet addresses:
- `owner`: The wallet that owns the Earn Account (signs EIP-712 typed data off-chain)
- `sender`: The wallet that pays for gas (signs and broadcasts transactions)

## Setup

1. Install dependencies:
```bash
pip install -e .
```

Or install manually:
```bash
pip install compass-api-sdk python-dotenv web3 eth-account
```

2. Copy the example environment file:
```bash
cp .env.example .env
```

3. Fill in your `.env` file with your actual values:
- `COMPASS_API_KEY`: Your Compass API key
- `WALLET_ADDRESS`: Your wallet address (owner of the Earn Account)
- `OWNER_PRIVATE_KEY`: Owner's private key (to sign EIP-712 typed data)
- `SENDER_PRIVATE_KEY`: Sender's private key (to sign and broadcast transactions)
- `BASE_RPC_URL`: Your Base mainnet RPC URL

## Run

```bash
python main.py
```

## What This Does

### Example 1: Fund Earn Account with Gas Sponsorship

This demonstrates the 4-step flow to fund an Earn Account with gas sponsorship:

1. **Get EIP-712 typed data**: Calls `/v2/gas_sponsorship/approve_transfer` with `gas_sponsorship: True` to get Permit2 approval typed data
2. **Sign typed data**: The `owner` signs the EIP-712 typed data off-chain (no gas required)
3. **Prepare transaction**: Calls `/v2/gas_sponsorship/prepare` with the signature to get the approval transaction
4. **Execute**: The `sender` signs and broadcasts the transaction (sender pays gas)

After this, the Earn Account can be funded using `/v2/earn/transfer` with gas sponsorship enabled.

### Example 2: Manage Earn Position with Gas Sponsorship

This demonstrates the 4-step flow to deposit into a vault with gas sponsorship:

1. **Get EIP-712 typed data**: Calls `/v2/earn/manage` with `gas_sponsorship: True` to get deposit typed data
2. **Sign typed data**: The `owner` signs the EIP-712 typed data off-chain (no gas required)
3. **Prepare transaction**: Calls `/v2/gas_sponsorship/prepare` with the signature to get the deposit transaction
4. **Execute**: The `sender` signs and broadcasts the transaction (sender pays gas)

## Notes

- The `owner` must be the address that owns the Earn Account
- The `sender` can be any address that has ETH on Base to pay for gas
- The `owner` and `sender` can be the same address, but they serve different roles in the flow
- Example 2 deposits 0.5 USDC into the Steakhouse USDC vault on Morpho (`0xbeeF010f9cb27031ad51e3333f9aF9C6B1228183`)
- Make sure your Earn Account has sufficient USDC balance for deposits
- Make sure the `sender` wallet has enough ETH on Base to cover gas fees
- **Important**: Make sure you're using `compass-api-sdk` version 2.0.1 or later

## Known Issues

**Example 2 (Manage Earn Position) - Signature Validation Error:**

There is a known issue with the Python SDK's EIP-712 structure handling for `BatchedSafeOperationsResponse` (SafeTx). When calling `/v2/gas_sponsorship/prepare` with EIP-712 data from `/v2/earn/manage`, the signature validation may fail with "Invalid signature" error.

**Workaround:**
- The TypeScript version works correctly. Please use the TypeScript example for managing Earn positions with gas sponsorship.
- Example 1 (Fund Earn Account) works correctly in Python.

**Root Cause:**
The Python SDK requires a dict format for EIP-712 data, but there's a structure mismatch between what we sign (for `eth_account` compatibility) and what the backend validates. The TypeScript SDK handles this correctly by passing the model object directly.

**Status:**
This is a known limitation. Please contact the API team about Python SDK's EIP-712 serialization for `BatchedSafeOperationsResponse`.

130 changes: 130 additions & 0 deletions v2/gas_sponsorship/python/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# SNIPPET START 1
from compass_api_sdk import CompassAPI, models
import os
from dotenv import load_dotenv
from web3 import Web3
from eth_account import Account
from eth_account.messages import encode_typed_data

load_dotenv()

COMPASS_API_KEY = os.getenv("COMPASS_API_KEY")
WALLET_ADDRESS = os.getenv("WALLET_ADDRESS")
OWNER_PRIVATE_KEY = os.getenv("OWNER_PRIVATE_KEY")
SENDER_PRIVATE_KEY = os.getenv("SENDER_PRIVATE_KEY")
BASE_RPC_URL = os.getenv("BASE_RPC_URL")

w3 = Web3(Web3.HTTPProvider(BASE_RPC_URL))

def normalize_private_key(key: str) -> str:
return key if key.startswith("0x") else f"0x{key}"

def sign_eip712(account: Account, eip712: dict) -> str:
encoded = encode_typed_data(full_message=eip712)
signed = account.sign_message(encoded)
return f"0x{signed.signature.hex()}"

def send_transaction(tx_dict: dict, private_key: str) -> str:
signed_tx = w3.eth.account.sign_transaction(tx_dict, private_key)
tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction)
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
tx_hash_hex = f"0x{tx_hash.hex()}"
print(f"Deposit transaction hash: {tx_hash_hex}")
print(f"View on BaseScan: https://basescan.org/tx/{tx_hash_hex}")
print(f"Deposit confirmed in block: {receipt.blockNumber}")
return tx_hash_hex
# SNIPPET END 1

# SNIPPET START 2
with CompassAPI(api_key_auth=COMPASS_API_KEY) as compass_api:
owner_account = Account.from_key(normalize_private_key(OWNER_PRIVATE_KEY))
sender_account = Account.from_key(normalize_private_key(SENDER_PRIVATE_KEY))
# SNIPPET END 2

# ============================================================================
# EXAMPLE 1: Fund Earn Account with Gas Sponsorship
# ============================================================================

# SNIPPET START 3
# Get EIP-712 typed data for Permit2 approval
try:
approve_response = compass_api.gas_sponsorship.gas_sponsorship_approve_transfer(
owner=WALLET_ADDRESS,
chain=models.Chain.BASE,
token="USDC",
gas_sponsorship=True,
)
except Exception as e:
if "allowance already set" in str(e).lower():
print("Permit2 approval already exists - skipping to Example 2")
approve_response = None
else:
raise
# SNIPPET END 3

# SNIPPET START 4
# Sign EIP-712 typed data with owner's private key
if approve_response and approve_response.eip_712:
approve_eip712 = approve_response.eip_712.model_dump(by_alias=True, mode="json")
approve_signature = sign_eip712(owner_account, approve_eip712)
else:
approve_eip712 = None
approve_signature = None
# SNIPPET END 4

# SNIPPET START 5
# Prepare and send Permit2 approval transaction
if approve_eip712 and approve_signature:
prepare_response = compass_api.gas_sponsorship.gas_sponsorship_prepare(
owner=WALLET_ADDRESS,
chain=models.Chain.BASE,
eip_712=approve_eip712,
signature=approve_signature,
sender=sender_account.address,
)
tx_dict = prepare_response.model_dump(by_alias=True)["transaction"]
send_transaction(tx_dict, SENDER_PRIVATE_KEY)
print("Earn Account can now be funded with gas sponsorship")
else:
print("Skipping Example 1 transaction - Permit2 approval already exists")
# SNIPPET END 5

# ============================================================================
# EXAMPLE 2: Manage Earn Position (Deposit) with Gas Sponsorship
# ============================================================================

# SNIPPET START 6
# Get EIP-712 typed data for deposit
manage_response = compass_api.earn.earn_manage(
owner=WALLET_ADDRESS,
chain=models.Chain.BASE,
venue={"type": "VAULT", "vault_address": "0xbeeF010f9cb27031ad51e3333f9aF9C6B1228183"},
action=models.EarnManageRequestAction.DEPOSIT,
amount="0.5",
gas_sponsorship=True,
fee=None,
)
# SNIPPET END 6

# SNIPPET START 7
# Sign EIP-712 typed data with owner's private key
import json
manage_eip712 = manage_response.eip_712.model_dump(by_alias=True, mode="json")
manage_eip712 = json.loads(json.dumps(manage_eip712, default=str))
manage_signature = sign_eip712(owner_account, manage_eip712)
# SNIPPET END 7

# SNIPPET START 8
# Prepare and send deposit transaction
eip712_input = models.BatchedSafeOperationsResponseInput(**manage_eip712)
prepare_response = compass_api.gas_sponsorship.gas_sponsorship_prepare(
owner=WALLET_ADDRESS,
chain=models.Chain.BASE,
eip_712=eip712_input,
signature=manage_signature,
sender=sender_account.address,
)
tx_dict = prepare_response.model_dump(by_alias=True)["transaction"]
send_transaction(tx_dict, SENDER_PRIVATE_KEY)
print("Gas-sponsored deposit transaction confirmed")
# SNIPPET END 8
11 changes: 11 additions & 0 deletions v2/gas_sponsorship/python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[project]
name = "gas_sponsorship_python_example"
version = "1.0.0"
description = "Example: Gas Sponsorship for Earn Account Funding and Position Management using Compass API"
dependencies = [
"compass-api-sdk",
"python-dotenv",
"web3",
"eth-account",
]

5 changes: 5 additions & 0 deletions v2/gas_sponsorship/typescript/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
COMPASS_API_KEY=your_api_key_here
WALLET_ADDRESS=0xYourOwnerWalletAddress
OWNER_PRIVATE_KEY=your_owner_private_key_here
SENDER_PRIVATE_KEY=your_sender_private_key_here
BASE_RPC_URL=https://mainnet.base.org
77 changes: 77 additions & 0 deletions v2/gas_sponsorship/typescript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# Gas Sponsorship - TypeScript Example

This example demonstrates two gas sponsorship use cases using the Compass API TypeScript SDK:

1. **Fund Earn Account with Gas Sponsorship**: Approve and transfer tokens from your wallet to your Earn Account, with gas paid by a sponsor
2. **Manage Earn Position with Gas Sponsorship**: Deposit into a Morpho vault from your Earn Account, with gas paid by a sponsor

## Prerequisites

- Node.js 18+ installed
- A Compass API key ([Get one here](https://auth-compasslabs-ai.auth.eu-west-2.amazoncognito.com/login?client_id=2l366l2b3dok7k71nbnu8r1u36&redirect_uri=https://api.compasslabs.ai/auth/callback&response_type=code&scope=openid+email+profile))
- Two wallet addresses:
- `owner`: The wallet that owns the Earn Account (signs EIP-712 typed data off-chain)
- `sender`: The wallet that pays for gas (signs and broadcasts transactions)

## Setup

1. Install dependencies:
```bash
npm install
```

2. Copy the example environment file:
```bash
cp .env.example .env
```

3. Fill in your `.env` file with your actual values:
- `COMPASS_API_KEY`: Your Compass API key
- `WALLET_ADDRESS`: Your wallet address (owner of the Earn Account)
- `OWNER_PRIVATE_KEY`: Owner's private key (to sign EIP-712 typed data)
- `SENDER_PRIVATE_KEY`: Sender's private key (to sign and broadcast transactions)
- `BASE_RPC_URL`: Your Base mainnet RPC URL

## Run

```bash
npm run dev
```

Or build and run:
```bash
npm run build
npm start
```

## What This Does

### Example 1: Fund Earn Account with Gas Sponsorship

This demonstrates the 4-step flow to fund an Earn Account with gas sponsorship:

1. **Get EIP-712 typed data**: Calls `/v2/gas_sponsorship/approve_transfer` with `gasSponsorship: true` to get Permit2 approval typed data
2. **Sign typed data**: The `owner` signs the EIP-712 typed data off-chain (no gas required)
3. **Prepare transaction**: Calls `/v2/gas_sponsorship/prepare` with the signature to get the approval transaction
4. **Execute**: The `sender` signs and broadcasts the transaction (sender pays gas)

After this, the Earn Account can be funded using `/v2/earn/transfer` with gas sponsorship enabled.

### Example 2: Manage Earn Position with Gas Sponsorship

This demonstrates the 4-step flow to deposit into a vault with gas sponsorship:

1. **Get EIP-712 typed data**: Calls `/v2/earn/manage` with `gasSponsorship: true` to get deposit typed data
2. **Sign typed data**: The `owner` signs the EIP-712 typed data off-chain (no gas required)
3. **Prepare transaction**: Calls `/v2/gas_sponsorship/prepare` with the signature to get the deposit transaction
4. **Execute**: The `sender` signs and broadcasts the transaction (sender pays gas)

## Notes

- The `owner` must be the address that owns the Earn Account
- The `sender` can be any address that has ETH on Base to pay for gas
- The `owner` and `sender` can be the same address, but they serve different roles in the flow
- Example 1 deposits into the Steakhouse USDC vault on Morpho (`0xbeeF010f9cb27031ad51e3333f9aF9C6B1228183`)
- Make sure your Earn Account has sufficient USDC balance for deposits
- Make sure the `sender` wallet has enough ETH on Base to cover gas fees

25 changes: 25 additions & 0 deletions v2/gas_sponsorship/typescript/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"name": "gas_sponsorship_typescript_example",
"version": "1.0.0",
"type": "module",
"main": "index.js",
"scripts": {
"build": "tsc",
"start": "tsc && node dist/index.js",
"dev": "ts-node --esm src/index.ts"
},
"author": "",
"license": "ISC",
"description": "Example: Gas Sponsorship for Earn Account Funding and Position Management using Compass API",
"dependencies": {
"@compass-labs/api-sdk": "^2.1.11",
"dotenv": "^16.5.0",
"viem": "^2.31.0"
},
"devDependencies": {
"@types/node": "^24.0.0",
"prettier": "^3.6.2",
"ts-node": "^10.9.2",
"typescript": "^5.8.3"
}
}
Loading
Loading