A Vyper smart contract for managing GPU DAO token purchases and cross-chain operations through the Paloma network.
The GPU DAO contract facilitates token purchases with cross-chain bridging capabilities. Users can purchase tokens using various assets, which are then deposited into a PUSD manager and bridged to the Paloma network.
- Language: Vyper 0.4.1
- License: Apache-2.0
- Author: Volume.finance
- EVM Version: Cancun
- Gas Optimization: Enabled
pusd_manager
: Address of the PUSD manager contractWETH9
: Address of WETH9 token contractpgwt
: Address of the PGWT token contractpgwt_amount
: Fixed amount of PGWT tokens required per purchasepurchase_limit
: Maximum contribution limit per user
compass
: Address of the Compass contract for cross-chain operationsrefund_wallet
: Address that receives gas feesgas_fee
: Gas fee amount in weiservice_fee_collector
: Address that receives service feesservice_fee
: Service fee percentage (basis points)paloma
: Paloma network identifier (bytes32)contributions
: Mapping of user addresses to their total contributionssend_nonces
: Mapping of nonces to prevent replay attacks
@deploy
def __init__(_compass: address, _pusd_manager: address, _weth9: address, _pgwt: address,
_pgwt_amount: uint256, _purchase_limit: uint256, _refund_wallet: address,
_gas_fee: uint256, _service_fee_collector: address, _service_fee: uint256)
Purpose: Initializes the contract with all required parameters.
Security Considerations:
- Validates that
_compass
is not the zero address - Ensures
_service_fee
is less thanDENOMINATOR
(100%) - Emits events for all parameter updates for transparency
Usage Example:
# Deploy with parameters
constructor_params = [
compass_address,
pusd_manager_address,
weth9_address,
pgwt_address,
pgwt_amount,
purchase_limit,
refund_wallet,
gas_fee,
service_fee_collector,
service_fee
]
contract = GPU_DAO.deploy(*constructor_params, sender=deployer)
Purpose: Safely approves token spending with error handling.
Security Considerations:
- Uses
default_return_value=True
to handle non-standard ERC20 tokens - Reverts on failed approvals to prevent silent failures
Purpose: Safely transfers tokens with error handling.
Security Considerations:
- Uses
default_return_value=True
for non-standard ERC20 compatibility - Reverts on failed transfers
Purpose: Safely transfers tokens from one address to another with error handling.
Security Considerations:
- Uses
default_return_value=True
for non-standard ERC20 compatibility - Reverts on failed transfers
Purpose: Allows users to purchase tokens by providing assets and receiving PUSD tokens.
Function Flow:
- Transfers required PGWT tokens from user to contract
- Handles gas fee deduction and refund
- Determines the source token (from path or PUSD manager asset)
- Processes token deposit (WETH or ERC20)
- Calculates and transfers service fees
- Approves and deposits tokens to PUSD manager
- Updates user contribution and checks purchase limit
- Sends PGWT tokens to Paloma via Compass
- Emits Purchase event
Security Considerations:
- Access Control: No restrictions - any user can call
- Reentrancy: No external calls after state changes
- Input Validation: Validates
min_amount
when path is provided - Overflow Protection: Uses safe math operations
- Purchase Limit: Enforces per-user contribution limits
Usage Example:
# Purchase with ETH (WETH)
contract.purchase(
path=b"", # Empty path for default asset
amount=1e18, # 1 ETH
min_amount=0,
value=1e18, # Send 1 ETH
sender=user
)
# Purchase with custom token
contract.purchase(
path=token_address + swap_path, # Token address + swap path
amount=1000e6, # 1000 USDC
min_amount=950e18, # Minimum PUSD received
sender=user
)
Purpose: Allows users to claim rewards or refunds.
Function Flow:
- Handles gas fee deduction and refund
- Returns any excess ETH to the caller
- Emits Claim event
Security Considerations:
- Access Control: No restrictions - any user can call
- Gas Fee: Deducts gas fee if configured
- ETH Refund: Returns excess ETH to caller
Usage Example:
# Claim with gas fee
contract.claim(value=gas_fee, sender=user)
Purpose: Updates the Compass contract address.
Security Considerations:
- Access Control: Only current compass can call
- SLC Check: Verifies SLC is available before update
- Event Emission: Logs the update for transparency
Usage Example:
# Only callable by current compass
contract.update_compass(new_compass_address, sender=current_compass)
Purpose: Sets the Paloma network identifier.
Security Considerations:
- Access Control: Only compass can call
- One-time Setup: Can only be set once (when paloma is empty)
- Data Validation: Validates message data length and extracts paloma ID
Usage Example:
# Set paloma ID (called by compass)
paloma_id = b"paloma_network_id_32_bytes_long"
contract.set_paloma(data=paloma_id, sender=compass)
Purpose: Updates the refund wallet address.
Security Considerations:
- Access Control: Only compass with valid paloma signature
- Event Emission: Logs the update
Usage Example:
# Update refund wallet (called by compass with paloma signature)
contract.update_refund_wallet(new_wallet, sender=compass)
Purpose: Updates the gas fee amount.
Security Considerations:
- Access Control: Only compass with valid paloma signature
- Event Emission: Logs the update
Usage Example:
# Update gas fee (called by compass with paloma signature)
contract.update_gas_fee(new_gas_fee, sender=compass)
Purpose: Updates the service fee collector address.
Security Considerations:
- Access Control: Only compass with valid paloma signature
- Event Emission: Logs the update
Usage Example:
# Update service fee collector (called by compass with paloma signature)
contract.update_service_fee_collector(new_collector, sender=compass)
Purpose: Updates the service fee percentage.
Security Considerations:
- Access Control: Only compass with valid paloma signature
- Input Validation: Ensures fee is less than 100%
- Event Emission: Logs the update
Usage Example:
# Update service fee (called by compass with paloma signature)
contract.update_service_fee(new_fee, sender=compass)
Purpose: Validates that the caller is the compass and has a valid paloma signature.
Security Considerations:
- Access Control: Only compass can pass
- Signature Validation: Verifies paloma signature in message data
- Reused Logic: Centralized validation for paloma-authorized functions
- sender: Address of the purchaser (indexed)
- from_token: Address of the token used for purchase
- amount: Amount of tokens purchased
- pusd_amount: Amount of PUSD tokens received
- sender: Address of the claimant (indexed)
- old_compass: Previous compass address
- new_compass: New compass address
- old_refund_wallet: Previous refund wallet address
- new_refund_wallet: New refund wallet address
- paloma: Paloma network identifier
- old_gas_fee: Previous gas fee amount
- new_gas_fee: New gas fee amount
- old_service_fee_collector: Previous service fee collector address
- new_service_fee_collector: New service fee collector address
- old_service_fee: Previous service fee percentage
- new_service_fee: New service fee percentage
- Public Functions:
purchase()
andclaim()
are unrestricted - Compass-Only:
update_compass()
,set_paloma()
require compass authorization - Paloma-Authorized: Update functions require compass + paloma signature validation
- No external calls after state changes in critical functions
- Safe token transfer patterns used throughout
- Address validation in constructor
- Service fee bounds checking
- Purchase limit enforcement
- Message data validation for paloma operations
- Safe ERC20 transfer patterns with
default_return_value=True
- Balance checks before and after transfers
- Proper approval management
- Gas fee collection mechanism
- Service fee calculation and distribution
- Purchase limit per user
- Excess ETH refund handling
This project uses the Ape Framework for testing. To run tests:
# Install Ape Framework
pip install eth-ape
# Install Vyper compiler
pip install vyper
# Run all tests
ape test
# Run tests with verbose output
ape test -v
# Run specific test file
ape test tests/test_gpu_dao.py
# Run tests with coverage
ape test --coverage
Create test files in a tests/
directory with the following structure:
# tests/test_gpu_dao.py
import pytest
from ape import accounts, Contract
def test_constructor():
# Test constructor parameters
pass
def test_purchase():
# Test purchase functionality
pass
def test_claim():
# Test claim functionality
pass
def test_admin_functions():
# Test admin/compass functions
pass
# Deploy to local network
ape run deploy
# Deploy to testnet
ape run deploy --network ethereum:goerli
# Deploy to mainnet
ape run deploy --network ethereum:mainnet
# scripts/deploy.py
from ape import accounts, Contract
def main():
deployer = accounts.load("deployer")
# Deploy GPU DAO
gpu_dao = Contract.deploy(
compass_address,
pusd_manager_address,
weth9_address,
pgwt_address,
pgwt_amount,
purchase_limit,
refund_wallet,
gas_fee,
service_fee_collector,
service_fee,
sender=deployer
)
print(f"GPU DAO deployed at: {gpu_dao.address}")
- ERC20: Standard ERC20 token interface
- PusdManager: PUSD management contract
- Weth: WETH9 wrapper contract
- Compass: Cross-chain bridge contract
DENOMINATOR
: 10^18 (for fee calculations)
Apache-2.0 License - see LICENSE file for details.