# Technical Architecture

Deep dive into MakaPay's smart contract architecture, deterministic addresses, and cross-chain capabilities.

***

## Smart Contract Overview

MakaPay uses a minimal proxy pattern with CREATE2 for gas-efficient, deterministic payment addresses.

```
┌─────────────────────────────────────────────────────────────┐
│                    MakaChain (Hub)                          │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────┐  │
│  │  GasTank    │  │PaymentNotifier│ │ TrustedOracle       │  │
│  │  (Balances) │  │  (Events)    │  │ (Price Feeds)       │  │
│  └─────────────┘  └─────────────┘  └─────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│              Payment Chains (Ethereum, Polygon, BSC)        │
│  ┌─────────────────────────┐  ┌───────────────────────────┐ │
│  │ PaymentWalletFactory    │  │ PaymentWalletImplementation│ │
│  │ (Deploys wallets)       │  │ (Template contract)        │ │
│  └─────────────────────────┘  └───────────────────────────┘ │
│                                                             │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐            │
│  │PaymentWallet│ │PaymentWallet│ │PaymentWallet│  ...       │
│  │  (Proxy 1)  │ │  (Proxy 2)  │ │  (Proxy N)  │            │
│  └─────────────┘ └─────────────┘ └─────────────┘            │
└─────────────────────────────────────────────────────────────┘
```

***

## PaymentWalletFactory

The Factory contract deploys payment wallets using the CREATE2 opcode for deterministic addresses.

### Key Functions

#### `computeAddress()`

Pre-computes the payment wallet address before deployment.

```solidity
function computeAddress(
    string calldata orderId,
    address merchant,
    address token,
    address feeRecipient,
    uint256 feeAmount
) external view returns (address)
```

**Parameters**:

* `orderId`: Unique payment identifier
* `merchant`: Address to receive funds
* `token`: ERC20 token contract address
* `feeRecipient`: Address receiving protocol fees
* `feeAmount`: Fee amount to deduct

**Returns**: The deterministic address where the wallet will be deployed.

#### `createPaymentWallet()`

Deploys a payment wallet at the pre-computed address.

```solidity
function createPaymentWallet(
    string calldata orderId,
    address merchant,
    address token,
    uint256 amount,
    address feeRecipient,
    uint256 feeAmount,
    uint256 minAmount
) external returns (address wallet)
```

**What happens**:

1. Computes salt from all parameters
2. Deploys minimal proxy via CREATE2
3. Initializes the proxy with payment details
4. Automatically calls `withdraw()` to settle funds

### Address Computation (CREATE2)

The wallet address is computed as:

```
address = keccak256(
    0xff,
    factory_address,
    salt,
    keccak256(proxy_bytecode)
)
```

Where `salt` is:

```solidity
bytes32 salt = keccak256(abi.encodePacked(
    orderId,
    merchant,
    token,
    feeRecipient,
    feeAmount
));
```

***

## PaymentWalletImplementation

The implementation contract contains the logic that all payment wallet proxies delegate to.

### Storage Variables

```solidity
address public merchant;      // Receives payment
address public token;         // ERC20 token
uint256 public amount;        // Expected amount
string public orderId;        // Payment reference
address public feeRecipient;  // Receives fees
uint256 public feeAmount;     // Fee to deduct
uint256 public minAmount;     // Minimum for auto-settle
bool public initialized;      // Prevent re-init
```

### Key Functions

#### `initialize()`

Called once when the proxy is deployed.

```solidity
function initialize(
    string calldata _orderId,
    address _merchant,
    address _token,
    uint256 _amount,
    address _feeRecipient,
    uint256 _feeAmount,
    uint256 _minAmount
) external
```

#### `withdraw()`

Settles funds to the merchant.

```solidity
function withdraw(address _token) external nonReentrant
```

**Logic**:

1. Get token balance of wallet
2. Calculate fee (proportional if partial payment)
3. Transfer fee to `feeRecipient`
4. Transfer remainder to `merchant`
5. Call merchant's `onPaymentReceived()` callback (if contract)

