# Payment Integration

Guide for integrating blockchain payments with NCN Network.

***

## Overview

NCN Network uses blockchain-based payments:

1. Client receives payment info after submitting request
2. Client pays to smart contract
3. Client confirms payment with gateway
4. Inference proceeds
5. Payment distributed on completion

***

## Payment Flow

```
┌──────────────────────────────────────────────────────────────────────────┐
│                          Payment Flow                                     │
│                                                                          │
│   Client                 Gateway              Blockchain                 │
│     │                       │                      │                     │
│     │ 1. Submit request     │                      │                     │
│     │──────────────────────▶│                      │                     │
│     │                       │                      │                     │
│     │ 2. Payment info       │                      │                     │
│     │◀──────────────────────│                      │                     │
│     │   (amount, contract)  │                      │                     │
│     │                       │                      │                     │
│     │ 3. Pay to contract    │                      │                     │
│     │───────────────────────────────────────────────▶│                    │
│     │                       │                      │                     │
│     │ 4. tx_hash            │                      │                     │
│     │◀──────────────────────────────────────────────│                    │
│     │                       │                      │                     │
│     │ 5. Confirm payment    │                      │                     │
│     │──────────────────────▶│                      │                     │
│     │   (tx_hash)           │                      │                     │
│     │                       │                      │                     │
│     │                       │ 6. Verify tx         │                     │
│     │                       │──────────────────────▶│                    │
│     │                       │                      │                     │
│     │ 7. Processing...      │                      │                     │
│     │◀──────────────────────│                      │                     │
│     │                       │                      │                     │
│     │ 8. Result             │                      │                     │
│     │◀──────────────────────│                      │                     │
│     │                       │                      │                     │
└──────────────────────────────────────────────────────────────────────────┘
```

***

## Prerequisites

* Web3 wallet (MetaMask, etc.) or programmatic wallet
* NCN tokens (testnet: use faucet)
* ETH for gas fees

***

## Contract Addresses

### Testnet (Forknet)

| Contract             | Address                                      |
| -------------------- | -------------------------------------------- |
| **InferencePayment** | `0x4361115359E5C0a25c9b2f8Bb71184F010b768ea` |
| **NCNToken**         | `0x38E2565e8905BeAf83C34b266592465C22A2f108` |

**Network Config:**

* RPC URL: `https://testnet-rpc-1.forknet.io`
* Chain ID: `828`

***

## Integration Steps

### 1. Submit Request & Get Payment Info

```python
import requests

# Submit inference request
response = requests.post(
    "http://localhost:8080/api/v1/inference",
    json={
        "model_uuid": "bark_semantic",
        "input_data": '{"text": "Hello"}'
    }
)

result = response.json()
request_id = result['request_id']

# Check if payment is required
if result.get('payment_required'):
    payment_info = result['payment_info']
    amount_wei = payment_info['total_amount_wei']
    contract_address = payment_info['contract_address']
    signatures = payment_info['validator_signatures']
```

### 2. Approve Token Spend

```python
from web3 import Web3

w3 = Web3(Web3.HTTPProvider('https://testnet-rpc-1.forknet.io'))

TOKEN_ADDRESS = '0x38E2565e8905BeAf83C34b266592465C22A2f108'
CONTRACT_ADDRESS = '0x4361115359E5C0a25c9b2f8Bb71184F010b768ea'

# ERC20 ABI (approve function only)
token_abi = [
    {
        "inputs": [
            {"name": "spender", "type": "address"},
            {"name": "amount", "type": "uint256"}
        ],
        "name": "approve",
        "outputs": [{"type": "bool"}],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]

token = w3.eth.contract(address=TOKEN_ADDRESS, abi=token_abi)

# Approve contract to spend tokens
tx = token.functions.approve(
    CONTRACT_ADDRESS,
    int(amount_wei)
).build_transaction({
    'from': YOUR_ADDRESS,
    'nonce': w3.eth.get_transaction_count(YOUR_ADDRESS),
    'gas': 100000,
    'gasPrice': w3.eth.gas_price
})

signed_tx = w3.eth.account.sign_transaction(tx, YOUR_PRIVATE_KEY)
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
w3.eth.wait_for_transaction_receipt(tx_hash)
```

### 3. Initiate Payment

