# 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](/nc/neurochainai-guides/clients/grpc-client.md) - gRPC integration
* [HTTP Client](/nc/neurochainai-guides/clients/http-client.md) - HTTP integration
* [Examples](/nc/neurochainai-guides/clients/examples.md) - More code examples


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.neurochain.ai/nc/neurochainai-guides/clients/payment-integration.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
