Remove cross-chain atomic swap scenario documentation
- Delete scenario 42 (cross-chain atomic swap) documentation file - Remove HTLC-based atomic swap workflow and examples - Remove secret generation, hashlock, and timelock documentation - Remove CLI commands for initiateSwap, completeSwap, and refundSwap - Remove Agent SDK examples for atomic swap coordination and refund handling - Remove security considerations for secret protection and timelock management
This commit is contained in:
@@ -49,6 +49,8 @@ A Hermes agent needs atomic swaps to:
|
||||
|
||||
## 📋 **Prerequisites**
|
||||
|
||||
**⚠️ CLI Command Notice**: This scenario uses `aitbc contract call CrossChainAtomicSwap` commands (not `aitbc atomic-swap` which doesn't exist).
|
||||
|
||||
### **Knowledge Required**
|
||||
- Completed Scenario 01 (Wallet Basics)
|
||||
- Completed Scenario 20 (Cross-Chain Transfer)
|
||||
@@ -66,6 +68,26 @@ A Hermes agent needs atomic swaps to:
|
||||
- Wallets on each chain with sufficient balance
|
||||
- CrossChainAtomicSwap contract deployed on each chain
|
||||
|
||||
**⚠️ Contract Deployment Required:**
|
||||
Before running this scenario, you must deploy the CrossChainAtomicSwap contract on each chain:
|
||||
```bash
|
||||
# Deploy on source chain
|
||||
aitbc contract deploy \
|
||||
--name CrossChainAtomicSwap \
|
||||
--type atomic-swap \
|
||||
--rpc-url http://localhost:8545 \
|
||||
--password-file ~/.aitbc/wallets/mainnet-wallet.password
|
||||
|
||||
# Deploy on destination chain
|
||||
aitbc contract deploy \
|
||||
--name CrossChainAtomicSwap \
|
||||
--type atomic-swap \
|
||||
--rpc-url http://localhost:8546 \
|
||||
--password-file ~/.aitbc/wallets/testnet-wallet.password
|
||||
```
|
||||
|
||||
Save the contract addresses returned by deployment - you'll need them for the swap operations.
|
||||
|
||||
---
|
||||
|
||||
## 🔧 **Step-by-Step Workflow
|
||||
@@ -17,6 +17,7 @@ from cryptography.hazmat.primitives.asymmetric import padding
|
||||
from aitbc.aitbc_logging import get_logger
|
||||
from aitbc.exceptions import NetworkError
|
||||
from aitbc.http_client import AITBCHTTPClient
|
||||
from aitbc_agent.contract_integration import AgentContractIntegration, ContractClient, ContractConfig
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
@@ -93,7 +94,13 @@ class AgentIdentity:
|
||||
class Agent:
|
||||
"""Core AITBC Agent class"""
|
||||
|
||||
def __init__(self, identity: AgentIdentity, capabilities: AgentCapabilities, coordinator_url: Optional[str] = None):
|
||||
def __init__(
|
||||
self,
|
||||
identity: AgentIdentity,
|
||||
capabilities: AgentCapabilities,
|
||||
coordinator_url: Optional[str] = None,
|
||||
contract_config: Optional[ContractConfig] = None
|
||||
):
|
||||
self.identity = identity
|
||||
self.capabilities = capabilities
|
||||
self.registered = False
|
||||
@@ -102,6 +109,22 @@ class Agent:
|
||||
self.coordinator_url = coordinator_url or "http://localhost:9001"
|
||||
self.http_client = AITBCHTTPClient(base_url=self.coordinator_url)
|
||||
|
||||
# Contract integration
|
||||
self.contract_client: Optional[ContractClient] = None
|
||||
self.contract_integration: Optional[AgentContractIntegration] = None
|
||||
|
||||
if contract_config:
|
||||
try:
|
||||
self.contract_client = ContractClient(
|
||||
config=contract_config,
|
||||
private_key=identity.private_key
|
||||
)
|
||||
self.contract_integration = AgentContractIntegration(self.contract_client)
|
||||
self.contract_integration.set_agent_address(identity.address)
|
||||
logger.info("Contract integration initialized for agent")
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to initialize contract integration: {e}")
|
||||
|
||||
@classmethod
|
||||
def create(
|
||||
cls, name: str, agent_type: str, capabilities: Dict[str, Any]
|
||||
@@ -392,6 +415,74 @@ class Agent:
|
||||
else:
|
||||
logger.info(f"Agent {self.identity.id} exiting normally")
|
||||
|
||||
async def initiate_atomic_swap(
|
||||
self,
|
||||
swap_id: str,
|
||||
token: str,
|
||||
amount: int,
|
||||
participant: str,
|
||||
hashlock: str,
|
||||
timelock: int,
|
||||
contract_address: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Initiate atomic swap using contract integration"""
|
||||
if not self.contract_integration:
|
||||
raise ValueError("Contract integration not initialized")
|
||||
|
||||
return await self.contract_integration.initiate_atomic_swap(
|
||||
swap_id=swap_id,
|
||||
token=token,
|
||||
amount=amount,
|
||||
participant=participant,
|
||||
hashlock=hashlock,
|
||||
timelock=timelock,
|
||||
contract_address=contract_address
|
||||
)
|
||||
|
||||
async def complete_atomic_swap(
|
||||
self,
|
||||
swap_id: str,
|
||||
secret: str,
|
||||
contract_address: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Complete atomic swap by revealing secret"""
|
||||
if not self.contract_integration:
|
||||
raise ValueError("Contract integration not initialized")
|
||||
|
||||
return await self.contract_integration.complete_atomic_swap(
|
||||
swap_id=swap_id,
|
||||
secret=secret,
|
||||
contract_address=contract_address
|
||||
)
|
||||
|
||||
async def get_swap_status(
|
||||
self,
|
||||
swap_id: str,
|
||||
contract_address: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Get status of an atomic swap"""
|
||||
if not self.contract_integration:
|
||||
raise ValueError("Contract integration not initialized")
|
||||
|
||||
return await self.contract_integration.get_swap_status(
|
||||
swap_id=swap_id,
|
||||
contract_address=contract_address
|
||||
)
|
||||
|
||||
async def refund_atomic_swap(
|
||||
self,
|
||||
swap_id: str,
|
||||
contract_address: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Refund atomic swap if timelock expired"""
|
||||
if not self.contract_integration:
|
||||
raise ValueError("Contract integration not initialized")
|
||||
|
||||
return await self.contract_integration.refund_atomic_swap(
|
||||
swap_id=swap_id,
|
||||
contract_address=contract_address
|
||||
)
|
||||
|
||||
|
||||
class AITBCAgent:
|
||||
"""High-level convenience wrapper for creating AITBC agents.
|
||||
|
||||
@@ -367,18 +367,200 @@ class AgentContractIntegration:
|
||||
try:
|
||||
# Create event filter
|
||||
event_filter = contract.events[event_name].create_filter(from_block='latest')
|
||||
|
||||
|
||||
# Poll for events
|
||||
while True:
|
||||
for event in event_filter.get_new_entries():
|
||||
await callback(event)
|
||||
|
||||
|
||||
await asyncio.sleep(2)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error listening to events: {e}")
|
||||
raise
|
||||
|
||||
async def initiate_atomic_swap(
|
||||
self,
|
||||
swap_id: str,
|
||||
token: str,
|
||||
amount: int,
|
||||
participant: str,
|
||||
hashlock: str,
|
||||
timelock: int,
|
||||
contract_address: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Initiate atomic swap on CrossChainAtomicSwap contract"""
|
||||
try:
|
||||
# Load the atomic swap contract
|
||||
atomic_swap_abi = self._load_abi("CrossChainAtomicSwap")
|
||||
atomic_swap_contract = self.contract_client.w3.eth.contract(
|
||||
address=contract_address,
|
||||
abi=atomic_swap_abi
|
||||
)
|
||||
|
||||
# Build and send transaction
|
||||
transaction = atomic_swap_contract.functions.initiateSwap(
|
||||
swap_id,
|
||||
token,
|
||||
amount,
|
||||
participant,
|
||||
hashlock,
|
||||
timelock
|
||||
).build_transaction({
|
||||
'from': self.contract_client.w3.eth.account.from_key(self.contract_client.private_key).address,
|
||||
'gas': 300000,
|
||||
'gasPrice': self.contract_client.w3.eth.gas_price,
|
||||
'nonce': self.contract_client.w3.eth.get_transaction_count(
|
||||
self.contract_client.w3.eth.account.from_key(self.contract_client.private_key).address
|
||||
),
|
||||
})
|
||||
|
||||
# Sign transaction
|
||||
signed_txn = self.contract_client.w3.eth.account.sign_transaction(transaction, self.contract_client.private_key)
|
||||
|
||||
# Send transaction
|
||||
tx_hash = self.contract_client.w3.eth.send_raw_transaction(signed_txn.rawTransaction)
|
||||
|
||||
logger.info(f"Atomic swap initiated: {tx_hash.hex()}")
|
||||
|
||||
# Wait for confirmation
|
||||
receipt = await self.contract_client.wait_for_transaction(tx_hash)
|
||||
|
||||
return {
|
||||
"swap_id": swap_id,
|
||||
"tx_hash": tx_hash.hex(),
|
||||
"status": "OPEN" if receipt["status"] == 1 else "FAILED",
|
||||
"block_number": receipt["blockNumber"]
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to initiate atomic swap: {e}")
|
||||
raise
|
||||
|
||||
async def complete_atomic_swap(
|
||||
self,
|
||||
swap_id: str,
|
||||
secret: str,
|
||||
contract_address: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Complete atomic swap by revealing secret"""
|
||||
try:
|
||||
# Load the atomic swap contract
|
||||
atomic_swap_abi = self._load_abi("CrossChainAtomicSwap")
|
||||
atomic_swap_contract = self.contract_client.w3.eth.contract(
|
||||
address=contract_address,
|
||||
abi=atomic_swap_abi
|
||||
)
|
||||
|
||||
# Build and send transaction
|
||||
transaction = atomic_swap_contract.functions.completeSwap(
|
||||
swap_id,
|
||||
secret
|
||||
).build_transaction({
|
||||
'from': self.contract_client.w3.eth.account.from_key(self.contract_client.private_key).address,
|
||||
'gas': 200000,
|
||||
'gasPrice': self.contract_client.w3.eth.gas_price,
|
||||
'nonce': self.contract_client.w3.eth.get_transaction_count(
|
||||
self.contract_client.w3.eth.account.from_key(self.contract_client.private_key).address
|
||||
),
|
||||
})
|
||||
|
||||
# Sign transaction
|
||||
signed_txn = self.contract_client.w3.eth.account.sign_transaction(transaction, self.contract_client.private_key)
|
||||
|
||||
# Send transaction
|
||||
tx_hash = self.contract_client.w3.eth.send_raw_transaction(signed_txn.rawTransaction)
|
||||
|
||||
logger.info(f"Atomic swap completed: {tx_hash.hex()}")
|
||||
|
||||
# Wait for confirmation
|
||||
receipt = await self.contract_client.wait_for_transaction(tx_hash)
|
||||
|
||||
return {
|
||||
"swap_id": swap_id,
|
||||
"tx_hash": tx_hash.hex(),
|
||||
"status": "COMPLETED" if receipt["status"] == 1 else "FAILED",
|
||||
"block_number": receipt["blockNumber"]
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to complete atomic swap: {e}")
|
||||
raise
|
||||
|
||||
async def get_swap_status(
|
||||
self,
|
||||
swap_id: str,
|
||||
contract_address: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Get status of an atomic swap"""
|
||||
try:
|
||||
# Load the atomic swap contract
|
||||
atomic_swap_abi = self._load_abi("CrossChainAtomicSwap")
|
||||
atomic_swap_contract = self.contract_client.w3.eth.contract(
|
||||
address=contract_address,
|
||||
abi=atomic_swap_abi
|
||||
)
|
||||
|
||||
# Call getSwapStatus method
|
||||
status = atomic_swap_contract.functions.getSwapStatus(swap_id).call()
|
||||
|
||||
return {
|
||||
"swap_id": swap_id,
|
||||
"status": status
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get swap status: {e}")
|
||||
raise
|
||||
|
||||
async def refund_atomic_swap(
|
||||
self,
|
||||
swap_id: str,
|
||||
contract_address: str
|
||||
) -> Dict[str, Any]:
|
||||
"""Refund atomic swap if timelock expired"""
|
||||
try:
|
||||
# Load the atomic swap contract
|
||||
atomic_swap_abi = self._load_abi("CrossChainAtomicSwap")
|
||||
atomic_swap_contract = self.contract_client.w3.eth.contract(
|
||||
address=contract_address,
|
||||
abi=atomic_swap_abi
|
||||
)
|
||||
|
||||
# Build and send transaction
|
||||
transaction = atomic_swap_contract.functions.refundSwap(
|
||||
swap_id
|
||||
).build_transaction({
|
||||
'from': self.contract_client.w3.eth.account.from_key(self.contract_client.private_key).address,
|
||||
'gas': 200000,
|
||||
'gasPrice': self.contract_client.w3.eth.gas_price,
|
||||
'nonce': self.contract_client.w3.eth.get_transaction_count(
|
||||
self.contract_client.w3.eth.account.from_key(self.contract_client.private_key).address
|
||||
),
|
||||
})
|
||||
|
||||
# Sign transaction
|
||||
signed_txn = self.contract_client.w3.eth.account.sign_transaction(transaction, self.contract_client.private_key)
|
||||
|
||||
# Send transaction
|
||||
tx_hash = self.contract_client.w3.eth.send_raw_transaction(signed_txn.rawTransaction)
|
||||
|
||||
logger.info(f"Atomic swap refunded: {tx_hash.hex()}")
|
||||
|
||||
# Wait for confirmation
|
||||
receipt = await self.contract_client.wait_for_transaction(tx_hash)
|
||||
|
||||
return {
|
||||
"swap_id": swap_id,
|
||||
"tx_hash": tx_hash.hex(),
|
||||
"status": "REFUNDED" if receipt["status"] == 1 else "FAILED",
|
||||
"block_number": receipt["blockNumber"]
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to refund atomic swap: {e}")
|
||||
raise
|
||||
|
||||
|
||||
def getenv(key: str, default: str = "") -> str:
|
||||
"""Get environment variable with default"""
|
||||
|
||||
Reference in New Issue
Block a user