```python
# InferencePayment ABI (initiateInferenceRequest function)
payment_abi = [
    {
        "inputs": [
            {"name": "requestId", "type": "bytes32"},
            {"name": "gateway", "type": "address"},
            {"name": "computeNode", "type": "address"},
            {"name": "computePrice", "type": "uint256"},
            {"name": "gatewayGas", "type": "uint256"},
            {"name": "validatorReward", "type": "uint256"},
            {"name": "treasuryFee", "type": "uint256"},
            {"name": "expiry", "type": "uint256"},
            {"name": "validatorSignatures", "type": "bytes[]"}
        ],
        "name": "initiateInferenceRequest",
        "outputs": [],
        "stateMutability": "nonpayable",
        "type": "function"
    }
]

payment = w3.eth.contract(address=CONTRACT_ADDRESS, abi=payment_abi)

# Convert request_id to bytes32
request_id_bytes = Web3.keccak(text=request_id)

# Build transaction
tx = payment.functions.initiateInferenceRequest(
    request_id_bytes,
    payment_info['gateway_address'],
    payment_info['compute_node_address'],
    int(payment_info['compute_price_wei']),
    int(payment_info['gateway_gas_wei']),
    int(payment_info['validator_reward_wei']),
    int(payment_info['treasury_fee_wei']),
    payment_info['expiry_timestamp'],
    [bytes.fromhex(sig[2:]) for sig in payment_info['validator_signatures']]
).build_transaction({
    'from': YOUR_ADDRESS,
    'nonce': w3.eth.get_transaction_count(YOUR_ADDRESS),
    'gas': 500000,
    'gasPrice': w3.eth.gas_price
})

signed_tx = w3.eth.account.sign_transaction(tx, YOUR_PRIVATE_KEY)
tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction)
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
```

### 4. Confirm Payment with Gateway

```python
# Confirm payment with gateway
response = requests.post(
    f"http://localhost:8080/api/v1/inference/{request_id}/confirm-payment",
    json={
        "tx_hash": tx_hash.hex(),
        "block_number": receipt['blockNumber']
    }
)

if response.status_code == 200:
    print("Payment confirmed, inference proceeding...")
```

### 5. Wait for Result

```python
import time

while True:
    response = requests.get(f"http://localhost:8080/api/v1/inference/{request_id}")
    status = response.json()
    
    if status['status'] == 'completed':
        print(f"Result: {status['output_data']}")
        break
    elif status['status'] == 'failed':
        print(f"Error: {status['error_message']}")
        break
    
    time.sleep(1)
```

***

## JavaScript Integration

### Using ethers.js

```javascript
import { ethers } from 'ethers';

const provider = new ethers.providers.JsonRpcProvider('https://testnet-rpc-1.forknet.io');
const wallet = new ethers.Wallet(PRIVATE_KEY, provider);

const TOKEN_ADDRESS = '0x38E2565e8905BeAf83C34b266592465C22A2f108';
const CONTRACT_ADDRESS = '0x4361115359E5C0a25c9b2f8Bb71184F010b768ea';

// Token ABI
const tokenABI = ['function approve(address spender, uint256 amount) returns (bool)'];
const token = new ethers.Contract(TOKEN_ADDRESS, tokenABI, wallet);

// Payment ABI
const paymentABI = [
  'function initiateInferenceRequest(bytes32 requestId, address gateway, address computeNode, uint256 computePrice, uint256 gatewayGas, uint256 validatorReward, uint256 treasuryFee, uint256 expiry, bytes[] validatorSignatures)'
];
const payment = new ethers.Contract(CONTRACT_ADDRESS, paymentABI, wallet);

async function payForInference(paymentInfo) {
  // 1. Approve tokens
  const approveTx = await token.approve(
    CONTRACT_ADDRESS,
    paymentInfo.total_amount_wei
  );
  await approveTx.wait();
  
  // 2. Initiate payment
  const requestIdBytes = ethers.utils.id(paymentInfo.request_id);
  
  const payTx = await payment.initiateInferenceRequest(
    requestIdBytes,
    paymentInfo.gateway_address,
    paymentInfo.compute_node_address,
    paymentInfo.compute_price_wei,
    paymentInfo.gateway_gas_wei,
    paymentInfo.validator_reward_wei,
    paymentInfo.treasury_fee_wei,
    paymentInfo.expiry_timestamp,
    paymentInfo.validator_signatures
  );
  
  const receipt = await payTx.wait();
  return receipt.transactionHash;
}
```

***

## Complete Example

### Python with Full Payment Flow