```solidity
// Proportional fee calculation for partial payments
uint256 actualFee = (balance * feeAmount) / amount;

// Transfer fee
IERC20(token).safeTransfer(feeRecipient, actualFee);

// Transfer to merchant
IERC20(token).safeTransfer(merchant, balance - actualFee);
```

***

## EIP-1167 Minimal Proxy Pattern

Instead of deploying full contract bytecode for each payment, we use minimal proxies.

### Benefits

| Aspect         | Full Contract | Minimal Proxy               |
| -------------- | ------------- | --------------------------- |
| Deployment Gas | \~500,000     | \~50,000                    |
| Bytecode Size  | \~5KB         | \~45 bytes                  |
| Functionality  | Full          | Delegates to implementation |

### How It Works

The minimal proxy is just 45 bytes:

```
363d3d373d3d3d363d73<implementation_address>5af43d82803e903d91602b57fd5bf3
```

All calls to the proxy are delegated to the implementation contract.

***

## Nick's Method & Cross-Chain Recovery

### What is Nick's Method?

Nick's Method (named after Nick Johnson) uses CREATE2 to deploy contracts at the same address across different blockchains.

### Why It Matters for MakaPay

**Problem**: A customer sends USDT on Polygon to an address, but the merchant expected payment on Ethereum.

**Traditional Approach**: Funds are lost. The address on Ethereum is either:

* Empty (no contract)
* A different contract
* Inaccessible

**MakaPay Approach**: Because we use CREATE2 with identical parameters:

1. The address is **the same** on all chains
2. We can deploy the **same wallet** on any chain
3. Funds can be **recovered** by deploying on the correct chain

### How Cross-Chain Recovery Works

```
Scenario: Customer sends USDT to Polygon address,
          but payment was created for Ethereum

1. Payment created for Ethereum
   └── Address computed: 0xABC123...

2. Customer mistakenly sends on Polygon
   └── Funds arrive at: 0xABC123... (same address!)

3. Recovery process:
   a. MakaPay detects funds on wrong chain
   b. Deploys PaymentWallet on Polygon at 0xABC123...
   c. Wallet withdraws funds to merchant
   d. Small recovery fee applied

Result: Funds recovered instead of lost!
```

### Technical Requirements for Same Address

For the address to be identical across chains:

1. **Same Factory Address**: Factory must be at same address on all chains
2. **Same Implementation**: Implementation bytecode must be identical
3. **Same Parameters**: orderId, merchant, token address\*, feeRecipient, feeAmount

\*Token addresses may differ across chains, but the computation uses the original chain's token address.

### Deploying Factory at Same Address

