Smart contracts
1. MersoBNPL Contract (Per Game)
Purpose: Core BNPL logic and payment management for each game
Key State Variables:
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:
// 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:
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:
contract MersoTokenPool is Ownable {
mapping(address => bool) public allowedTokens;
mapping(address => uint256) public tokenLiquidity;
}
Key Functions:
// 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:
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:
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:
// 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:
// 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();
}