-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathopNode.sol
179 lines (148 loc) · 6.79 KB
/
opNode.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { MinerAPI } from "@zondax/filecoin-solidity/contracts/v0.8/MinerAPI.sol";
import { BigInts } from "@zondax/filecoin-solidity/contracts/v0.8/utils/BigInts.sol";
import { CommonTypes } from "@zondax/filecoin-solidity/contracts/v0.8/types/CommonTypes.sol";
import "./utils/FilAddress.sol";
import {DataConvert} from "./utils/data-convert.sol";
import "./models/actorInfo.sol";
interface PondNodeCall {
function getMinersByActorId(uint64) external view returns(ActorInfo calldata);
function withdraw(uint64,uint256) external payable;
function contractToAddress(uint256,address) external payable;
function send(uint64,uint256) external payable;
}
interface RateContract {
function withdrawalLimit(uint64) external returns (uint256);
function getMaxBorrowableAmount(uint64) external view returns(uint256);
}
interface DebtContract {
function balanceOf(address) external view returns (uint256);
}
contract OpNode {
using DataConvert for *;
address admin; // Administrator address
address public debtAddress; // Loan Contract Address
address public rateAddress = 0xdb4e6Bff063de9D104280067b1e9e3d3644b36f4; // Interest rate contract address
address public manageAddress; // Node Contract Address
address public pondAddress; // Fund pool sub contract address
address operateAddr; // Operating profit distribution address
address riskAddr; // Risk capital address
// Determine if it is the operator's method
modifier onlyOperator(uint64 actorId) {
// Node contract acquisition operator
ActorInfo memory miner = PondNodeCall(manageAddress).getMinersByActorId(actorId);
require(msg.sender == miner.operator || msg.sender == admin, "No operation permissions");
_;
}
// Determine if it is an administrator
modifier onlyAdmin() {
require(msg.sender == admin, "No admin permissions");
_;
}
// Replace with a new admin
function updateAdmin(address _admin) public onlyAdmin {
admin = _admin;
}
// Set interest rate contract address
function setRateAddrContractAddr(address addr) public onlyAdmin {
rateAddress = addr;
}
// Set loan contract address
function setDebtContractAddr(address addr) public onlyAdmin {
debtAddress = addr;
}
// Set Pool Contract Address
function setPondContractAddr(address addr) public onlyAdmin {
pondAddress = addr;
}
// Set operating profit distribution address
function setOperateAddr(address addr) public onlyAdmin {
operateAddr = addr;
}
// Set risk pool address
function setRiskAddr(address addr) public onlyAdmin {
riskAddr = addr;
}
// Set node contract address
function setManageContractAddr(address addr) public onlyAdmin {
manageAddress = addr;
}
// Set associated contract address at once
function setAllContractAddr(address[4] calldata addrList) public onlyAdmin {
rateAddress = addrList[0];
debtAddress = addrList[1];
pondAddress = addrList[2];
manageAddress = addrList[3];
}
// Initialize partial information
constructor() {
admin = msg.sender;
}
// Node withdrawal
function withdraw(uint64 target, uint256 amount, uint256 isTotal) external onlyOperator(target) {
// Query node data
ActorInfo memory miner = PondNodeCall(manageAddress).getMinersByActorId(target);
uint256 wLimit = RateContract(rateAddress).withdrawalLimit(target);
// If there is a corresponding identifier, assign the maximum amount queried to the account
if (isTotal == 0) {
amount = wLimit;
}else {
require(amount <= wLimit && amount > 0,"Exceeding available limit");
}
// Withdrawal to internal contract
PondNodeCall(pondAddress).withdraw(target,amount);
// Transfer to existing owner
PondNodeCall(pondAddress).contractToAddress(amount,FilAddress.toIDAddress(miner.ownerId));
}
// Loan
function loan(uint64 target, uint256 amount, uint256 isTotal) external onlyOperator(target) {
// Obtain maximum loan amount
uint256 maxLoan = RateContract(rateAddress).getMaxBorrowableAmount(target);
if (isTotal == 0) {
amount = maxLoan;
}else {
// Determine whether the loan amount is greater than the available loan amount
// Determine whether the loan amount is greater than the amount of the smart contract
require(amount <= maxLoan && amount <= pondAddress.balance, "Excessive borrowing amount");
}
// Bookkeeping
// Bookkeeping in lending smart contracts
address targetAddr = FilAddress.toIDAddress(target);
(bool successAddDebt, ) = debtAddress.call(
abi.encodeWithSignature("addDebts(uint256,address)", amount, targetAddr)
);
require(successAddDebt, "External call failed");
// Transfer to node
PondNodeCall(pondAddress).send(target,amount);
}
// Repayment
function repayment(uint64 target, uint256 amount,uint256 isTotal) public onlyOperator(target) {
address targetAddr = FilAddress.toIDAddress(target);
require(isSufficient(target,targetAddr,amount), "External call failed");
// Write off accounts and obtain the amount that should be transferred
(bool successRepay, bytes memory resultRepay) = debtAddress.call(
abi.encodeWithSignature("repayDebts(uint256,address,bool)", amount, targetAddr, isTotal)
);
require(successRepay, "External call failed");
(uint256 pondRepay,uint256 operateRepay,uint256 riskRepay) = abi.decode(resultRepay, (uint256,uint256,uint256));
// Withdrawal to internal contract
PondNodeCall(pondAddress).withdraw(target,pondRepay);
// Divide accounts
PondNodeCall(pondAddress).contractToAddress(operateRepay,operateAddr);// Operating profit sharing
if (riskRepay > 0) {
PondNodeCall(pondAddress).contractToAddress(riskRepay,riskAddr); // Risk pool
}
}
// Determine whether the repayment conditions are met
function isSufficient(uint64 target, address targetAddr, uint256 amount) private returns (bool) {
(uint256 value,) = BigInts.toUint256(MinerAPI.getAvailableBalance(CommonTypes.FilActorId.wrap(target)));
// Determine if the amount is sufficient
require(value >= amount,"Insufficient available balance");
// Determine the amount of debt owed
uint256 targetBalance = DebtContract(debtAddress).balanceOf(targetAddr);
//Determine if there is any outstanding amount
require(targetBalance > 0,"Node has no outstanding payments");
return true;
}
}