# Smart contracts

#### **1. MersoBNPL Contract (Per Game)**

**Purpose**: Core BNPL logic and payment management for each game

**Key State Variables**:

```solidity
contract MersoBNPL is Ownable, ReentrancyGuard {
    MersoTokenPool public immutable MERSO_TOKEN_POOL;
    
    address[] public allowedCollections;
    mapping(address => address) public wrappedCollection;
    mapping(address => address) public originalCollectionToken;
    mapping(address => mapping(uint256 => uint256)) public tokenLastPayment;
    mapping(address => mapping(uint256 => address)) public tokenUser;
    mapping(address => mapping(uint256 => uint256)) public tokenPaymentNumber;
    mapping(address => mapping(uint256 => uint256)) public tokenSplitPayment;
}
```

**Key Functions**:

```solidity
// Add new NFT collection to the protocol
function addNewAllowedCollection(
    address originalCollection,
    string memory wCollectionName,
    string memory wCollectionSymbol,
    address gameToken
) external onlyOwner;

// Purchase NFT with BNPL (user pays 50% upfront)
function buyTokenFrom(
    address originalCollection,
    uint256 tokenId,
    uint256 tokenPrice
) external onlyAllowedCollection(originalCollection) nonReentrant;

// Process weekly payment (called by owner)
function payUserNFTPortion(
    address collection,
    uint256 tokenId
) external onlyOwner onlyRegisteredToken(collection, tokenId) nonReentrant;
```

**Payment Flow Logic**:

```solidity
function buyTokenFrom(address originalCollection, uint256 tokenId, uint256 tokenPrice) external {
    // 1. User pays 50% upfront
    uint256 amountToTransfer = (tokenPrice * 50) / 100;
    _transferTokensToPool(msg.sender, gameTokenAddress, amountToTransfer);
    
    // 2. Protocol pays 85% to game company
    uint256 amountToGame = (tokenPrice * 85) / 100;
    _buyTokenFromOriginalCollection(originalCollection, tokenId, tokenPrice);
    
    // 3. Track loan details
    tokenLastPayment[originalCollection][tokenId] = block.timestamp;
    tokenUser[originalCollection][tokenId] = msg.sender;
    tokenPaymentNumber[originalCollection][tokenId] = 0;
    tokenSplitPayment[originalCollection][tokenId] = amountToTransfer / 4;
    
    // 4. Mint wrapped NFT to user
    wrappedNFTContract.mint(msg.sender, tokenId);
}
```

#### **2. MersoTokenPool Contract (Per Chain)**

**Purpose**: Manages liquidity and payment tokens for each blockchain

**Key State Variables**:

```solidity
contract MersoTokenPool is Ownable {
    mapping(address => bool) public allowedTokens;
    mapping(address => uint256) public tokenLiquidity;
}
```

**Key Functions**:

```solidity
// Token management
function addAllowedToken(address token) external onlyOwner;
function removeAllowedToken(address token) external onlyOwner;

// Liquidity management
function transferTokensToPool(address token, uint256 amount) external onlyAllowedToken(token);
function withdrawToken(address token, uint256 amount) external onlyOwner;

// Token validation
function isAllowedToken(address token) external view returns (bool);
function getTokenLiquidity(address token) external view returns (uint256);
```

**Liquidity Management**:

```solidity
function transferTokensToPool(address token, uint256 amount) external onlyAllowedToken(token) {
    tokenLiquidity[token] += amount;
    bool success = IERC20(token).transferFrom(msg.sender, address(this), amount);
    if (!success) {
        revert TokenPool__TransferFromFailed();
    }
}
```

#### **3. WrappedNFT Contract (Per Collection)**

**Purpose**: Creates wrapped versions of original NFTs with transfer restrictions

**Key State Variables**:

```solidity
contract WrappedNFT is IERC721, IERC721Metadata, Ownable {
    address public immutable ORIGINAL_COLLECTION;
    string private _name;
    string private _symbol;
    mapping(uint256 tokenId => address) private _owners;
    mapping(address owner => uint256) private _balances;
}
```

**Key Functions**:

```solidity
// NFT wrapping (only owner can mint)
function mint(address to, uint256 tokenId) external onlyOwner;

// NFT unwrapping (only owner can burn)
function burnFrom(address from, uint256 tokenId) external onlyOwner;

// Transfer restrictions (all transfer functions revert)
function transferFrom(address from, address to, uint256 tokenId) external pure {
    revert WrappedNFT__TransferNotAllowed();
}

function approve(address to, uint256 tokenId) external pure {
    revert WrappedNFT__ApproveNotAllowed();
}
```

**Transfer Restrictions**:

```solidity
// All transfer and approval functions are disabled
function safeTransferFrom(address from, address to, uint256 tokenId) external pure {
    revert WrappedNFT__TransferNotAllowed();
}

function setApprovalForAll(address operator, bool approved) external pure {
    revert WrappedNFT__ApproveNotAllowed();
}
```
