iagent-pay 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iagent_pay-1.0.0/PKG-INFO +117 -0
- iagent_pay-1.0.0/README.md +88 -0
- iagent_pay-1.0.0/iagent_pay/__init__.py +6 -0
- iagent_pay-1.0.0/iagent_pay/agent_pay.py +148 -0
- iagent_pay-1.0.0/iagent_pay/config.py +39 -0
- iagent_pay-1.0.0/iagent_pay/pricing.py +69 -0
- iagent_pay-1.0.0/iagent_pay/wallet_manager.py +96 -0
- iagent_pay-1.0.0/iagent_pay.egg-info/PKG-INFO +117 -0
- iagent_pay-1.0.0/iagent_pay.egg-info/SOURCES.txt +12 -0
- iagent_pay-1.0.0/iagent_pay.egg-info/dependency_links.txt +1 -0
- iagent_pay-1.0.0/iagent_pay.egg-info/requires.txt +3 -0
- iagent_pay-1.0.0/iagent_pay.egg-info/top_level.txt +1 -0
- iagent_pay-1.0.0/setup.cfg +4 -0
- iagent_pay-1.0.0/setup.py +30 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iagent-pay
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: The First Payment SDK for Autonomous AI Agents.
|
|
5
|
+
Home-page: https://github.com/agent-pay/sdk
|
|
6
|
+
Author: AgentPay Inc.
|
|
7
|
+
Author-email: hello@agentpay.ai
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
15
|
+
Requires-Python: >=3.7
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: web3>=6.0.0
|
|
18
|
+
Requires-Dist: eth-account>=0.8.0
|
|
19
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: requires-dist
|
|
27
|
+
Dynamic: requires-python
|
|
28
|
+
Dynamic: summary
|
|
29
|
+
|
|
30
|
+
# 🤖 iAgentPay SDK v1.0
|
|
31
|
+
|
|
32
|
+
**The Standard Payment Layer for Autonomous AI Agents.**
|
|
33
|
+
|
|
34
|
+
[](https://badge.fury.io/py/iagent-pay)
|
|
35
|
+
[](https://opensource.org/licenses/MIT)
|
|
36
|
+
|
|
37
|
+
AgentPay is a Python SDK designed to allow AI Agents (AutoGPT, LangChain, BabyAGI) to send and receive micropayments securely.
|
|
38
|
+
|
|
39
|
+
## 🚀 Features
|
|
40
|
+
|
|
41
|
+
* **⚡ High-Frequency Trading:** Capable of 750+ transactions per minute.
|
|
42
|
+
* **🔐 Military-Grade Security:** Encrypted JSON Keystores (AES-128).
|
|
43
|
+
* **🔐 Military-Grade Security:** Encrypted JSON Keystores (AES-128).
|
|
44
|
+
* **🌍 Multi-Chain Support (EVM):**
|
|
45
|
+
* ✅ **Ethereum** (Mainnet & Sepolia)
|
|
46
|
+
* ✅ **Base** (Coinbase L2)
|
|
47
|
+
* ✅ **Polygon** (Low fees)
|
|
48
|
+
* ✅ **Arbitrum** & **Optimism**
|
|
49
|
+
* 🚧 *Solana (Coming Soon in v2.0)*
|
|
50
|
+
* **🛡️ Reliability Engine:** Auto-manages Nonces and Gas Fees to prevent stuck transactions.
|
|
51
|
+
* **🛡️ Reliability Engine:** Auto-manages Nonces and Gas Fees to prevent stuck transactions.
|
|
52
|
+
* **💸 Dynamic Pricing:** Update your agent's service fees remotely without code changes.
|
|
53
|
+
* **🎁 60-Day Free Trial:** Start building risk-free with our extended beta program.
|
|
54
|
+
* **📊 Audit Logs:** Built-in SQLite transaction history.
|
|
55
|
+
|
|
56
|
+
## 📦 Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install iagent-pay
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## ⚡ Quick Start
|
|
63
|
+
|
|
64
|
+
### 1. Initialize Wallet
|
|
65
|
+
```python
|
|
66
|
+
from iagent_pay import WalletManager
|
|
67
|
+
|
|
68
|
+
# Create or Load Wallet (Securely)
|
|
69
|
+
wm = WalletManager()
|
|
70
|
+
wallet = wm.get_or_create_wallet(password="SuperSecurePassword")
|
|
71
|
+
print(f"My Agent Address: {wallet.address}")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Send a Payment (Sepolia)
|
|
75
|
+
```python
|
|
76
|
+
from iagent_pay import AgentPay
|
|
77
|
+
|
|
78
|
+
# Connect to Sepolia (or BASE, POLYGON, LOCAL)
|
|
79
|
+
agent = AgentPay(wallet, chain_name="SEPOLIA")
|
|
80
|
+
|
|
81
|
+
# Pay another agent 0.001 ETH
|
|
82
|
+
tx_hash = agent.pay_agent(
|
|
83
|
+
recipient_address="0x123...",
|
|
84
|
+
amount=0.001,
|
|
85
|
+
wait=True # Wait for confirmation
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
print(f"Payment Successful! Hash: {tx_hash}")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3. High-Frequency Mode (No Waiting)
|
|
92
|
+
```python
|
|
93
|
+
# Send 10 payments instantly
|
|
94
|
+
for i in range(10):
|
|
95
|
+
agent.pay_agent("0x123...", 0.0001, wait=False)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 🛠️ Configuration
|
|
99
|
+
|
|
100
|
+
To enable remote pricing updates, create a `pricing_config.json` locally or host it online:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"trial_days": 14,
|
|
105
|
+
"subscription_price_eth": 0.01
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from iagent_pay import PricingManager
|
|
111
|
+
|
|
112
|
+
pm = PricingManager(config_url="https://mysite.com/pricing.json")
|
|
113
|
+
price = pm.get_config()['subscription_price_eth']
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 📄 License
|
|
117
|
+
MIT
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# 🤖 iAgentPay SDK v1.0
|
|
2
|
+
|
|
3
|
+
**The Standard Payment Layer for Autonomous AI Agents.**
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/py/iagent-pay)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
AgentPay is a Python SDK designed to allow AI Agents (AutoGPT, LangChain, BabyAGI) to send and receive micropayments securely.
|
|
9
|
+
|
|
10
|
+
## 🚀 Features
|
|
11
|
+
|
|
12
|
+
* **⚡ High-Frequency Trading:** Capable of 750+ transactions per minute.
|
|
13
|
+
* **🔐 Military-Grade Security:** Encrypted JSON Keystores (AES-128).
|
|
14
|
+
* **🔐 Military-Grade Security:** Encrypted JSON Keystores (AES-128).
|
|
15
|
+
* **🌍 Multi-Chain Support (EVM):**
|
|
16
|
+
* ✅ **Ethereum** (Mainnet & Sepolia)
|
|
17
|
+
* ✅ **Base** (Coinbase L2)
|
|
18
|
+
* ✅ **Polygon** (Low fees)
|
|
19
|
+
* ✅ **Arbitrum** & **Optimism**
|
|
20
|
+
* 🚧 *Solana (Coming Soon in v2.0)*
|
|
21
|
+
* **🛡️ Reliability Engine:** Auto-manages Nonces and Gas Fees to prevent stuck transactions.
|
|
22
|
+
* **🛡️ Reliability Engine:** Auto-manages Nonces and Gas Fees to prevent stuck transactions.
|
|
23
|
+
* **💸 Dynamic Pricing:** Update your agent's service fees remotely without code changes.
|
|
24
|
+
* **🎁 60-Day Free Trial:** Start building risk-free with our extended beta program.
|
|
25
|
+
* **📊 Audit Logs:** Built-in SQLite transaction history.
|
|
26
|
+
|
|
27
|
+
## 📦 Installation
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install iagent-pay
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## ⚡ Quick Start
|
|
34
|
+
|
|
35
|
+
### 1. Initialize Wallet
|
|
36
|
+
```python
|
|
37
|
+
from iagent_pay import WalletManager
|
|
38
|
+
|
|
39
|
+
# Create or Load Wallet (Securely)
|
|
40
|
+
wm = WalletManager()
|
|
41
|
+
wallet = wm.get_or_create_wallet(password="SuperSecurePassword")
|
|
42
|
+
print(f"My Agent Address: {wallet.address}")
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Send a Payment (Sepolia)
|
|
46
|
+
```python
|
|
47
|
+
from iagent_pay import AgentPay
|
|
48
|
+
|
|
49
|
+
# Connect to Sepolia (or BASE, POLYGON, LOCAL)
|
|
50
|
+
agent = AgentPay(wallet, chain_name="SEPOLIA")
|
|
51
|
+
|
|
52
|
+
# Pay another agent 0.001 ETH
|
|
53
|
+
tx_hash = agent.pay_agent(
|
|
54
|
+
recipient_address="0x123...",
|
|
55
|
+
amount=0.001,
|
|
56
|
+
wait=True # Wait for confirmation
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
print(f"Payment Successful! Hash: {tx_hash}")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 3. High-Frequency Mode (No Waiting)
|
|
63
|
+
```python
|
|
64
|
+
# Send 10 payments instantly
|
|
65
|
+
for i in range(10):
|
|
66
|
+
agent.pay_agent("0x123...", 0.0001, wait=False)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## 🛠️ Configuration
|
|
70
|
+
|
|
71
|
+
To enable remote pricing updates, create a `pricing_config.json` locally or host it online:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"trial_days": 14,
|
|
76
|
+
"subscription_price_eth": 0.01
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from iagent_pay import PricingManager
|
|
82
|
+
|
|
83
|
+
pm = PricingManager(config_url="https://mysite.com/pricing.json")
|
|
84
|
+
price = pm.get_config()['subscription_price_eth']
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## 📄 License
|
|
88
|
+
MIT
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import sqlite3
|
|
3
|
+
from web3 import Web3
|
|
4
|
+
from eth_account.signers.local import LocalAccount
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from decimal import Decimal
|
|
7
|
+
from .config import ChainConfig
|
|
8
|
+
from .pricing import PricingManager
|
|
9
|
+
|
|
10
|
+
class AgentPay:
|
|
11
|
+
"""
|
|
12
|
+
The main SDK class for AI Agents to interact with the blockchain.
|
|
13
|
+
✅ Professional Grade: Includes Nonce Management, Smart Gas, and Audit Logs.
|
|
14
|
+
✅ Multi-Chain: Supports Sepolia, Base, Polygon, and Local.
|
|
15
|
+
"""
|
|
16
|
+
def __init__(self, wallet: LocalAccount, chain_name: str = "LOCAL", provider_url: Optional[str] = None):
|
|
17
|
+
self.wallet = wallet
|
|
18
|
+
self.nonce = None # Local nonce tracker
|
|
19
|
+
|
|
20
|
+
# Database for Audit Logs
|
|
21
|
+
self.db_path = "agent_history.db"
|
|
22
|
+
self._init_db()
|
|
23
|
+
|
|
24
|
+
# Multi-Chain Configuration
|
|
25
|
+
if provider_url:
|
|
26
|
+
self.w3 = Web3(Web3.HTTPProvider(provider_url))
|
|
27
|
+
else:
|
|
28
|
+
try:
|
|
29
|
+
network = ChainConfig.get_network(chain_name)
|
|
30
|
+
print(f"🌍 Connecting to {network['name']}...")
|
|
31
|
+
|
|
32
|
+
if network['rpc']:
|
|
33
|
+
self.w3 = Web3(Web3.HTTPProvider(network['rpc']))
|
|
34
|
+
else:
|
|
35
|
+
# Simulation / Local
|
|
36
|
+
from web3.providers.eth_tester import EthereumTesterProvider
|
|
37
|
+
self.w3 = Web3(EthereumTesterProvider())
|
|
38
|
+
except ValueError as e:
|
|
39
|
+
# Fallback or re-raise
|
|
40
|
+
print(str(e))
|
|
41
|
+
# Default to local if unknown
|
|
42
|
+
from web3.providers.eth_tester import EthereumTesterProvider
|
|
43
|
+
self.w3 = Web3(EthereumTesterProvider())
|
|
44
|
+
|
|
45
|
+
if not self.w3.is_connected():
|
|
46
|
+
raise ConnectionError("Failed to connect to Blockchain Provider")
|
|
47
|
+
|
|
48
|
+
def _init_db(self):
|
|
49
|
+
"""Initializes the local SQLite database for audit logs."""
|
|
50
|
+
conn = sqlite3.connect(self.db_path)
|
|
51
|
+
c = conn.cursor()
|
|
52
|
+
c.execute('''CREATE TABLE IF NOT EXISTS transactions
|
|
53
|
+
(timestamp REAL, tx_hash TEXT, recipient TEXT, amount REAL, status TEXT)''')
|
|
54
|
+
conn.commit()
|
|
55
|
+
conn.close()
|
|
56
|
+
|
|
57
|
+
def _log_transaction(self, tx_hash, recipient, amount, status="PENDING"):
|
|
58
|
+
"""Saves transaction details to the local audit log."""
|
|
59
|
+
conn = sqlite3.connect(self.db_path)
|
|
60
|
+
c = conn.cursor()
|
|
61
|
+
c.execute("INSERT INTO transactions VALUES (?, ?, ?, ?, ?)",
|
|
62
|
+
(time.time(), tx_hash, recipient, amount, status))
|
|
63
|
+
conn.commit()
|
|
64
|
+
conn.close()
|
|
65
|
+
|
|
66
|
+
def get_balance(self) -> Decimal:
|
|
67
|
+
"""Returns the balance in ETH (or native token) as a Decimal."""
|
|
68
|
+
wei_balance = self.w3.eth.get_balance(self.wallet.address)
|
|
69
|
+
return Decimal(self.w3.from_wei(wei_balance, 'ether'))
|
|
70
|
+
|
|
71
|
+
def _get_nonce(self):
|
|
72
|
+
"""
|
|
73
|
+
Reliability Engine: seamless nonce management.
|
|
74
|
+
Gets the higher value between local counter and network count
|
|
75
|
+
to prevent 'nonce too low' errors.
|
|
76
|
+
"""
|
|
77
|
+
network_nonce = self.w3.eth.get_transaction_count(self.wallet.address, 'pending')
|
|
78
|
+
if self.nonce is None or network_nonce > self.nonce:
|
|
79
|
+
self.nonce = network_nonce
|
|
80
|
+
return self.nonce
|
|
81
|
+
|
|
82
|
+
def _get_smart_gas_price(self):
|
|
83
|
+
"""
|
|
84
|
+
Smart Gas Station: Auto-calculates optimal fee.
|
|
85
|
+
Adds a 10% 'bribe' (tip) to ensure the transaction is picked up quickly.
|
|
86
|
+
"""
|
|
87
|
+
base_price = self.w3.eth.gas_price
|
|
88
|
+
# Add 10% premium for speed/reliability
|
|
89
|
+
premium_price = int(base_price * 1.10)
|
|
90
|
+
return premium_price
|
|
91
|
+
|
|
92
|
+
def pay_agent(self, recipient_address: str, amount: float, wait: bool = True) -> str:
|
|
93
|
+
"""
|
|
94
|
+
Sends a payment to another agent with robustness and logging.
|
|
95
|
+
Args:
|
|
96
|
+
wait (bool): If True, blocks until transaction is mined (safer).
|
|
97
|
+
If False, returns immediately (faster for HFT).
|
|
98
|
+
"""
|
|
99
|
+
if not self.w3.is_address(recipient_address):
|
|
100
|
+
raise ValueError(f"Invalid recipient address: {recipient_address}")
|
|
101
|
+
|
|
102
|
+
amount_wei = self.w3.to_wei(amount, 'ether')
|
|
103
|
+
|
|
104
|
+
# 1. Get Reliable Nonce
|
|
105
|
+
current_nonce = self._get_nonce()
|
|
106
|
+
|
|
107
|
+
# 2. Get Smart Gas
|
|
108
|
+
gas_price = self._get_smart_gas_price()
|
|
109
|
+
|
|
110
|
+
tx = {
|
|
111
|
+
'nonce': current_nonce,
|
|
112
|
+
'to': recipient_address,
|
|
113
|
+
'value': amount_wei,
|
|
114
|
+
'gas': 21000,
|
|
115
|
+
'gasPrice': gas_price,
|
|
116
|
+
'chainId': self.w3.eth.chain_id
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
# 3. Sign & Send
|
|
120
|
+
signed_tx = self.w3.eth.account.sign_transaction(tx, self.wallet.key)
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
tx_hash_bytes = self.w3.eth.send_raw_transaction(signed_tx.raw_transaction)
|
|
124
|
+
tx_hash = self.w3.to_hex(tx_hash_bytes)
|
|
125
|
+
|
|
126
|
+
# 4. Update Local Nonce (Increment for next tx)
|
|
127
|
+
self.nonce += 1
|
|
128
|
+
|
|
129
|
+
# 5. Audit Log
|
|
130
|
+
print(f"✅ Tx Sent: {tx_hash} (Gas: {gas_price/1e9:.2f} Gwei)")
|
|
131
|
+
self._log_transaction(tx_hash, recipient_address, amount, "SENT")
|
|
132
|
+
|
|
133
|
+
if wait:
|
|
134
|
+
print("⏳ Waiting for confirmation...")
|
|
135
|
+
self.w3.eth.wait_for_transaction_receipt(tx_hash)
|
|
136
|
+
print("✅ Confirmed!")
|
|
137
|
+
self._log_transaction(tx_hash, recipient_address, amount, "CONFIRMED")
|
|
138
|
+
|
|
139
|
+
return tx_hash
|
|
140
|
+
|
|
141
|
+
except ValueError as e:
|
|
142
|
+
# Handle "replacement transaction underpriced" specifically
|
|
143
|
+
if 'replacement transaction underpriced' in str(e):
|
|
144
|
+
print("⚠️ Transaction underpriced. Retrying with HIGHER gas...")
|
|
145
|
+
# Recursively retry with forced higher gas?
|
|
146
|
+
# For now just raising, but in v2 we'd implement the loop.
|
|
147
|
+
raise e
|
|
148
|
+
raise e
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
class ChainConfig:
|
|
2
|
+
"""
|
|
3
|
+
Pre-configured settings for major AI-friendly blockchains.
|
|
4
|
+
"""
|
|
5
|
+
LOCAL = {
|
|
6
|
+
"name": "Local Testnet",
|
|
7
|
+
"rpc": None,
|
|
8
|
+
"chain_id": 1337,
|
|
9
|
+
"symbol": "ETH"
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
SEPOLIA = {
|
|
13
|
+
"name": "Sepolia Testnet",
|
|
14
|
+
"rpc": "https://1rpc.io/sepolia",
|
|
15
|
+
"chain_id": 11155111,
|
|
16
|
+
"symbol": "SepoliaETH"
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
BASE_MAINNET = {
|
|
20
|
+
"name": "Base (Coinbase)",
|
|
21
|
+
"rpc": "https://mainnet.base.org",
|
|
22
|
+
"chain_id": 8453,
|
|
23
|
+
"symbol": "ETH"
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
POLYGON = {
|
|
27
|
+
"name": "Polygon PoS",
|
|
28
|
+
"rpc": "https://polygon-rpc.com",
|
|
29
|
+
"chain_id": 137,
|
|
30
|
+
"symbol": "MATIC"
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@staticmethod
|
|
34
|
+
def get_network(name: str):
|
|
35
|
+
"""Returns the config dict for the requested network."""
|
|
36
|
+
name = name.upper()
|
|
37
|
+
if hasattr(ChainConfig, name):
|
|
38
|
+
return getattr(ChainConfig, name)
|
|
39
|
+
raise ValueError(f"Unknown network: {name}")
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import time
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import urllib.request
|
|
5
|
+
from typing import Dict, Any
|
|
6
|
+
|
|
7
|
+
class PricingManager:
|
|
8
|
+
"""
|
|
9
|
+
Manages dynamic pricing and configuration.
|
|
10
|
+
Features:
|
|
11
|
+
- Remote Fetching: Pulls config from a URL (e.g., GitHub Gist, S3).
|
|
12
|
+
- Caching (TTL): Caches config locally for X seconds to avoid spamming the server.
|
|
13
|
+
- Auto-Refresh: If cache expires, refetches automatically on next call.
|
|
14
|
+
- Fallback: Uses default/local config if internet fails.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
DEFAULT_CONFIG = {
|
|
18
|
+
"trial_days": 14,
|
|
19
|
+
"subscription_price_eth": 0.01,
|
|
20
|
+
"pay_per_use_price_eth": 0.0001,
|
|
21
|
+
"active": True
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
def __init__(self, config_url: str = None, cache_ttl_seconds: int = 300):
|
|
25
|
+
self.config_url = config_url
|
|
26
|
+
self.cache_ttl = cache_ttl_seconds
|
|
27
|
+
self.last_updated = 0
|
|
28
|
+
self.cached_config = self.DEFAULT_CONFIG.copy()
|
|
29
|
+
|
|
30
|
+
# For testing purposes, we can override with a local file path
|
|
31
|
+
self.local_override_path = "pricing_config.json"
|
|
32
|
+
|
|
33
|
+
def get_config(self) -> Dict[str, Any]:
|
|
34
|
+
"""Returns the current configuration, refreshing if necessary."""
|
|
35
|
+
current_time = time.time()
|
|
36
|
+
|
|
37
|
+
# Check if cache is expired
|
|
38
|
+
if current_time - self.last_updated > self.cache_ttl:
|
|
39
|
+
print("🔄 Refreshing pricing config...")
|
|
40
|
+
self._refresh_config()
|
|
41
|
+
|
|
42
|
+
return self.cached_config
|
|
43
|
+
|
|
44
|
+
def _refresh_config(self):
|
|
45
|
+
"""Fetches the latest config from Remote URL or Local File."""
|
|
46
|
+
# 1. Try Local File Override (Simulating Remote for MVP)
|
|
47
|
+
if os.path.exists(self.local_override_path):
|
|
48
|
+
try:
|
|
49
|
+
with open(self.local_override_path, 'r') as f:
|
|
50
|
+
self.cached_config = json.load(f)
|
|
51
|
+
self.last_updated = time.time()
|
|
52
|
+
print("✅ Config updated from local file.")
|
|
53
|
+
return
|
|
54
|
+
except Exception as e:
|
|
55
|
+
print(f"⚠️ Failed to read local config: {e}")
|
|
56
|
+
|
|
57
|
+
# 2. Try Remote URL (if configured)
|
|
58
|
+
if self.config_url:
|
|
59
|
+
try:
|
|
60
|
+
with urllib.request.urlopen(self.config_url, timeout=5) as response:
|
|
61
|
+
data = json.loads(response.read().decode())
|
|
62
|
+
self.cached_config = data
|
|
63
|
+
self.last_updated = time.time()
|
|
64
|
+
print("✅ Config updated from Remote URL.")
|
|
65
|
+
return
|
|
66
|
+
except Exception as e:
|
|
67
|
+
print(f"⚠️ Failed to reach remote config: {e}. Using cached/default.")
|
|
68
|
+
|
|
69
|
+
# If both fail, we stick with what we have (Graceful Degradation)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import os
|
|
3
|
+
from eth_account import Account
|
|
4
|
+
from eth_account.signers.local import LocalAccount
|
|
5
|
+
from typing import Optional
|
|
6
|
+
|
|
7
|
+
# File to store the private key locally (Simulating a secure vault)
|
|
8
|
+
KEY_FILE_ENV = ".env"
|
|
9
|
+
KEY_FILE_JSON = "wallet_key.json"
|
|
10
|
+
|
|
11
|
+
class WalletManager:
|
|
12
|
+
"""
|
|
13
|
+
Manages the creation and loading of wallets for AI Agents.
|
|
14
|
+
Supports both legacy .env (text) and secure Keystore (JSON).
|
|
15
|
+
"""
|
|
16
|
+
def __init__(self):
|
|
17
|
+
# Enable unaudited HD wallet features for MVP ease of use
|
|
18
|
+
Account.enable_unaudited_hdwallet_features()
|
|
19
|
+
|
|
20
|
+
def get_or_create_wallet(self, password: Optional[str] = None) -> LocalAccount:
|
|
21
|
+
"""
|
|
22
|
+
Loads the existing wallet.
|
|
23
|
+
Prioritizes Encrypted Keystore if password is provided.
|
|
24
|
+
Falls back to .env for legacy support.
|
|
25
|
+
Creates new if nothing exists.
|
|
26
|
+
"""
|
|
27
|
+
# 1. Try to load from Strong Keystore (JSON)
|
|
28
|
+
if password and os.path.exists(KEY_FILE_JSON):
|
|
29
|
+
print("🔐 Loading from Secure Keystore...")
|
|
30
|
+
try:
|
|
31
|
+
with open(KEY_FILE_JSON, "r") as f:
|
|
32
|
+
encrypted_json = f.read()
|
|
33
|
+
return Account.from_key(Account.decrypt(encrypted_json, password))
|
|
34
|
+
except Exception as e:
|
|
35
|
+
print(f"❌ Failed to decrypt keystore: {e}")
|
|
36
|
+
# Don't fallback to .env if password was provided but failed, that's a security risk
|
|
37
|
+
raise e
|
|
38
|
+
|
|
39
|
+
# 2. Try to load from Weak File (.env)
|
|
40
|
+
if os.path.exists(KEY_FILE_ENV):
|
|
41
|
+
with open(KEY_FILE_ENV, "r") as f:
|
|
42
|
+
content = f.read().strip()
|
|
43
|
+
if content.startswith("TESTNET_PRIVATE_KEY="):
|
|
44
|
+
private_key = content.split("=")[1]
|
|
45
|
+
# print("⚠️ Loaded from INSECURE .env file. Consider migrating to Keystore.")
|
|
46
|
+
return Account.from_key(private_key)
|
|
47
|
+
|
|
48
|
+
# 3. Create new if not exists
|
|
49
|
+
print("⚠️ No existing wallet found. creating NEW one...")
|
|
50
|
+
account = Account.create()
|
|
51
|
+
|
|
52
|
+
# If password provided, save as Encrypted Keystore
|
|
53
|
+
if password:
|
|
54
|
+
self.save_keystore(account, password)
|
|
55
|
+
else:
|
|
56
|
+
# Fallback to .env
|
|
57
|
+
self.save_to_env(account)
|
|
58
|
+
|
|
59
|
+
return account
|
|
60
|
+
|
|
61
|
+
def save_keystore(self, account: LocalAccount, password: str):
|
|
62
|
+
"""Encrypts and saves the wallet to a JSON file."""
|
|
63
|
+
print("🔒 Encrypting wallet...")
|
|
64
|
+
encrypted = Account.encrypt(account.key, password)
|
|
65
|
+
with open(KEY_FILE_JSON, "w") as f:
|
|
66
|
+
json.dump(encrypted, f)
|
|
67
|
+
print(f"✅ Saved Encrypted Keystore to {KEY_FILE_JSON}")
|
|
68
|
+
|
|
69
|
+
def save_to_env(self, account: LocalAccount):
|
|
70
|
+
"""Saves raw key to .env (Legacy/Insecure)."""
|
|
71
|
+
with open(KEY_FILE_ENV, "w") as f:
|
|
72
|
+
f.write(f"TESTNET_PRIVATE_KEY={account.key.hex()}")
|
|
73
|
+
print(f"⚠️ Saved raw private key to {KEY_FILE_ENV}")
|
|
74
|
+
|
|
75
|
+
def create_wallet(self) -> LocalAccount:
|
|
76
|
+
"""Generates a brand new random wallet (Ephemeral)."""
|
|
77
|
+
account = Account.create()
|
|
78
|
+
return account
|
|
79
|
+
|
|
80
|
+
def load_wallet(self, private_key: str) -> LocalAccount:
|
|
81
|
+
"""Loads a wallet from a private key string."""
|
|
82
|
+
account = Account.from_key(private_key)
|
|
83
|
+
return account
|
|
84
|
+
|
|
85
|
+
def get_address(self, account: LocalAccount) -> str:
|
|
86
|
+
"""Returns the public address of the wallet."""
|
|
87
|
+
return account.address
|
|
88
|
+
|
|
89
|
+
if __name__ == "__main__":
|
|
90
|
+
wm = WalletManager()
|
|
91
|
+
# Test legacy load
|
|
92
|
+
try:
|
|
93
|
+
wallet = wm.get_or_create_wallet()
|
|
94
|
+
print(f"Managed Wallet Address: {wallet.address}")
|
|
95
|
+
except Exception as e:
|
|
96
|
+
print(f"Error loading wallet: {e}")
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: iagent-pay
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: The First Payment SDK for Autonomous AI Agents.
|
|
5
|
+
Home-page: https://github.com/agent-pay/sdk
|
|
6
|
+
Author: AgentPay Inc.
|
|
7
|
+
Author-email: hello@agentpay.ai
|
|
8
|
+
Classifier: Programming Language :: Python :: 3
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
13
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
14
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
15
|
+
Requires-Python: >=3.7
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: web3>=6.0.0
|
|
18
|
+
Requires-Dist: eth-account>=0.8.0
|
|
19
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
20
|
+
Dynamic: author
|
|
21
|
+
Dynamic: author-email
|
|
22
|
+
Dynamic: classifier
|
|
23
|
+
Dynamic: description
|
|
24
|
+
Dynamic: description-content-type
|
|
25
|
+
Dynamic: home-page
|
|
26
|
+
Dynamic: requires-dist
|
|
27
|
+
Dynamic: requires-python
|
|
28
|
+
Dynamic: summary
|
|
29
|
+
|
|
30
|
+
# 🤖 iAgentPay SDK v1.0
|
|
31
|
+
|
|
32
|
+
**The Standard Payment Layer for Autonomous AI Agents.**
|
|
33
|
+
|
|
34
|
+
[](https://badge.fury.io/py/iagent-pay)
|
|
35
|
+
[](https://opensource.org/licenses/MIT)
|
|
36
|
+
|
|
37
|
+
AgentPay is a Python SDK designed to allow AI Agents (AutoGPT, LangChain, BabyAGI) to send and receive micropayments securely.
|
|
38
|
+
|
|
39
|
+
## 🚀 Features
|
|
40
|
+
|
|
41
|
+
* **⚡ High-Frequency Trading:** Capable of 750+ transactions per minute.
|
|
42
|
+
* **🔐 Military-Grade Security:** Encrypted JSON Keystores (AES-128).
|
|
43
|
+
* **🔐 Military-Grade Security:** Encrypted JSON Keystores (AES-128).
|
|
44
|
+
* **🌍 Multi-Chain Support (EVM):**
|
|
45
|
+
* ✅ **Ethereum** (Mainnet & Sepolia)
|
|
46
|
+
* ✅ **Base** (Coinbase L2)
|
|
47
|
+
* ✅ **Polygon** (Low fees)
|
|
48
|
+
* ✅ **Arbitrum** & **Optimism**
|
|
49
|
+
* 🚧 *Solana (Coming Soon in v2.0)*
|
|
50
|
+
* **🛡️ Reliability Engine:** Auto-manages Nonces and Gas Fees to prevent stuck transactions.
|
|
51
|
+
* **🛡️ Reliability Engine:** Auto-manages Nonces and Gas Fees to prevent stuck transactions.
|
|
52
|
+
* **💸 Dynamic Pricing:** Update your agent's service fees remotely without code changes.
|
|
53
|
+
* **🎁 60-Day Free Trial:** Start building risk-free with our extended beta program.
|
|
54
|
+
* **📊 Audit Logs:** Built-in SQLite transaction history.
|
|
55
|
+
|
|
56
|
+
## 📦 Installation
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install iagent-pay
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## ⚡ Quick Start
|
|
63
|
+
|
|
64
|
+
### 1. Initialize Wallet
|
|
65
|
+
```python
|
|
66
|
+
from iagent_pay import WalletManager
|
|
67
|
+
|
|
68
|
+
# Create or Load Wallet (Securely)
|
|
69
|
+
wm = WalletManager()
|
|
70
|
+
wallet = wm.get_or_create_wallet(password="SuperSecurePassword")
|
|
71
|
+
print(f"My Agent Address: {wallet.address}")
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 2. Send a Payment (Sepolia)
|
|
75
|
+
```python
|
|
76
|
+
from iagent_pay import AgentPay
|
|
77
|
+
|
|
78
|
+
# Connect to Sepolia (or BASE, POLYGON, LOCAL)
|
|
79
|
+
agent = AgentPay(wallet, chain_name="SEPOLIA")
|
|
80
|
+
|
|
81
|
+
# Pay another agent 0.001 ETH
|
|
82
|
+
tx_hash = agent.pay_agent(
|
|
83
|
+
recipient_address="0x123...",
|
|
84
|
+
amount=0.001,
|
|
85
|
+
wait=True # Wait for confirmation
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
print(f"Payment Successful! Hash: {tx_hash}")
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### 3. High-Frequency Mode (No Waiting)
|
|
92
|
+
```python
|
|
93
|
+
# Send 10 payments instantly
|
|
94
|
+
for i in range(10):
|
|
95
|
+
agent.pay_agent("0x123...", 0.0001, wait=False)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 🛠️ Configuration
|
|
99
|
+
|
|
100
|
+
To enable remote pricing updates, create a `pricing_config.json` locally or host it online:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"trial_days": 14,
|
|
105
|
+
"subscription_price_eth": 0.01
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
from iagent_pay import PricingManager
|
|
111
|
+
|
|
112
|
+
pm = PricingManager(config_url="https://mysite.com/pricing.json")
|
|
113
|
+
price = pm.get_config()['subscription_price_eth']
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 📄 License
|
|
117
|
+
MIT
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
setup.py
|
|
3
|
+
iagent_pay/__init__.py
|
|
4
|
+
iagent_pay/agent_pay.py
|
|
5
|
+
iagent_pay/config.py
|
|
6
|
+
iagent_pay/pricing.py
|
|
7
|
+
iagent_pay/wallet_manager.py
|
|
8
|
+
iagent_pay.egg-info/PKG-INFO
|
|
9
|
+
iagent_pay.egg-info/SOURCES.txt
|
|
10
|
+
iagent_pay.egg-info/dependency_links.txt
|
|
11
|
+
iagent_pay.egg-info/requires.txt
|
|
12
|
+
iagent_pay.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
iagent_pay
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
from setuptools import setup, find_packages
|
|
2
|
+
|
|
3
|
+
setup(
|
|
4
|
+
name="iagent-pay",
|
|
5
|
+
version="1.0.0",
|
|
6
|
+
description="The First Payment SDK for Autonomous AI Agents.",
|
|
7
|
+
long_description=open("README.md", encoding="utf-8").read() if open("README.md") else "",
|
|
8
|
+
long_description_content_type="text/markdown",
|
|
9
|
+
author="AgentPay Inc.",
|
|
10
|
+
author_email="hello@agentpay.ai",
|
|
11
|
+
url="https://github.com/agent-pay/sdk",
|
|
12
|
+
packages=find_packages(),
|
|
13
|
+
# If we keep flat structure, we might need py_modules, but we will move to a package structure.
|
|
14
|
+
# py_modules=["iagent_pay", "wallet_manager", "config", "pricing"],
|
|
15
|
+
install_requires=[
|
|
16
|
+
"web3>=6.0.0",
|
|
17
|
+
"eth-account>=0.8.0",
|
|
18
|
+
"python-dotenv>=1.0.0"
|
|
19
|
+
],
|
|
20
|
+
classifiers=[
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"License :: OSI Approved :: MIT License",
|
|
23
|
+
"Operating System :: OS Independent",
|
|
24
|
+
"Intended Audience :: Developers",
|
|
25
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
26
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
27
|
+
"Topic :: Office/Business :: Financial",
|
|
28
|
+
],
|
|
29
|
+
python_requires='>=3.7',
|
|
30
|
+
)
|