```python
#!/usr/bin/env python3
import requests
import time
from web3 import Web3

class NCNPaymentClient:
    def __init__(self, gateway_url, rpc_url, private_key):
        self.gateway_url = gateway_url
        self.w3 = Web3(Web3.HTTPProvider(rpc_url))
        self.account = self.w3.eth.account.from_key(private_key)
        
        self.TOKEN_ADDRESS = '0x38E2565e8905BeAf83C34b266592465C22A2f108'
        self.CONTRACT_ADDRESS = '0x4361115359E5C0a25c9b2f8Bb71184F010b768ea'
        
        # Load ABIs
        self.token = self.w3.eth.contract(
            address=self.TOKEN_ADDRESS,
            abi=self._token_abi()
        )
        self.payment = self.w3.eth.contract(
            address=self.CONTRACT_ADDRESS,
            abi=self._payment_abi()
        )
    
    def inference(self, model_uuid, input_data, timeout=120):
        """Submit inference with payment."""
        # 1. Submit request
        response = requests.post(
            f"{self.gateway_url}/api/v1/inference",
            json={
                "model_uuid": model_uuid,
                "input_data": input_data
            }
        )
        result = response.json()
        request_id = result['request_id']
        
        # 2. Handle payment if required
        if result.get('payment_required'):
            payment_info = result['payment_info']
            
            # Approve tokens
            self._approve_tokens(payment_info['total_amount_wei'])
            
            # Pay
            tx_hash = self._initiate_payment(request_id, payment_info)
            
            # Confirm with gateway
            requests.post(
                f"{self.gateway_url}/api/v1/inference/{request_id}/confirm-payment",
                json={"tx_hash": tx_hash}
            )
        
        # 3. Wait for result
        return self._wait_for_result(request_id, timeout)
    
    def _approve_tokens(self, amount):
        tx = self.token.functions.approve(
            self.CONTRACT_ADDRESS,
            int(amount)
        ).build_transaction({
            'from': self.account.address,
            'nonce': self.w3.eth.get_transaction_count(self.account.address),
            'gas': 100000,
            'gasPrice': self.w3.eth.gas_price
        })
        signed = self.account.sign_transaction(tx)
        tx_hash = self.w3.eth.send_raw_transaction(signed.rawTransaction)
        self.w3.eth.wait_for_transaction_receipt(tx_hash)
    
    def _initiate_payment(self, request_id, payment_info):
        request_id_bytes = Web3.keccak(text=request_id)
        
        tx = self.payment.functions.initiateInferenceRequest(
            request_id_bytes,
            payment_info['gateway_address'],
            payment_info['compute_node_address'],
            int(payment_info['compute_price_wei']),
            int(payment_info['gateway_gas_wei']),
            int(payment_info['validator_reward_wei']),
            int(payment_info['treasury_fee_wei']),
            payment_info['expiry_timestamp'],
            [bytes.fromhex(sig[2:]) for sig in payment_info['validator_signatures']]
        ).build_transaction({
            'from': self.account.address,
            'nonce': self.w3.eth.get_transaction_count(self.account.address),
            'gas': 500000,
            'gasPrice': self.w3.eth.gas_price
        })
        
        signed = self.account.sign_transaction(tx)
        tx_hash = self.w3.eth.send_raw_transaction(signed.rawTransaction)
        self.w3.eth.wait_for_transaction_receipt(tx_hash)
        return tx_hash.hex()
    
    def _wait_for_result(self, request_id, timeout):
        start_time = time.time()
        while time.time() - start_time < timeout:
            response = requests.get(
                f"{self.gateway_url}/api/v1/inference/{request_id}"
            )
            status = response.json()
            
            if status['status'] == 'completed':
                return status['output_data']
            elif status['status'] == 'failed':
                raise Exception(status.get('error_message', 'Unknown error'))
            
            time.sleep(1)
        
        raise TimeoutError(f"Request {request_id} timed out")
    
    def _token_abi(self):
        return [{"inputs":[{"name":"spender","type":"address"},{"name":"amount","type":"uint256"}],"name":"approve","outputs":[{"type":"bool"}],"stateMutability":"nonpayable","type":"function"}]
    
    def _payment_abi(self):
        return [{"inputs":[{"name":"requestId","type":"bytes32"},{"name":"gateway","type":"address"},{"name":"computeNode","type":"address"},{"name":"computePrice","type":"uint256"},{"name":"gatewayGas","type":"uint256"},{"name":"validatorReward","type":"uint256"},{"name":"treasuryFee","type":"uint256"},{"name":"expiry","type":"uint256"},{"name":"validatorSignatures","type":"bytes[]"}],"name":"initiateInferenceRequest","outputs":[],"stateMutability":"nonpayable","type":"function"}]

# Usage
if __name__ == "__main__":
    client = NCNPaymentClient(
        gateway_url="http://localhost:8080",
        rpc_url="https://testnet-rpc-1.forknet.io",
        private_key="0x..."
    )
    
    result = client.inference(
        model_uuid="bark_semantic",
        input_data='{"text": "Hello, world!"}'
    )
    print(f"Result: {result}")
```

***

## Testnet Faucet

Get testnet NCN tokens:

```bash
# Check faucet availability
curl https://faucet.testnet.ncn-network.io/api/status

# Request tokens
curl -X POST https://faucet.testnet.ncn-network.io/api/faucet \
  -H "Content-Type: application/json" \
  -d '{"address": "0xYOUR_ADDRESS"}'
```

***

## Next Steps

* [gRPC Client](https://docs.neurochain.ai/nc/neurochainai-guides/clients/grpc-client) - gRPC integration
* [HTTP Client](https://docs.neurochain.ai/nc/neurochainai-guides/clients/http-client) - HTTP integration
* [Examples](https://docs.neurochain.ai/nc/neurochainai-guides/clients/examples) - More code examples