We use a keyless deployment transaction (Nick's original method):

```javascript
// Pre-signed transaction with known sender
const deploymentTx = {
  nonce: 0,
  gasPrice: 100 gwei,
  gasLimit: 500000,
  data: factoryBytecode,
  v: 27,
  r: "0x...",  // Pre-computed
  s: "0x...",  // Pre-computed
};

// This tx can be broadcast on any EVM chain
// Factory deploys at the exact same address every time
```

***

## Payment Flow (On-Chain)

### Step 1: Address Computation

```javascript
// Off-chain (frontend/API)
const address = await factory.computeAddress(
  paymentId,
  merchantAddress,
  tokenAddress,
  feeRecipient,
  feeAmount
);

// Address exists before any deployment!
// Customer can send funds here
```

### Step 2: Customer Payment

```
Customer → sends 100 USDT → 0xABC123... (computed address)

At this point:
- Address has 100 USDT balance
- No contract is deployed yet
- MakaPay monitors for incoming transfers
```

### Step 3: Settlement

```javascript
// On-chain (MakaPay operator)
const wallet = await factory.createPaymentWallet(
  paymentId,
  merchantAddress,
  tokenAddress,
  amount,
  feeRecipient,
  feeAmount,
  minAmount
);

// This:
// 1. Deploys proxy at 0xABC123...
// 2. Initializes with payment params
// 3. Calls withdraw() automatically
// 4. Merchant receives funds
```

### Step 4: Callback (Optional)

If merchant is a contract implementing `IPaymentReceiver`:

```solidity
interface IPaymentReceiver {
    function onPaymentReceived(
        string calldata orderId,
        address token,
        uint256 amountReceived,
        uint256 originalAmount,
        bool isPaymentComplete
    ) external;
}
```

The wallet calls this after settlement, enabling:

* Automatic order fulfillment
* Inventory updates
* Event logging

***

## PaymentNotifier (Gasless Settlements)

For gasless payments, the PaymentNotifier records settlements on MakaChain.

### Purpose

* Single source of truth for all settlements
* Emits events for off-chain indexing
* Collects processing fee ($0.10)

### Contract Interface

```solidity
function recordPayment(
    uint256 paymentChainId,
    bytes32 txHash
) external onlyOperator
```

### Event

```solidity
event PaymentRecorded(
    uint256 indexed paymentChainId,
    bytes32 indexed txHash,
    uint256 fee
);
```

***

## Security Measures

### Reentrancy Protection

All fund-moving functions use `nonReentrant` modifier:

```solidity
function withdraw(address _token) external nonReentrant {
    // Safe from reentrancy attacks
}
```

### SafeERC20

All token transfers use OpenZeppelin's SafeERC20:

```solidity
using SafeERC20 for IERC20;

// Handles non-standard tokens (like USDT) safely
IERC20(token).safeTransfer(recipient, amount);
```

### One-Time Initialization

Proxies can only be initialized once:

```solidity
function initialize(...) external {
    require(!initialized, "Already initialized");
    initialized = true;
    // ... set state
}
```

### Nonce Validation (Gas Tank)

Deposits use nonces to prevent replay attacks:

```solidity
mapping(string => uint256) public depositNonces;

function onPaymentReceived(...) external {
    uint256 expectedNonce = depositNonces[userId];
    require(nonce == expectedNonce, "Invalid nonce");
    depositNonces[userId] = expectedNonce + 1;
}
```

***

## Contract Addresses

### MakaChain Mainnet (777178)

| Contract        | Address                                      |
| --------------- | -------------------------------------------- |
| GasTank         | `0xE94EB77a80BddD3a1c1813ed17894af0a3837d2C` |
| PaymentNotifier | `0xb539C4B4D0442836261646dc2D852E31FC662DCC` |
| TrustedOracle   | `0x0ba6da3BF82719e5628d1cdb896Ef4ff62e2296f` |
| USDT            | `0x30C28E393E0732335235685B345c95E6465Ad8A5` |

### Payment Chains

| Chain     | Factory                                      | Implementation                               |
| --------- | -------------------------------------------- | -------------------------------------------- |
| Ethereum  | `0xCB45Df5057b9a287F9b95Af7ccdC49A1C9F2fcfA` | `0x0e77A0A5845C49EbC8EEA521024b5a04F7B0E20B` |
| Polygon   | `0xCB45Df5057b9a287F9b95Af7ccdC49A1C9F2fcfA` | `0x0e77A0A5845C49EbC8EEA521024b5a04F7B0E20B` |
| BSC       | `0xCB45Df5057b9a287F9b95Af7ccdC49A1C9F2fcfA` | `0x0e77A0A5845C49EbC8EEA521024b5a04F7B0E20B` |
| MakaChain | `0xCB45Df5057b9a287F9b95Af7ccdC49A1C9F2fcfA` | `0x0e77A0A5845C49EbC8EEA521024b5a04F7B0E20B` |

*Addresses are identical across all chains due to Nick's Method deployment.*

***

## Upgradeability

### Factory & Implementation

* **Not upgradeable** by design
* New versions deploy as new contracts
* Existing payments continue to work
* Ensures immutability and trust

### GasTank

* Upgradeable by owner
* Emergency functions for edge cases
* Multi-sig control recommended


---

# 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.makapay.io/developers/technical-architecture.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.
