Skip to content

add permissionless lending features #634

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions academy/lending-protocol/contracts/GlobalLedger.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.28;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@nilfoundation/smart-contracts/contracts/Nil.sol";
import "@nilfoundation/smart-contracts/contracts/NilTokenBase.sol";

// Axelar Gateway Interface for cross-chain communication
interface IAxelarGateway {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think axelar gateway is something that works over here. As we support our own inter shard communication system. I would prefer you to go through our docs of cross shard communication: here

You would have to deploy a lending pool using the asyncDeploy and then call a registration function.

function callContract(
string calldata destinationChain,
string calldata destinationAddress,
bytes calldata payload
) external;
}

/// @title GlobalLedger - Cross-chain ledger for lending pools
contract GlobalLedger is Ownable {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we already have the GlobalLedger inside CollateralManager.sol why did you want to write an amended contract? I would advise you to use the GlobalLedger inside CollateralManager.sol as it has a lot of functionality that would support backward compatiblity. So only thing you would have to change in GlobalLedger inside CollateralManager.sol would be add factory based role access to it, as your code for factory based role access looks good.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @gitshreevatsa, thanks for the update. I have made some changes on the code incuding removing Globalledger.sol to avoid duplicate and others.

mapping(address => bool) public registeredPools;
address public factory;
mapping(address => uint256) public userDeposits;
mapping(address => uint256) public userLoans;

event PoolRegistered(address indexed pool);
event DepositRecorded(address indexed user, uint256 amount);
event LoanRecorded(address indexed user, uint256 amount);

modifier onlyFactory() {
require(msg.sender == factory, "Not authorized");
_;
}

constructor(address _owner) Ownable(_owner) {}

function setFactory(address _factory) external onlyOwner {
require(factory == address(0), "Factory already set");
factory = _factory;
}

function registerLendingPool(address pool) external onlyFactory {
registeredPools[pool] = true;
emit PoolRegistered(pool);
}

function _execute(bytes calldata payload) internal {
(address user, uint256 amount, bool isDeposit) = abi.decode(payload, (address, uint256, bool));

require(registeredPools[msg.sender], "Unauthorized pool");

if (isDeposit) {
userDeposits[user] += amount;
emit DepositRecorded(user, amount);
} else {
userLoans[user] += amount;
emit LoanRecorded(user, amount);
}
}
}

contract LendingPool {
address public globalLedger;
address public owner;
string public globalLedgerChain;
IAxelarGateway public axelarGateway;
address public token; // Supported token for this lending pool

event DepositSent(address indexed user, uint256 amount);
event LoanSent(address indexed user, uint256 amount);

modifier onlyOwner() {
require(msg.sender == owner, "Not authorized");
_;
}

constructor(
address _globalLedger,
string memory _globalLedgerChain,
address _gateway,
address _owner,
address _token
) {
globalLedger = _globalLedger;
globalLedgerChain = _globalLedgerChain;
axelarGateway = IAxelarGateway(_gateway);
owner = _owner;
token = _token;
}

function deposit(uint256 amount) external {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that you have changed the deposit function such that it is not backward compatible. One of the main criterias is to make sure backward compatiblity, these changes don't let the interaction remain same.

bytes memory payload = abi.encode(msg.sender, amount, true);
string memory globalLedgerAddress = toAsciiString(globalLedger);

axelarGateway.callContract(globalLedgerChain, globalLedgerAddress, payload);

emit DepositSent(msg.sender, amount);
}

function borrow(uint256 amount) external {
bytes memory payload = abi.encode(msg.sender, amount, false);
string memory globalLedgerAddress = toAsciiString(globalLedger);

axelarGateway.callContract(globalLedgerChain, globalLedgerAddress, payload);

emit LoanSent(msg.sender, amount);
}

function toAsciiString(address _addr) internal pure returns (string memory) {
bytes memory s = new bytes(42);
bytes memory hexChars = "0123456789abcdef";

s[0] = "0";
s[1] = "x";

for (uint i = 0; i < 20; i++) {
s[2 + i * 2] = hexChars[uint8(uint160(_addr) >> (8 * (19 - i)) + 4) & 0xF];
s[3 + i * 2] = hexChars[uint8(uint160(_addr) >> (8 * (19 - i))) & 0xF];
}
return string(s);
}
}

contract LendingPoolFactory {
address public globalLedger;
event LendingPoolDeployed(address pool, address owner, address token);

constructor(address _globalLedger) {
globalLedger = _globalLedger;
}

function deployLendingPool(
string memory lendingPoolChain,
address gateway,
address token
) external returns (address) {
LendingPool newPool = new LendingPool(globalLedger, lendingPoolChain, gateway, msg.sender, token);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method wouldn't work if the contracts are deployed on different shards

GlobalLedger(globalLedger).registerLendingPool(address(newPool));
emit LendingPoolDeployed(address(newPool), msg.sender, token);
return address(newPool);
}
}
10 changes: 10 additions & 0 deletions academy/lending-protocol/contracts/LendingPool.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity ^0.8.28;
import "@nilfoundation/smart-contracts/contracts/Nil.sol";
import "@nilfoundation/smart-contracts/contracts/NilTokenBase.sol";


/// @title LendingPool
/// @dev The LendingPool contract facilitates lending and borrowing of tokens and handles collateral management.
/// It interacts with other contracts such as GlobalLedger, InterestManager, and Oracle for tracking deposits, calculating interest, and fetching token prices.
Expand Down Expand Up @@ -444,3 +445,12 @@ contract LendingPool is NilBase, NilTokenBase {
sendTokenInternal(borrower, collateralToken, collateralAmount);
}
}









4 changes: 3 additions & 1 deletion academy/lending-protocol/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion academy/lending-protocol/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"description": "This is an example repository to showcase how a lending protocol can be built on top of =nil;",
"devDependencies": {
"@nomicfoundation/hardhat-toolbox-viem": "^3.0.0",
"hardhat": "^2.22.18"
"hardhat": "^2.22.19"
},
"scripts": {
"compile": "npx hardhat compile",
Expand Down
9 changes: 0 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.