Note: There is a section for disputed findings below the gas report section
Issue | Instances | |
---|---|---|
[M‑01] | The owner is a single point of failure and a centralization risk |
85 |
[M‑02] | Excess funds sent via msg.value not refunded |
1 |
[M‑03] | Contracts are vulnerable to fee-on-transfer accounting-related issues | 4 |
[M‑04] | Unsafe use of transfer() /transferFrom() with IERC20 |
4 |
[M‑05] | Use of transferFrom() rather than safeTransferFrom() for NFTs in will lead to the loss of NFTs |
1 |
[M‑06] | Return values of transfer() /transferFrom() not checked |
6 |
[M‑07] | _safeMint() should be used rather than _mint() wherever possible |
3 |
Total: 104 instances over 7 issues
Issue | Instances | |
---|---|---|
[L‑01] | Some tokens may revert when zero value transfers are made | 19 |
[L‑02] | calc_token_amount() has slippage added on top of Curve's calculated slippage |
1 |
[L‑03] | approve() /safeApprove() may revert if the current approval is not zero |
20 |
[L‑04] | Missing contract-existence checks before low-level calls | 29 |
[L‑05] | External call recipient may consume all transaction gas | 12 |
[L‑06] | Multiplication on the result of a division | 8 |
[L‑07] | Division by zero not prevented | 13 |
[L‑08] | External calls in an un-bounded for- loop may result in a DOS |
61 |
[L‑09] | State variables not capped at reasonable values | 3 |
[L‑10] | Missing checks for address(0x0) when assigning values to address state variables |
46 |
[L‑11] | Allowed fees/rates should be capped by smart contracts | 2 |
[L‑12] | Solidity version 0.8.20 may not work on other chains due to PUSH0 |
67 |
[L‑13] | Consider implementing two-step procedure for updating protocol addresses | 7 |
[L‑14] | Unsafe downcast | 64 |
[L‑15] | Loss of precision | 121 |
[L‑16] | Array lengths not checked | 9 |
[L‑17] | Empty receive() /payable fallback() function does not authorize requests |
10 |
[L‑18] | Draft imports may break in new minor versions | 7 |
[L‑19] | Functions calling contracts/addresses with transfer hooks are missing reentrancy guards | 8 |
[L‑20] | Use Ownable2Step rather than Ownable |
4 |
[L‑21] | addRewardToken() does note remove old entries before adding new ones |
2 |
[L‑22] | Signature use at deadlines should be allowed | 3 |
[L‑23] | NFT doesn't handle hard forks | 2 |
[L‑24] | decimals() is not a part of the ERC-20 standard |
4 |
[L‑25] | tokenURI() does not follow EIP-721 |
2 |
[L‑26] | Open TODOs | 10 |
[L‑27] | Calls to _get() will revert when totalSupply() returns zero |
1 |
[L‑28] | latestAnswer() is deprecated |
5 |
[L‑29] | safeApprove() is deprecated |
1 |
[L‑30] | Use of a single-step ownership transfer | 1 |
Total: 542 instances over 30 issues
Issue | Instances | |
---|---|---|
[N‑01] | Events are missing sender information | 21 |
[N‑02] | Variables need not be initialized to zero | 129 |
[N‑03] | Consider using named mappings | 57 |
[N‑04] | Contract uses both require() /revert() as well as custom errors |
4 |
[N‑05] | Consider adding a block/deny-list | 55 |
[N‑06] | Non-external /public variable and function names should begin with an underscore |
89 |
[N‑07] | Large numeric literals should use underscores for readability | 15 |
[N‑08] | Unused contract variables | 4 |
[N‑09] | Use abi.encodeCall() instead of abi.encodeSignature() /abi.encodeSelector() |
58 |
[N‑10] | Constants in comparisons should appear on the left side | 92 |
[N‑11] | Consider disabling renounceOwnership() |
24 |
[N‑12] | Consider adding emergency-stop functionality | 18 |
[N‑13] | Events may be emitted out of order due to reentrancy | 23 |
[N‑14] | Function names should use lowerCamelCase | 17 |
[N‑15] | Consider bounding input array length | 29 |
[N‑16] | Consider moving msg.sender checks to a common authorization modifier |
10 |
[N‑17] | Imports could be organized more systematically | 27 |
[N‑18] | Overridden function has no body | 4 |
[N‑19] | Use OpenZeppelin's or Solady's Ownable, rather than re-inventing the wheel | 20 |
[N‑20] | Array is push() ed but not pop() ed |
5 |
[N‑21] | Long functions should be refactored into multiple, smaller, functions | 7 |
[N‑22] | Mixed usage of int /uint with int256 /uint256 |
7 |
[N‑23] | Unsafe conversion from unsigned to signed values | 10 |
[N‑24] | public functions not called by the contract should be declared external instead |
74 |
[N‑25] | constant s should be defined rather than using magic numbers |
194 |
[N‑26] | Event is not properly indexed |
22 |
[N‑27] | Duplicated require() /revert() checks should be refactored to a modifier or function |
33 |
[N‑28] | Vulnerable versions of packages are being used | 6 |
[N‑29] | Import declarations should import specific identifiers, rather than the whole file | 345 |
[N‑30] | Return values of approve() not checked |
45 |
[N‑31] | Contract implements interface without extending the interface | 9 |
[N‑32] | override function arguments that are unused should have the variable name removed or commented out to avoid compiler warnings |
5 |
[N‑33] | Cast is more restrictive than the type of the variable being assigned | 8 |
[N‑34] | Events that mark critical parameter changes should contain both the old and the new value | 59 |
[N‑35] | Constant redefined elsewhere | 23 |
[N‑36] | Use @inheritdoc rather than using a non-standard annotation |
5 |
[N‑37] | Inconsistent spacing in comments | 315 |
[N‑38] | Lines are too long | 361 |
[N‑39] | Variable names that consist of all capital letters should be reserved for constant /immutable variables |
6 |
[N‑40] | Non-library/interface files should use fixed compiler versions, not floating ones | 59 |
[N‑41] | Typos | 31 |
[N‑42] | NatSpec @param is missing |
329 |
[N‑43] | NatSpec @return argument is missing |
168 |
[N‑44] | Avoid the use of sensitive terms | 60 |
[N‑45] | Function ordering does not follow the Solidity style guide | 81 |
[N‑46] | Contract does not follow the Solidity style guide's suggested layout ordering | 15 |
[N‑47] | Control structures do not follow the Solidity Style Guide | 5 |
[N‑48] | Expressions for constant values such as a call to keccak256() , should use immutable rather than constant |
5 |
[N‑49] | Numeric values having to do with time should use time units for readability | 14 |
[N‑50] | Consider using delete rather than assigning zero/false to clear values |
19 |
[N‑51] | Contracts should have full test coverage | 6 |
[N‑52] | Large or complicated code bases should implement invariant tests | 6 |
[N‑53] | Enable IR-based code generation | 6 |
[N‑54] | private functions not called by the contract should be removed |
1 |
[N‑55] | internal functions not called by the contract should be removed |
1 |
[N‑56] | Unused error definition |
1 |
[N‑57] | Contract names should use CamelCase | 1 |
[N‑58] | Cast to bytes or bytes32 for clearer semantic meaning |
2 |
[N‑59] | Custom error has no error details | 23 |
[N‑60] | Variable names don't follow the Solidity style guide | 4 |
[N‑61] | Contracts containing only utility functions should be made into libraries | 2 |
[N‑62] | Unused struct definition |
8 |
[N‑63] | if -statement can be converted to a ternary |
6 |
[N‑64] | Adding a return statement when the function defines a named return variable, is redundant |
3 |
[N‑65] | 2**<n> - 1 should be re-written as type(uint<n>).max |
1 |
[N‑66] | require() /revert() statements should have descriptive reason strings |
2 |
[N‑67] | Non-assembly method available | 2 |
[N‑68] | Missing event and or timelock for critical parameter change | 5 |
[N‑69] | Constructor visibility is ignored | 1 |
[N‑70] | Visibility should be set explicitly rather than defaulting to internal |
10 |
[N‑71] | Memory-safe annotation preferred over comment variant | 2 |
[N‑72] | Interfaces should be defined in separate files from their usage | 2 |
[N‑73] | Duplicate import statements | 1 |
[N‑74] | Using > />= without specifying an upper bound is unsafe |
1 |
[N‑75] | File is missing NatSpec | 4 |
[N‑76] | address s shouldn't be hard-coded |
1 |
[N‑77] | pragma experimental ABIEncoderV2 is deprecated |
3 |
[N‑78] | Use scientific notation (e.g. 1e18 ) rather than exponentiation (e.g. 10**18 ) |
2 |
[N‑79] | else -block not required |
3 |
[N‑80] | Use a more recent version of solidity | 1 |
[N‑81] | Use a more recent version of solidity | 3 |
[N‑82] | Strings should use double quotes rather than single quotes | 7 |
Total: 3142 instances over 82 issues
Issue | Instances | Total Gas Saved | |
---|---|---|---|
[G‑01] | Reduce gas usage by moving to Solidity 0.8.19 or later | 68 | - |
[G‑02] | Using bool s for storage incurs overhead |
17 | 290700 |
[G‑03] | Avoid updating storage when the value hasn't changed | 26 | 20800 |
[G‑04] | unchecked {} can be used on the division of two uint s in order to save gas |
76 | 1520 |
[G‑05] | Remove or replace unused state variables | 3 | - |
[G‑06] | Multiple address /ID mappings can be combined into a single mapping of an address /ID to a struct , where appropriate |
10 | 420 |
[G‑07] | State variables only set in the constructor should be declared immutable |
27 | 56619 |
[G‑08] | State variables can be packed into fewer storage slots | 6 | 12000 |
[G‑09] | Using storage instead of memory for structs/arrays saves gas |
18 | 75600 |
[G‑10] | State variables should be cached in stack variables rather than re-reading them from storage | 156 | 15132 |
[G‑11] | <x> += <y> costs more gas than <x> = <x> + <y> for state variables |
5 | 565 |
[G‑12] | Add unchecked {} for subtractions where the operands cannot underflow because of a previous require() or if -statement |
21 | 1785 |
[G‑13] | <array>.length should not be looked up in every loop of a for -loop |
24 | 72 |
[G‑14] | ++i /i++ should be unchecked{++i} /unchecked{i++} when it is not possible for them to overflow, as is the case when used in for - and while -loops |
27 | 1620 |
[G‑15] | private functions not called by the contract should be removed to save deployment gas |
1 | - |
[G‑16] | Optimize names to save gas | 54 | 1188 |
[G‑17] | >= costs less gas than > |
2 | 6 |
[G‑18] | internal functions not called by the contract should be removed to save deployment gas |
1 | - |
[G‑19] | ++i costs less gas than i++ , especially when it's used in for -loops (--i /i-- too) |
41 | 205 |
[G‑20] | Splitting require() statements that use && saves gas |
7 | 21 |
[G‑21] | Using private rather than public for constants, saves gas |
17 | - |
[G‑22] | Don't compare boolean expressions to boolean literals | 6 | 54 |
[G‑23] | Multiple if -statements with mutually-exclusive conditions should be changed to if -else statements |
2 | - |
[G‑24] | require() or revert() statements that check input arguments should be at the top of the function |
3 | - |
[G‑25] | Empty blocks should be removed or emit something | 23 | - |
[G‑26] | Superfluous event fields | 1 | 34 |
[G‑27] | Use custom errors rather than revert() /require() strings to save gas |
244 | - |
[G‑28] | Functions guaranteed to revert when called by normal users can be marked payable |
87 | 1827 |
[G‑29] | Constructors can be marked payable |
50 | 1050 |
[G‑30] | Structs can be packed into fewer storage slots | 5 | 10000 |
[G‑31] | Inverting the condition of an if -else -statement wastes gas |
1 | - |
[G‑32] | Division by two should use bit shifting | 3 | 60 |
[G‑33] | Structs can be packed into fewer storage slots by truncating timestamp bytes | 1 | 2000 |
[G‑34] | Multiple accesses of a mapping/array should use a local variable cache | 10 | 420 |
[G‑35] | internal functions only called once can be inlined to save gas |
26 | 520 |
[G‑36] | require() /revert() strings longer than 32 bytes cost extra gas |
23 | 69 |
[G‑37] | keccak256() should only need to be called on a specific string literal once |
3 | 126 |
[G‑38] | Usage of uints /ints smaller than 32 bytes (256 bits) incurs overhead |
5 | 110 |
[G‑39] | Stack variable used as a cheaper cache for a state variable is only used once | 1 | 3 |
[G‑40] | Consider using bytes32 rather than a string |
8 | - |
[G‑41] | The result of function calls should be cached rather than re-calling the function | 8 | - |
[G‑42] | Use a more recent version of solidity | 2 | - |
[G‑43] | Not using the named return variables anywhere in the function is confusing | 69 | - |
[G‑44] | Avoid contract existence checks by using low level calls | 2 | 200 |
[G‑45] | String literals passed to abi.encode() /abi.encodePacked() should not be split by commas |
1 | 21 |
Total: 1191 instances over 45 issues with 494747 gas saved
Gas totals are estimates based on data from the Ethereum Yellowpaper. The estimates use the lower bounds of ranges and count two iterations of each for
-loop. All values above are runtime, not deployment, values; deployment values are listed in the individual issue descriptions. The table above as well as its gas numbers do not include any of the excluded findings.
The issues below may be reported by other bots/wardens, but can be penalized/ignored since either the rule or the specified instances are invalid
Issue | Instances | |
---|---|---|
[D‑01] | 16 | |
[D‑02] | constant variables, which will save gas |
5 |
[D‑03] | 16 | |
[D‑04] | abi.encode() is less efficient than abi.encodepacked() |
17 |
[D‑05] | 72 | |
[D‑06] | address(0x0) |
10 |
[D‑07] | 59 | |
[D‑08] | public function visibility to external to save gas |
70 |
[D‑09] | 324 | |
[D‑10] | safeTransfer function does not check for contract existence |
2 |
[D‑11] | 7 |
Total: 598 instances over 11 issues
Having a single EOA as the only owner of contracts is a large centralization risk and a single point of failure. A single private key may be taken in a hack, or the sole holder of the key may become unable to retrieve the key when necessary. Consider changing to a multi-signature setup, or having a role-based authorization model.
There are 85 instances of this issue:
see instances
File: contracts/Penrose.sol
256: function setBigBangEthMarketDebtRate(uint256 _rate) external onlyOwner {
263: function setBigBangEthMarket(address _market) external onlyOwner {
281: function setConservator(address _conservator) external onlyOwner {
291: function setUsdoToken(address _usdoToken) external onlyOwner {
317 function registerSingularityMasterContract(
318 address mcAddress,
319 IPenrose.ContractType contractType_
320: ) external onlyOwner {
339 function registerBigBangMasterContract(
340 address mcAddress,
341 IPenrose.ContractType contractType_
342: ) external onlyOwner {
362 function registerSingularity(
363 address mc,
364 bytes calldata data,
365 bool useCreate2
366 )
367 external
368 payable
369 onlyOwner
370 registeredSingularityMasterContract(mc)
371 returns (address _contract)
372: {
381 function addSingularity(
382 address mc,
383 address _contract
384: ) external onlyOwner registeredSingularityMasterContract(mc) {
395 function registerBigBang(
396 address mc,
397 bytes calldata data,
398 bool useCreate2
399 )
400 external
401 payable
402 onlyOwner
403 registeredBigBangMasterContract(mc)
404 returns (address _contract)
405: {
414 function addBigBang(
415 address mc,
416 address _contract
417: ) external onlyOwner registeredBigBangMasterContract(mc) {
424 function executeMarketFn(
425 address[] calldata mc,
426 bytes[] memory data,
427 bool forceSuccess
428 )
429 external
430 onlyOwner
431 notPaused
432 returns (bool[] memory success, bytes[] memory result)
433: {
455: function setFeeTo(address feeTo_) external onlyOwner {
464: function setSwapper(ISwapper swapper, bool enable) external onlyOwner {
File: contracts/markets/Market.sol
142: function setBorrowOpeningFee(uint256 _val) external onlyOwner {
151: function setBorrowCap(uint256 _cap) external notPaused onlyOwner {
158 function setMarketConfig(
159 uint256 _borrowOpeningFee,
160 IOracle _oracle,
161 bytes calldata _oracleData,
162 address _conservator,
163 uint256 _callerFee,
164 uint256 _protocolFee,
165 uint256 _liquidationBonusAmount,
166 uint256 _minLiquidatorReward,
167 uint256 _maxLiquidatorReward,
168 uint256 _totalBorrowCap,
169 uint256 _collateralizationRate
170: ) external onlyOwner {
File: contracts/markets/bigBang/BigBang.sol
442 function refreshPenroseFees(
443 address
444: ) external onlyOwner notPaused returns (uint256 feeShares) {
466 function setBigBangConfig(
467 uint256 _minDebtRate,
468 uint256 _maxDebtRate,
469 uint256 _debtRateAgainstEthMarket,
470 uint256 _liquidationMultiplier
471: ) external onlyOwner {
File: contracts/markets/singularity/Singularity.sol
477 function refreshPenroseFees(
478 address feeTo
479: ) external onlyOwner notPaused returns (uint256 feeShares) {
489 function setSingularityConfig(
490 uint256 _lqCollateralizationRate,
491 uint256 _liquidationMultiplier,
492 uint256 _minimumTargetUtilization,
493 uint256 _maximumTargetUtilization,
494 uint64 _minimumInterestPerSecond,
495 uint64 _maximumInterestPerSecond,
496 uint256 _interestElasticity
497: ) external onlyOwner {
576 function setLiquidationQueueConfig(
577 ILiquidationQueue _liquidationQueue,
578 address _bidExecutionSwapper,
579 address _usdoSwapper
580: ) external onlyOwner {
File: contracts/usd0/BaseUSDO.sol
88: function setMaxFlashMintable(uint256 _val) external onlyOwner {
96: function setFlashMintFee(uint256 _val) external onlyOwner {
105: function setConservator(address _conservator) external onlyOwner {
File: contracts/Balancer.sol
172 function rebalance(
173 address payable _srcOft,
174 uint16 _dstChainId,
175 uint256 _slippage,
176 uint256 _amount,
177 bytes memory _ercData
178 )
179 external
180 payable
181 onlyOwner
182 onlyValidDestination(_srcOft, _dstChainId)
183 onlyValidSlippage(_slippage)
184: {
219 function initConnectedOFT(
220 address _srcOft,
221 uint16 _dstChainId,
222 address _dstOft,
223 bytes memory _ercData
224: ) external onlyOwner {
250 function addRebalanceAmount(
251 address _srcOft,
252 uint16 _dstChainId,
253 uint256 _amount
254: ) external onlyValidDestination(_srcOft, _dstChainId) onlyOwner {
File: contracts/TapiocaWrapper.sol
115 function executeTOFT(
116 address _toft,
117 bytes calldata _bytecode,
118 bool _revertOnFailure
119: ) external payable onlyOwner returns (bool success, bytes memory result) {
131 function executeCalls(
132 ExecutionCall[] calldata _call
133 )
134 external
135 payable
136 onlyOwner
137 returns (bool success, bytes[] memory results)
138: {
154 function createTOFT(
155 address _erc20,
156 bytes calldata _bytecode,
157 bytes32 _salt,
158 bool _linked
159: ) external onlyOwner {
File: contracts/tOFT/mTapiocaOFT.sol
116 function updateConnectedChain(
117 uint256 _chain,
118 bool _status
119: ) external onlyOwner {
131 function updateBalancerState(
132 address _balancer,
133 bool _status
134: ) external onlyOwner {
File: contracts/Vesting.sol
130: function registerUser(address _user, uint256 _amount) external onlyOwner {
151: function init(IERC20 _token, uint256 _seededAmount) external onlyOwner {
File: contracts/governance/twTAP.sol
455: function addRewardToken(IERC20 token) external onlyOwner returns (uint256) {
File: contracts/option-airdrop/AirdropBroker.sol
308 function setTapOracle(
309 IOracle _tapOracle,
310 bytes calldata _tapOracleData
311: ) external onlyOwner {
318 function setPhase2MerkleRoots(
319 bytes32[4] calldata _merkleRoots
320: ) external onlyOwner {
324 function registerUserForPhase(
325 uint256 _phase,
326 address[] calldata _users,
327 uint256[] calldata _amounts
328: ) external onlyOwner {
344 function setPaymentToken(
345 ERC20 _paymentToken,
346 IOracle _oracle,
347 bytes calldata _oracleData
348: ) external onlyOwner {
357 function setPaymentTokenBeneficiary(
358 address _paymentTokenBeneficiary
359: ) external onlyOwner {
365 function collectPaymentTokens(
366 address[] calldata _paymentTokens
367: ) external onlyOwner {
File: contracts/options/TapiocaOptionBroker.sol
446 function setTapOracle(
447 IOracle _tapOracle,
448 bytes calldata _tapOracleData
449: ) external onlyOwner {
458 function setPaymentToken(
459 ERC20 _paymentToken,
460 IOracle _oracle,
461 bytes calldata _oracleData
462: ) external onlyOwner {
471 function setPaymentTokenBeneficiary(
472 address _paymentTokenBeneficiary
473: ) external onlyOwner {
479 function collectPaymentTokens(
480 address[] calldata _paymentTokens
481: ) external onlyOwner {
File: contracts/options/TapiocaOptionLiquidityProvision.sol
259 function setSGLPoolWEight(
260 IERC20 singularity,
261 uint256 weight
262: ) external onlyOwner updateTotalSGLPoolWeights {
276 function registerSingularity(
277 IERC20 singularity,
278 uint256 assetID,
279 uint256 weight
280: ) external onlyOwner updateTotalSGLPoolWeights {
297 function unregisterSingularity(
298 IERC20 singularity
299: ) external onlyOwner updateTotalSGLPoolWeights {
File: contracts/tokens/BaseTapOFT.sol
326: function setTwTap(address _twTap) external onlyOwner {
File: contracts/tokens/LTap.sol
53: function setLockedUntil(uint256 _lockedUntil) external onlyOwner {
File: contracts/tokens/TapOFT.sol
140 function setGovernanceChainIdentifier(
141 uint256 _identifier
142: ) external onlyOwner {
152: function updatePause(bool val) external onlyOwner {
160: function setMinter(address _minter) external onlyOwner {
File: contracts/Swapper/UniswapV3Swapper.sol
61: function setPoolFee(uint24 _newFee) external onlyOwner {
File: contracts/aave/AaveStrategy.sol
122: function setDepositThreshold(uint256 amount) external onlyOwner {
129: function setMultiSwapper(address _swapper) external onlyOwner {
209: function emergencyWithdraw() external onlyOwner returns (uint256 result) {
File: contracts/balancer/BalancerStrategy.sol
109: function setDepositThreshold(uint256 amount) external onlyOwner {
120: function emergencyWithdraw() external onlyOwner returns (uint256 result) {
File: contracts/compound/CompoundStrategy.sol
89: function setDepositThreshold(uint256 amount) external onlyOwner {
100: function emergencyWithdraw() external onlyOwner returns (uint256 result) {
File: contracts/convex/ConvexTricryptoStrategy.sol
148: function emergencyWithdraw() external onlyOwner returns (uint256 result) {
163: function setDepositThreshold(uint256 amount) external onlyOwner {
170: function setMultiSwapper(address _swapper) external onlyOwner {
179: function setTricryptoLPGetter(address _lpGetter) external onlyOwner {
File: contracts/curve/TricryptoLPStrategy.sol
134: function setDepositThreshold(uint256 amount) external onlyOwner {
141: function setMultiSwapper(address _swapper) external onlyOwner {
150: function setTricryptoLPGetter(address _lpGetter) external onlyOwner {
199: function emergencyWithdraw() external onlyOwner returns (uint256 result) {
File: contracts/curve/TricryptoNativeStrategy.sol
125: function setDepositThreshold(uint256 amount) external onlyOwner {
132: function setMultiSwapper(address _swapper) external onlyOwner {
141: function setTricryptoLPGetter(address _lpGetter) external onlyOwner {
182: function emergencyWithdraw() external onlyOwner returns (uint256 result) {
File: contracts/glp/GlpStrategy.sol
104: function harvestGmx(uint256 priceNum, uint256 priceDenom) public onlyOwner {
113: function setFeeRecipient(address recipient) external onlyOwner {
File: contracts/lido/LidoEthStrategy.sol
93: function setDepositThreshold(uint256 amount) external onlyOwner {
104: function emergencyWithdraw() external onlyOwner returns (uint256 result) {
File: contracts/stargate/StargateStrategy.sol
142: function setDepositThreshold(uint256 amount) external onlyOwner {
149: function setMultiSwapper(address _swapper) external onlyOwner {
193: function emergencyWithdraw() external onlyOwner returns (uint256 result) {
File: contracts/yearn/YearnStrategy.sol
90: function setDepositThreshold(uint256 amount) external onlyOwner {
101: function emergencyWithdraw() external onlyOwner returns (uint256 result) {
File: contracts/NativeTokenFactory.sol
56: function transferOwnership(uint256 tokenId, address newOwner, bool direct, bool renounce) public onlyOwner(tokenId) {
109: function mint(uint256 tokenId, address to, uint256 amount) public onlyOwner(tokenId) {
127: function batchMint(uint256 tokenId, address[] calldata tos, uint256[] calldata amounts) public onlyOwner(tokenId) {
The code below allows the caller to provide Ether, but does not refund the amount in excess of what's required, leaving funds stranded in the contract. The condition should be changed to check for equality, or the code should refund the excess.
There is one instance of this issue:
File: contracts/Balancer.sol
201 bool _isNative = ITapiocaOFT(_srcOft).erc20() == address(0);
202 if (_isNative) {
203 if (msg.value <= _amount) revert FeeAmountNotSet();
204 _sendNative(_srcOft, _amount, _dstChainId, _slippage);
205 } else {
206 if (msg.value == 0) revert FeeAmountNotSet();
207 _sendToken(_srcOft, _amount, _dstChainId, _slippage, _ercData);
208 }
209
210 connectedOFTs[_srcOft][_dstChainId].rebalanceable -= _amount;
211 emit Rebalanced(_srcOft, _dstChainId, _slippage, _amount, _isNative);
212: }
The functions below transfer funds from the caller to the receiver via transferFrom()
, but do not ensure that the actual number of tokens received is the same as the input amount to the transfer. If the token is a fee-on-transfer token, the balance after the transfer will be smaller than expected, leading to accounting issues. Even if there are checks later, related to a secondary transfer, an attacker may be able to use latent funds (e.g. mistakenly sent by another user) in order to get a free credit. One way to solve this problem is to measure the balance before and after the transfer, and use the difference as the amount, rather than the stated amount.
There are 4 instances of this issue:
File: contracts/option-airdrop/AirdropBroker.sol
487 function _processOTCDeal(
488 ERC20 _paymentToken,
489 PaymentTokenOracle memory _paymentTokenOracle,
490 uint256 tapAmount,
491 uint256 discount
492 ) internal {
493 // Get TAP valuation
494 uint256 otcAmountInUSD = tapAmount * epochTAPValuation;
495
496 // Get payment token valuation
497 (, uint256 paymentTokenValuation) = _paymentTokenOracle.oracle.get(
498 _paymentTokenOracle.oracleData
499 );
500
501 // Calculate payment amount and initiate the transfers
502 uint256 discountedPaymentAmount = _getDiscountedPaymentAmount(
503 otcAmountInUSD,
504 paymentTokenValuation,
505 discount,
506 _paymentToken.decimals()
507 );
508
509 _paymentToken.transferFrom(
510 msg.sender,
511 address(this),
512 discountedPaymentAmount
513 );
514 tapOFT.transfer(msg.sender, tapAmount);
515: }
File: contracts/options/TapiocaOptionBroker.sol
508 function _processOTCDeal(
509 ERC20 _paymentToken,
510 PaymentTokenOracle memory _paymentTokenOracle,
511 uint256 tapAmount,
512 uint256 discount
513 ) internal {
514 // Get TAP valuation
515 uint256 otcAmountInUSD = tapAmount * epochTAPValuation;
516
517 // Get payment token valuation
518 (, uint256 paymentTokenValuation) = _paymentTokenOracle.oracle.get(
519 _paymentTokenOracle.oracleData
520 );
521
522 // Calculate payment amount and initiate the transfers
523 uint256 discountedPaymentAmount = _getDiscountedPaymentAmount(
524 otcAmountInUSD,
525 paymentTokenValuation,
526 discount,
527 _paymentToken.decimals()
528 );
529
530 _paymentToken.transferFrom(
531 msg.sender,
532 address(this),
533 discountedPaymentAmount
534 );
535 tapOFT.extractTAP(msg.sender, tapAmount);
536: }
File: contracts/Magnetar/modules/MagnetarMarketModule.sol
792 function _extractTokens(
793 address _from,
794 address _token,
795 uint256 _amount
796 ) private {
797 IERC20(_token).safeTransferFrom(_from, address(this), _amount);
798: }
File: contracts/Swapper/BaseSwapper.sol
144 function _extractTokens(
145 ISwapper.YieldBoxData calldata ybData,
146 IYieldBox _yieldBox,
147 address token,
148 uint256 tokenId,
149 uint256 amount,
150 uint256 share
151 ) internal returns (uint256) {
152 if (ybData.withdrawFromYb) {
153 (amount, share) = _yieldBox.withdraw(
154 tokenId,
155 address(this),
156 address(this),
157 amount,
158 share
159 );
160 return amount;
161 }
162 IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
163 return amount;
164: }
Some tokens do not implement the ERC20 standard properly but are still accepted by most code that accepts ERC20 tokens. For example Tether (USDT)'s transfer()
and transferFrom()
functions on L1 do not return booleans as the specification requires, and instead have no return value. When these sorts of tokens are cast to IERC20
, their function signatures do not match and therefore the calls made, revert (see this link for a test case). Use OpenZeppelin’s SafeERC20
's safeTransfer()
/safeTransferFrom()
instead
There are 4 instances of this issue:
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
377 paymentToken.transfer(
378 paymentTokenBeneficiary,
379 paymentToken.balanceOf(address(this))
380: );
509 _paymentToken.transferFrom(
510 msg.sender,
511 address(this),
512 discountedPaymentAmount
513: );
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
491 paymentToken.transfer(
492 paymentTokenBeneficiary,
493 paymentToken.balanceOf(address(this))
494: );
530 _paymentToken.transferFrom(
531 msg.sender,
532 address(this),
533 discountedPaymentAmount
534: );
[M‑05] Use of transferFrom()
rather than safeTransferFrom()
for NFTs in will lead to the loss of NFTs
The EIP-721 standard says the following about transferFrom()
:
/// @notice Transfer ownership of an NFT -- THE CALLER IS RESPONSIBLE
/// TO CONFIRM THAT `_to` IS CAPABLE OF RECEIVING NFTS OR ELSE
/// THEY MAY BE PERMANENTLY LOST
/// @dev Throws unless `msg.sender` is the current owner, an authorized
/// operator, or the approved address for this NFT. Throws if `_from` is
/// not the current owner. Throws if `_to` is the zero address. Throws if
/// `_tokenId` is not a valid NFT.
/// @param _from The current owner of the NFT
/// @param _to The new owner
/// @param _tokenId The NFT to transfer
function transferFrom(address _from, address _to, uint256 _tokenId) external payable;
https://github.com/ethereum/EIPs/blob/78e2c297611f5e92b6a5112819ab71f74041ff25/EIPS/eip-721.md?plain=1#L103-L113
Code must use the safeTransferFrom()
flavor if it hasn't otherwise verified that the receiving address can handle it
There is one instance of this issue:
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
342: tOLP.transferFrom(address(this), otapOwner, oTAPPosition.tOLP);
Not all IERC20
implementations revert()
when there's a failure in transfer()
/transferFrom()
. The function signature has a boolean
return value and they indicate errors that way instead. By not checking the return value, operations that should have marked as failed, may potentially go through without actually making a payment
There are 6 instances of this issue:
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
377 paymentToken.transfer(
378 paymentTokenBeneficiary,
379 paymentToken.balanceOf(address(this))
380: );
509 _paymentToken.transferFrom(
510 msg.sender,
511 address(this),
512 discountedPaymentAmount
513: );
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
491 paymentToken.transfer(
492 paymentTokenBeneficiary,
493 paymentToken.balanceOf(address(this))
494: );
530 _paymentToken.transferFrom(
531 msg.sender,
532 address(this),
533 discountedPaymentAmount
534: );
File: tap-token-audit/contracts/tokens/LTap.sol
42: tapToken.transferFrom(msg.sender, address(this), amount);
50: tapToken.transfer(msg.sender, amount);
_mint()
is discouraged in favor of _safeMint()
which ensures that the recipient is either an EOA or implements IERC721Receiver
. Both OpenZeppelin and solmate have versions of this function. In the cases below, _mint()
does not call ERC721TokenReceiver.onERC721Received()
on the recipient.
There are 3 instances of this issue:
File: YieldBox/contracts/YieldBox.sol
139: _mint(to, assetId, share);
178: _mint(to, assetId, 1);
204: _mint(to, assetId, share);
In spite of the fact that EIP-20 states that zero-valued transfers must be accepted, some tokens, such as LEND will revert if this is attempted, which may cause transactions that involve other tokens (such as batch operations) to fully revert. Consider skipping the transfer if the amount is zero, which will also save gas.
There are 19 instances of this issue:
see instances
File: contracts/tOFT/BaseTOFT.sol
356 "TOFT_allowed"
357 );
358 }
359: IERC20(erc20).safeTransferFrom(_fromAddress, address(this), _amount);
371 if (erc20 == address(0)) {
372 _safeTransferETH(_toAddress, _amount);
373 } else {
374: IERC20(erc20).safeTransfer(_toAddress, _amount);
File: contracts/tOFT/mTapiocaOFT.sol
145 if (_isNative) {
146 _safeTransferETH(msg.sender, _amount);
147 } else {
148: IERC20(erc20).safeTransfer(msg.sender, _amount);
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
272 if (erc20 == address(0)) {
273 _safeTransferETH(_toAddress, _amount);
274 } else {
275: IERC20(erc20).safeTransfer(_toAddress, _amount);
File: contracts/Vesting.sol
116 users[msg.sender].claimed += _claimable;
117 users[msg.sender].latestClaimTimestamp = block.timestamp;
118
119: token.safeTransfer(msg.sender, _claimable);
File: contracts/governance/twTAP.sol
445 totals.totalDistPerVote[_rewardTokenId] +=
446 (_amount * DIST_PRECISION) /
447 uint256(totals.netActiveVotes);
448: rewardToken.safeTransferFrom(msg.sender, address(this), _amount);
489 if (amount > 0) {
490 // Math is safe: `amount` calculated safely in `claimable()`
491 claimed[_tokenId][i] += amount;
492: rewardTokens[i].safeTransfer(_to, amount);
511 if (amount > 0) {
512 // Math is safe: `amount` calculated safely in `claimable()`
513 claimed[_tokenId][claimableIndex] += amount;
514: rewardTokens[claimableIndex].safeTransfer(_to, amount);
File: contracts/option-airdrop/AirdropBroker.sol
374 unchecked {
375 for (uint256 i = 0; i < len; ++i) {
376 ERC20 paymentToken = ERC20(_paymentTokens[i]);
377 paymentToken.transfer(
378 paymentTokenBeneficiary,
379 paymentToken.balanceOf(address(this))
380: );
506 _paymentToken.decimals()
507 );
508
509 _paymentToken.transferFrom(
510 msg.sender,
511 address(this),
512 discountedPaymentAmount
513: );
File: contracts/options/TapiocaOptionBroker.sol
488 unchecked {
489 for (uint256 i = 0; i < len; ++i) {
490 ERC20 paymentToken = ERC20(_paymentTokens[i]);
491 paymentToken.transfer(
492 paymentTokenBeneficiary,
493 paymentToken.balanceOf(address(this))
494: );
527 _paymentToken.decimals()
528 );
529
530 _paymentToken.transferFrom(
531 msg.sender,
532 address(this),
533 discountedPaymentAmount
534: );
File: contracts/Magnetar/modules/MagnetarMarketModule.sol
420 (uint256 tOLPSglAssetId, , ) = ITapiocaOptionLiquidityProvision(
421 lockData.target
422 ).activeSingularities(address(singularity));
423 IERC20(address(singularity)).safeTransferFrom(
424 user,
425 address(this),
426 fraction
427: );
794 address _token,
795 uint256 _amount
796 ) private {
797: IERC20(_token).safeTransferFrom(_from, address(this), _amount);
File: contracts/Swapper/BaseSwapper.sol
159 );
160 return amount;
161 }
162: IERC20(token).safeTransferFrom(msg.sender, address(this), amount);
File: contracts/Swapper/CurveSwapper.sol
137 0
138 );
139 } else {
140: IERC20(tokenOut).safeTransfer(to, amountOut);
File: contracts/glp/GlpStrategy.sol
145 glpVester.withdraw();
146 }
147 // Call this first; `_vestByGlp()` will lock the GLP again
148: IERC20(contractAddress).safeTransfer(to, amount);
File: contracts/YieldBox.sol
141 // Interactions
142 if (asset.tokenType == TokenType.ERC20) {
143 // For ERC20 tokens, use the safe helper function to deal with broken ERC20 implementations. This actually calls transferFrom on the ERC20 contract.
144: IERC20(asset.contractAddress).safeTransferFrom(from, address(asset.strategy), amount);
206 // Interactions
207 wrappedNative.deposit{ value: amount }();
208 // Strategies always receive wrappedNative (supporting both wrapped and raw native tokens adds too much complexity)
209: wrappedNative.safeTransfer(address(asset.strategy), amount);
According to the Curve docs, StableSwap.calc_token_amount()
already includes slippage but not fees, so adding extra slippage on top of the returned result, as is done by the caller of functions higher up the caller chain, is an incorrect operation.
There is one instance of this issue:
File: contracts/curve/TricryptoLPGetter.sol
/// @audit TricryptoNativeStrategy._addLiquidityAndStake()
200 function _calcDepositInOneCoin(
201 uint256[3] memory arr
202 ) private view returns (uint256) {
203: return liquidityPool.calc_token_amount(arr, true);
Calling approve()
without first calling approve(0)
if the current approval is non-zero will revert with some tokens, such as Tether (USDT). While Tether is known to do this, it applies to other tokens as well, which are trying to protect against this attack vector. safeApprove()
itself also implements this protection.
Always reset the approval to zero before changing it to a new value, or use safeIncreaseAllowance()
/safeDecreaseAllowance()
There are 20 instances of this issue:
see instances
File: contracts/markets/bigBang/BigBang.sol
450: asset.approve(address(yieldBox), totalFees);
761: asset.approve(address(yieldBox), amount);
File: contracts/Balancer.sol
321: erc20.approve(address(router), _amount);
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
215: IERC20(erc20).approve(externalData.swapper, amount);
File: contracts/tOFT/modules/BaseTOFTStrategyModule.sol
184: _erc20.approve(address(yieldBox), _amount);
File: contracts/Magnetar/modules/MagnetarMarketModule.sol
157: IERC20(collateralAddress).approve(
234: IERC20(assetAddress).approve(address(yieldBox), depositAmount);
339: IERC20(bbCollateralAddress).approve(
386: IERC20(sglAssetAddress).approve(
File: contracts/aave/AaveStrategy.sol
76: rewardToken.approve(_multiSwapper, type(uint256).max);
File: contracts/convex/ConvexTricryptoStrategy.sol
108: rewardToken.approve(_multiSwapper, type(uint256).max);
172: rewardToken.approve(address(swapper), 0);
174: rewardToken.approve(_swapper, type(uint256).max);
File: contracts/curve/TricryptoLPStrategy.sol
79: lpToken.approve(_lpGauge, type(uint256).max);
81: rewardToken.approve(_multiSwapper, type(uint256).max);
143: rewardToken.approve(address(swapper), 0);
144: rewardToken.approve(_swapper, type(uint256).max);
File: contracts/curve/TricryptoNativeStrategy.sol
80: rewardToken.approve(_multiSwapper, type(uint256).max);
134: rewardToken.approve(address(swapper), 0);
135: rewardToken.approve(_swapper, type(uint256).max);
Low-level calls return success if there is no code present at the specified address. In addition to the zero-address checks, add a check to verify that <address>.code.length > 0
There are 29 instances of this issue:
see instances
File: contracts/Penrose.sol
444 (success[i], result[i]) = mc[i].call(data[i]);
445 if (forceSuccess) {
446 require(success[i], _getRevertMsg(result[i]));
447 }
448 ++i;
449: }
File: contracts/markets/bigBang/BigBang.sol
216 (bool success, bytes memory result) = address(this).delegatecall(
217 calls[i]
218 );
219 require(success || !revertOnFail, _getRevertMsg(result));
220 successes[i] = success;
221: results[i] = _getRevertMsg(result);
File: contracts/markets/singularity/Singularity.sol
188 (bool success, bytes memory result) = address(this).delegatecall(
189 calls[i]
190 );
191 require(success || !revertOnFail, _getRevertMsg(result));
192 successes[i] = success;
193: results[i] = _getRevertMsg(result);
625 (success, returnData) = module.delegatecall(_data);
626 if (!success) {
627 revert(_getRevertMsg(returnData));
628 }
629: }
638 (success, returnData) = module.staticcall(_data);
639 if (!success) {
640 revert(_getRevertMsg(returnData));
641 }
642: }
File: contracts/usd0/BaseUSDO.sol
369 (success, returnData) = module.delegatecall(_data);
370 if (!success && !_forwardRevert) {
371 revert(_getRevertMsg(returnData));
372 }
373: }
File: contracts/usd0/modules/USDOLeverageModule.sol
169 (bool success, bytes memory reason) = module.delegatecall(
170 abi.encodeWithSelector(
171 this.leverageUpInternal.selector,
172 amount,
173 swapData,
174: externalData,
File: contracts/usd0/modules/USDOMarketModule.sol
168 (bool success, bytes memory reason) = module.delegatecall(
169 abi.encodeWithSelector(
170 this.lendInternal.selector,
171 to,
172 lendParams,
173: approvals,
File: contracts/usd0/modules/USDOOptionsModule.sol
174 (bool success, bytes memory reason) = module.delegatecall(
175 abi.encodeWithSelector(
176 this.exerciseInternal.selector,
177 optionsData.from,
178 optionsData.oTAPTokenID,
179: optionsData.paymentToken,
File: contracts/TapiocaWrapper.sol
120 (success, result) = payable(_toft).call{value: msg.value}(_bytecode);
121 if (_revertOnFailure && !success) {
122 revert TapiocaWrapper__TOFTExecutionFailed(result);
123 }
124: }
141 (success, results[i]) = payable(_call[i].toft).call{
142 value: msg.value
143 }(_call[i].bytecode);
144 if (_call[i].revertOnFailure && !success) {
145 revert TapiocaWrapper__TOFTExecutionFailed(results[i]);
146: }
File: contracts/tOFT/BaseTOFT.sol
380 (bool sent, ) = to.call{value: amount}("");
381 require(sent, "TOFT_failed");
382: }
411 (success, returnData) = module.delegatecall(_data);
412 if (!success && !_forwardRevert) {
413 revert(_getRevertMsg(returnData));
414 }
415: }
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
184 (bool success, bytes memory reason) = module.delegatecall(
185 abi.encodeWithSelector(
186 this.leverageDownInternal.selector,
187 amount,
188 swapData,
189: externalData,
280 (bool sent, ) = to.call{value: amount}("");
281 require(sent, "TOFT_failed");
282: }
File: contracts/tOFT/modules/BaseTOFTMarketModule.sol
160 (bool success, bytes memory reason) = module.delegatecall(
161 abi.encodeWithSelector(
162 this.borrowInternal.selector,
163 _to,
164 borrowParams,
165: withdrawParams,
File: contracts/tOFT/modules/BaseTOFTOptionsModule.sol
189 (bool success, bytes memory reason) = module.delegatecall(
190 abi.encodeWithSelector(
191 this.exerciseInternal.selector,
192 optionsData.from,
193 optionsData.oTAPTokenID,
194: optionsData.paymentToken,
File: contracts/tOFT/modules/BaseTOFTStrategyModule.sol
152 (bool success, bytes memory reason) = module.delegatecall(
153 abi.encodeWithSelector(
154 this.depositToYieldbox.selector,
155 assetId,
156 amount,
157: share,
File: contracts/tokens/BaseTapOFT.sol
236 rewardClaimSendParams[i].callParams
237 );
238 ++i;
239 }
240 } catch Error(string memory _reason) {
241: emit CallFailedStr(_srcChainId, _payload, _reason);
File: contracts/Magnetar/MagnetarV2.sol
1045 (bool success, bytes memory returnData) = target.call(actionCalldata);
1046 if (!success && !allowFailure) {
1047 _getRevertMsg(returnData);
1048 }
1049: }
1071 (success, returnData) = module.delegatecall(_data);
1072 if (!success) {
1073 _getRevertMsg(returnData);
1074 }
1075: }
File: contracts/Multicall/Multicall3.sol
52 calli.callData
53 );
54 if (!result.success) {
55 _getRevertMsg(result.returnData);
56 }
57: unchecked {
51 (result.success, result.returnData) = calli.target.call(
52 calli.callData
53 );
54 if (!result.success) {
55 _getRevertMsg(result.returnData);
56: }
80 calli.callData
81 );
82 if (!result.success) {
83 _getRevertMsg(result.returnData);
84 }
85: unchecked {
79 (result.success, result.returnData) = calli.target.call{value: val}(
80 calli.callData
81 );
82 if (!result.success) {
83 _getRevertMsg(result.returnData);
84: }
File: contracts/Swapper/BaseSwapper.sol
99 (bool success, bytes memory data) = token.call(
100 abi.encodeWithSelector(0x095ea7b3, to, value)
101 );
102 require(
103 success && (data.length == 0 || abi.decode(data, (bool))),
104: "BaseSwapper::safeApprove: approve failed"
File: contracts/convex/ConvexTricryptoStrategy.sol
356 (bool successEmtptyApproval, ) = token.call(
357 abi.encodeWithSelector(
358 bytes4(keccak256("approve(address,uint256)")),
359 to,
360 0
361: )
369 (bool success, bytes memory data) = token.call(
370 abi.encodeWithSelector(
371 bytes4(keccak256("approve(address,uint256)")),
372 to,
373 value
374: )
File: contracts/curve/TricryptoLPStrategy.sol
105 (bool success, bytes memory response) = address(lpGauge).staticcall(
106 abi.encodeWithSignature("claimable_tokens(address)", address(this))
107 );
108 result = 0;
109 uint256 claimable = 0;
110: if (success) {
There is no limit specified on the amount of gas used, so the recipient can use up all of the transaction's gas, causing it to revert. Use addr.call{gas: <amount>}("")
or this library instead.
There are 12 instances of this issue:
see instances
File: contracts/Penrose.sol
/// @audit `executeMarketFn()`
444: (success[i], result[i]) = mc[i].call(data[i]);
File: contracts/TapiocaWrapper.sol
/// @audit `executeTOFT()`
120: (success, result) = payable(_toft).call{value: msg.value}(_bytecode);
/// @audit `executeCalls()`
141: (success, results[i]) = payable(_call[i].toft).call{
File: contracts/tOFT/BaseTOFT.sol
/// @audit `_safeTransferETH()`
380: (bool sent, ) = to.call{value: amount}("");
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
/// @audit `_safeTransferETH()`
280: (bool sent, ) = to.call{value: amount}("");
File: contracts/Magnetar/MagnetarV2.sol
/// @audit `burst()`
206: _action.call.length > 0,
/// @audit `_permit()`
1045: (bool success, bytes memory returnData) = target.call(actionCalldata);
File: contracts/Multicall/Multicall3.sol
/// @audit `multicall()`
51: (result.success, result.returnData) = calli.target.call(
/// @audit `multicallValue()`
79: (result.success, result.returnData) = calli.target.call{value: val}(
File: contracts/Swapper/BaseSwapper.sol
/// @audit `_safeApprove()`
99: (bool success, bytes memory data) = token.call(
File: contracts/convex/ConvexTricryptoStrategy.sol
/// @audit `_safeApprove()`
356: (bool successEmtptyApproval, ) = token.call(
/// @audit `_safeApprove()`
369: (bool success, bytes memory data) = token.call(
Dividing an integer by another integer will often result in loss of precision. When the result is multiplied by another number, the loss of precision is magnified, often to material magnitudes. (X / Z) * Y
should be re-written as (X * Y) / Z
There are 8 instances of this issue:
File: contracts/markets/Market.sol
290 uint256 denominator = ((10 ** ratesPrecision) -
291 (collateralizationRate *
292 ((10 ** ratesPrecision) + liquidationMultiplier)) /
293: (10 ** ratesPrecision)) * (10 ** (18 - ratesPrecision));
392 (userCollateralShare[user] *
393 (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
394: collateralizationRate),
392 (userCollateralShare[user] *
393: (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
417 collateralShare *
418 (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
419: collateralizationRate,
417 collateralShare *
418: (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
File: contracts/markets/singularity/SGLLiquidation.sol
83 (collateralShare *
84 (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
85: lqCollateralizationRate),
83 (collateralShare *
84: (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
File: contracts/oracle/implementations/ARBTriCryptoOracle.sol
137: uint256 _discount = Math.max((_g ** 2 / 1 ether) * _a, 1e34); // handle qbrt nonconvergence
The divisions below take an input parameter which does not have any zero-value checks, which may lead to the functions reverting when zero is passed.
There are 13 instances of this issue:
see instances
File: contracts/markets/Market.sol
387 uint256 _exchangeRate
388 ) internal view returns (uint256 collateralAmountInAsset) {
389 collateralAmountInAsset =
390 yieldBox.toAmount(
391 collateralId,
392 (userCollateralShare[user] *
393 (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
394 collateralizationRate),
395 false
396 ) /
397: _exchangeRate;
435 false
436 );
437
438: max = (collateralAmount * EXCHANGE_RATE_PRECISION) / _exchangeRate;
486 return 0;
487 }
488 uint256 _numerator = numerator * 10 ** (precision + 1);
489: uint256 _quotient = ((_numerator / denominator) + 5) / 10;
File: contracts/markets/bigBang/BigBang.sol
778 uint256 collateralShare
779 )
780 {
781 uint256 collateralPartInAsset = (yieldBox.toAmount(
782 collateralId,
783 userCollateralShare[user],
784 false
785: ) * EXCHANGE_RATE_PRECISION) / _exchangeRate;
File: contracts/markets/singularity/SGLLiquidation.sol
78
79 Rebase memory _totalBorrow = totalBorrow;
80
81 uint256 collateralAmountInAsset = yieldBox.toAmount(
82 collateralId,
83 (collateralShare *
84 (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
85 lqCollateralizationRate),
86 false
87: ) / _exchangeRate;
213 uint256 collateralShare
214 )
215 {
216 uint256 collateralPartInAsset = (yieldBox.toAmount(
217 collateralId,
218 userCollateralShare[user],
219 false
220: ) * EXCHANGE_RATE_PRECISION) / _exchangeRate;
File: contracts/option-airdrop/AirdropBroker.sol
527 uint256 _paymentTokenDecimals
528 ) internal pure returns (uint256 paymentAmount) {
529 // Calculate payment amount
530: uint256 rawPaymentAmount = _otcAmountInUSD / _paymentTokenValuation;
File: contracts/options/TapiocaOptionBroker.sol
548 uint256 _paymentTokenDecimals
549 ) internal pure returns (uint256 paymentAmount) {
550 // Calculate payment amount
551: uint256 rawPaymentAmount = _otcAmountInUSD / _paymentTokenValuation;
File: contracts/twAML.sol
138 if (_cumulative == 0) {
139 return _dMax;
140 }
141: uint256 target = (_magnitude * _dMax) / _cumulative;
File: contracts/YieldBoxRebase.sol
29 totalShares_ += 1e8;
30
31 // Calculte the shares using te current amount to share ratio
32: share = (amount * totalShares_) / totalAmount;
32 share = (amount * totalShares_) / totalAmount;
33
34 // Default is to round down (Solidity), round up if required
35: if (roundUp && (share * totalAmount) / totalShares_ < amount) {
52 totalShares_ += 1e8;
53
54 // Calculte the amount using te current amount to share ratio
55: amount = (share * totalAmount) / totalShares_;
55 amount = (share * totalAmount) / totalShares_;
56
57 // Default is to round down (Solidity), round up if required
58: if (roundUp && (amount * totalShares_) / totalAmount < share) {
Consider limiting the number of iterations in for-
loops that make external calls
There are 61 instances of this issue:
see instances
File: contracts/markets/singularity/SGLLiquidation.sol
128 uint256 collateralShare = yieldBox.toShare(
129 collateralId,
130 (amountWithBonus * _exchangeRate) / EXCHANGE_RATE_PRECISION,
131 false
132: );
File: contracts/usd0/modules/USDOLeverageModule.sol
289 IERC20Permit(approvals[i].target).permit(
290 approvals[i].owner,
291 approvals[i].spender,
292 approvals[i].value,
293 approvals[i].deadline,
294 approvals[i].v,
295 approvals[i].r,
296 approvals[i].s
297: )
274 IPermitAll(approvals[i].target).permitAll(
275 approvals[i].owner,
276 approvals[i].spender,
277 approvals[i].deadline,
278 approvals[i].v,
279 approvals[i].r,
280 approvals[i].s
281: )
258 IPermitBorrow(approvals[i].target).permitBorrow(
259 approvals[i].owner,
260 approvals[i].spender,
261 approvals[i].value,
262 approvals[i].deadline,
263 approvals[i].v,
264 approvals[i].r,
265 approvals[i].s
266: )
File: contracts/usd0/modules/USDOMarketModule.sol
278 IERC20Permit(approvals[i].target).permit(
279 approvals[i].owner,
280 approvals[i].spender,
281 approvals[i].value,
282 approvals[i].deadline,
283 approvals[i].v,
284 approvals[i].r,
285 approvals[i].s
286: )
263 IPermitAll(approvals[i].target).permitAll(
264 approvals[i].owner,
265 approvals[i].spender,
266 approvals[i].deadline,
267 approvals[i].v,
268 approvals[i].r,
269 approvals[i].s
270: )
247 IPermitBorrow(approvals[i].target).permitBorrow(
248 approvals[i].owner,
249 approvals[i].spender,
250 approvals[i].value,
251 approvals[i].deadline,
252 approvals[i].v,
253 approvals[i].r,
254 approvals[i].s
255: )
File: contracts/usd0/modules/USDOOptionsModule.sol
279 IERC20Permit(approvals[i].target).permit(
280 approvals[i].owner,
281 approvals[i].spender,
282 approvals[i].value,
283 approvals[i].deadline,
284 approvals[i].v,
285 approvals[i].r,
286 approvals[i].s
287: )
264 IPermitAll(approvals[i].target).permitAll(
265 approvals[i].owner,
266 approvals[i].spender,
267 approvals[i].deadline,
268 approvals[i].v,
269 approvals[i].r,
270 approvals[i].s
271: )
248 IPermitBorrow(approvals[i].target).permitBorrow(
249 approvals[i].owner,
250 approvals[i].spender,
251 approvals[i].value,
252 approvals[i].deadline,
253 approvals[i].v,
254 approvals[i].r,
255 approvals[i].s
256: )
File: contracts/TapiocaWrapper.sol
99: harvestableTapiocaOFTs[i].harvestFees();
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
319 IERC20Permit(approvals[i].target).permit(
320 approvals[i].owner,
321 approvals[i].spender,
322 approvals[i].value,
323 approvals[i].deadline,
324 approvals[i].v,
325 approvals[i].r,
326 approvals[i].s
327: )
304 IPermitAll(approvals[i].target).permitAll(
305 approvals[i].owner,
306 approvals[i].spender,
307 approvals[i].deadline,
308 approvals[i].v,
309 approvals[i].r,
310 approvals[i].s
311: )
288 IPermitBorrow(approvals[i].target).permitBorrow(
289 approvals[i].owner,
290 approvals[i].spender,
291 approvals[i].value,
292 approvals[i].deadline,
293 approvals[i].v,
294 approvals[i].r,
295 approvals[i].s
296: )
File: contracts/tOFT/modules/BaseTOFTMarketModule.sol
295 IERC20Permit(approvals[i].target).permit(
296 approvals[i].owner,
297 approvals[i].spender,
298 approvals[i].value,
299 approvals[i].deadline,
300 approvals[i].v,
301 approvals[i].r,
302 approvals[i].s
303: )
280 IPermitAll(approvals[i].target).permitAll(
281 approvals[i].owner,
282 approvals[i].spender,
283 approvals[i].deadline,
284 approvals[i].v,
285 approvals[i].r,
286 approvals[i].s
287: )
264 IPermitBorrow(approvals[i].target).permitBorrow(
265 approvals[i].owner,
266 approvals[i].spender,
267 approvals[i].value,
268 approvals[i].deadline,
269 approvals[i].v,
270 approvals[i].r,
271 approvals[i].s
272: )
File: contracts/tOFT/modules/BaseTOFTOptionsModule.sol
294 IERC20Permit(approvals[i].target).permit(
295 approvals[i].owner,
296 approvals[i].spender,
297 approvals[i].value,
298 approvals[i].deadline,
299 approvals[i].v,
300 approvals[i].r,
301 approvals[i].s
302: )
279 IPermitAll(approvals[i].target).permitAll(
280 approvals[i].owner,
281 approvals[i].spender,
282 approvals[i].deadline,
283 approvals[i].v,
284 approvals[i].r,
285 approvals[i].s
286: )
263 IPermitBorrow(approvals[i].target).permitBorrow(
264 approvals[i].owner,
265 approvals[i].spender,
266 approvals[i].value,
267 approvals[i].deadline,
268 approvals[i].v,
269 approvals[i].r,
270 approvals[i].s
271: )
File: contracts/option-airdrop/AirdropBroker.sol
377 paymentToken.transfer(
378 paymentTokenBeneficiary,
379 paymentToken.balanceOf(address(this))
380: );
379: paymentToken.balanceOf(address(this))
File: contracts/options/TapiocaOptionBroker.sol
491 paymentToken.transfer(
492 paymentTokenBeneficiary,
493 paymentToken.balanceOf(address(this))
494: );
493: paymentToken.balanceOf(address(this))
File: contracts/tokens/BaseTapOFT.sol
229 ISendFrom(address(rewardTokens[i])).sendFrom{
230 value: rewardClaimSendParams[i].ethValue
231 }(
232 address(this),
233 _srcChainId,
234 LzLib.addressToBytes32(to),
235 IERC20(rewardTokens[i]).balanceOf(address(this)),
236 rewardClaimSendParams[i].callParams
237: );
235: IERC20(rewardTokens[i]).balanceOf(address(this)),
335 IERC20Permit(approvals[i].target).permit(
336 approvals[i].owner,
337 approvals[i].spender,
338 approvals[i].value,
339 approvals[i].deadline,
340 approvals[i].v,
341 approvals[i].r,
342 approvals[i].s
343: )
File: contracts/Magnetar/MagnetarV2.sol
699 IUSDOBase(_action.target).removeAsset(
700 data.from,
701 data.to,
702 data.lzDstChainId,
703 data.zroPaymentAddress,
704 data.adapterParams,
705 data.externalData,
706 data.removeAndRepayData,
707 data.approvals
708: );
683 IUSDOBase(_action.target).initMultiHopBuy(
684 data.from,
685 data.collateralAmount,
686 data.borrowAmount,
687 data.swapData,
688 data.lzData,
689 data.externalData,
690 data.airdropAdapterParams,
691 data.approvals
692: );
667 IUSDOBase(_action.target).initMultiHopBuy(
668 data.from,
669 data.collateralAmount,
670 data.borrowAmount,
671 data.swapData,
672 data.lzData,
673 data.externalData,
674 data.airdropAdapterParams,
675 data.approvals
676: );
655 ITapiocaOptionsBrokerCrossChain(_action.target).exerciseOption(
656 data.optionsData,
657 data.lzData,
658 data.tapSendData,
659 data.approvals
660: );
642 IMarket(data.market).sellCollateral(
643 data.from,
644 data.share,
645 data.minAmountOut,
646 address(data.swapper),
647 data.dexData
648: );
628 IMarket(data.market).buyCollateral(
629 data.from,
630 data.borrowAmount,
631 data.supplyAmount,
632 data.minAmountOut,
633 address(data.swapper),
634 data.dexData
635: );
517 ITapiocaOFT(_action.target).retrieveFromStrategy{
518 value: _action.value
519 }(
520 msg.sender,
521 amount,
522 share,
523 assetId,
524 lzDstChainId,
525 zroPaymentAddress,
526 airdropAdapterParam
527: );
482 ITapiocaOFT(_action.target).sendToStrategy{
483 value: _action.value
484 }(
485 msg.sender,
486 data.to,
487 data.amount,
488 data.share,
489 data.assetId,
490 data.lzDstChainId,
491 data.options
492: );
463 IUSDOBase(_action.target).sendAndLendOrRepay{
464 value: _action.value
465 }(
466 msg.sender,
467 to,
468 dstChainId,
469 zroPaymentAddress,
470 lendParams,
471 approvals,
472 withdrawParams,
473 adapterParams
474: );
426 ITapiocaOFT(_action.target).sendToYBAndBorrow{
427 value: _action.value
428 }(
429 msg.sender,
430 to,
431 lzDstChainId,
432 airdropAdapterParams,
433 borrowParams,
434 withdrawParams,
435 options,
436 approvals
437: );
391 uint256 amount = IMarket(_action.target).repay(
392 msg.sender,
393 data.to,
394 data.skim,
395 data.part
396: );
374 uint256 fraction = IMarket(_action.target).addAsset(
375 msg.sender,
376 data.to,
377 data.skim,
378 data.share
379: );
316 (uint256 part, uint256 share) = IMarket(_action.target).borrow(
317 msg.sender,
318 data.to,
319 data.amount
320: );
302 IMarket(_action.target).addCollateral(
303 msg.sender,
304 data.to,
305 data.skim,
306 data.amount,
307 data.share
308: );
282 (uint256 amountOut, uint256 shareOut) = IYieldBoxBase(
283 _action.target
284 ).depositAsset(
285 data.assetId,
286 msg.sender,
287 data.to,
288 data.amount,
289 data.share
290: );
268 ISendFrom(_action.target).sendFrom{value: _action.value}(
269 msg.sender,
270 dstChainId,
271 to,
272 amount,
273 lzCallParams
274: );
243 ITapiocaOFT(_action.target).wrap(
244 msg.sender,
245 data.to,
246 data.amount
247: );
239 ITapiocaOFT(_action.target).wrapNative{
240 value: _action.value
241: }(data.to);
978 (uint128 totalAssetElastic, uint128 totalAssetBase) = sgl //
979: .totalAsset(); //
982: result[i].userAssetFraction = sgl.balanceOf(who); //
987: ) = sgl.getInterestDetails();
1008: (uint64 debtRate, uint64 lastAccrued) = bigBang.accrueInfo();
1011: result[i].minDebtRate = bigBang.minDebtRate();
1012: result[i].maxDebtRate = bigBang.maxDebtRate();
1013 result[i].debtRateAgainstEthMarket = bigBang
1014: .debtRateAgainstEthMarket();
1015: result[i].currentDebtRate = bigBang.getDebtRate();
1017: IPenrose penrose = IPenrose(bigBang.penrose());
1018: result[i].mainBBMarket = penrose.bigBangEthMarket();
1019: result[i].mainBBDebtRate = penrose.bigBangEthDebtRate();
File: contracts/convex/ConvexTricryptoStrategy.sol
198 ISwapper.SwapData memory swapData = swapper.buildSwapData(
199 tokens[i],
200 address(wrappedNative),
201 rewards[i],
202 0,
203 false,
204 false
205: );
206: uint256 calcAmount = swapper.getOutputAmount(swapData, "");
208: swapper.swap(swapData, minAmount, address(this), "");
256 balancesBefore[i] = IERC20(tempData.tokens[i]).balanceOf(
257 address(this)
258: );
274 balancesAfter[i] = IERC20(tempData.tokens[i]).balanceOf(
275 address(this)
276: );
Consider adding minimum/maximum value checks to ensure that the state variables below can never be used to excessively harm users, including via griefing
There are 3 instances of this issue:
File: contracts/markets/bigBang/BigBang.sol
159: maxDebtRate = _debtRateMax;
160: minDebtRate = _debtRateMin;
File: contracts/tokens/LTap.sol
38: maxLockedUntil = _maxLockedUntil;
There are 46 instances of this issue:
see instances
File: contracts/Penrose.sol
92: yieldBox = _yieldBox;
93: tapToken = tapToken_;
94: owner = _owner;
113: wethToken = wethToken_;
264: bigBangEthMarket = _market;
456: feeTo = feeTo_;
570: markets[marketIndex] = clonesOf[mcLocation][j];
File: contracts/markets/bigBang/BigBang.sol
127: penrose = tapiocaBar_;
File: contracts/markets/singularity/Singularity.sol
96: penrose = tapiocaBar_;
File: contracts/usd0/BaseUSDOStorage.sol
80: yieldBox = _yieldBox;
File: contracts/tOFT/BaseTOFTStorage.sol
61: erc20 = _erc20;
64: yieldBox = _yieldBox;
File: contracts/Vesting.sol
72: owner = _owner;
156: token = _token;
File: contracts/option-airdrop/AirdropBroker.sol
105: paymentTokenBeneficiary = _paymentTokenBeneficiary;
109: owner = _owner;
312: tapOracle = _tapOracle;
349: paymentTokens[_paymentToken].oracle = _oracle;
360: paymentTokenBeneficiary = _paymentTokenBeneficiary;
File: contracts/option-airdrop/aoTAP.sol
42: owner = _owner;
File: contracts/options/TapiocaOptionBroker.sol
89: paymentTokenBeneficiary = _paymentTokenBeneficiary;
94: owner = _owner;
450: tapOracle = _tapOracle;
463: paymentTokens[_paymentToken].oracle = _oracle;
474: paymentTokenBeneficiary = _paymentTokenBeneficiary;
File: contracts/options/TapiocaOptionLiquidityProvision.sol
75: owner = _owner;
File: contracts/tokens/LTap.sol
36: tapToken = _tapToken;
File: contracts/Swapper/CurveSwapper.sol
40: curvePool = _curvePool;
41: yieldBox = _yieldBox;
File: contracts/Swapper/UniswapV2Swapper.sol
41: yieldBox = _yieldBox;
File: contracts/Swapper/UniswapV3Swapper.sol
54: yieldBox = _yieldBox;
55: swapRouter = _swapRouter;
56: factory = _factory;
File: contracts/oracle/implementations/ARBTriCryptoOracle.sol
55: TRI_CRYPTO = pool;
56: BTC_FEED = btcFeed;
57: ETH_FEED = ethFeed;
58: USDT_FEED = usdtFeed;
59: WBTC_FEED = wbtcFeed;
File: contracts/oracle/implementations/GLPOracle.sol
11: glpManager = glpManager_;
File: contracts/oracle/implementations/SGOracle.sol
38: SG_POOL = pool;
39: UNDERLYING = _underlying;
File: contracts/glp/GlpStrategy.sol
82: feeRecipient = owner;
114: feeRecipient = recipient;
File: contracts/stargate/StargateStrategy.sol
79: stgEthPool = _stgEthPool;
File: contracts/YieldBox.sol
92: wrappedNative = wrappedNative_;
93: uriBuilder = uriBuilder_;
Fees/rates should be required to be below 100%, preferably at a much lower limit, to ensure users don't have to monitor the blockchain for changes prior to using the protocol
There are 2 instances of this issue:
File: contracts/Penrose.sol
256 function setBigBangEthMarketDebtRate(uint256 _rate) external onlyOwner {
257 bigBangEthDebtRate = _rate;
258 emit BigBangEthMarketDebtRate(_rate);
259: }
File: contracts/Swapper/UniswapV3Swapper.sol
61 function setPoolFee(uint24 _newFee) external onlyOwner {
62 emit PoolFee(poolFee, _newFee);
63 poolFee = _newFee;
64: }
The compiler for Solidity 0.8.20 switches the default target EVM version to Shanghai, which includes the new PUSH0
op code. This op code may not yet be implemented on all L2s, so deployment on these chains will fail. To work around this issue, use an earlier EVM version. While the project itself may or may not compile with 0.8.20, other projects with which it integrates, or which extend this project may, and those projects will have problems deploying these contracts/libraries.
There are 67 instances of this issue:
see instances
File: contracts/Penrose.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/Market.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/MarketERC20.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/bigBang/BigBang.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/singularity/SGLBorrow.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/singularity/SGLCollateral.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/singularity/SGLCommon.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/singularity/SGLLendingCommon.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/singularity/SGLLeverage.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/singularity/SGLLiquidation.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/singularity/SGLStorage.sol
2: pragma solidity ^0.8.18;
File: contracts/markets/singularity/Singularity.sol
2: pragma solidity ^0.8.18;
File: contracts/usd0/BaseUSDO.sol
2: pragma solidity ^0.8.18;
File: contracts/usd0/BaseUSDOStorage.sol
2: pragma solidity ^0.8.18;
File: contracts/usd0/USDO.sol
2: pragma solidity ^0.8.18;
File: contracts/usd0/modules/USDOLeverageModule.sol
2: pragma solidity ^0.8.18;
File: contracts/usd0/modules/USDOMarketModule.sol
2: pragma solidity ^0.8.18;
File: contracts/usd0/modules/USDOOptionsModule.sol
2: pragma solidity ^0.8.18;
File: contracts/Balancer.sol
2: pragma solidity ^0.8.18;
File: contracts/TapiocaWrapper.sol
2: pragma solidity ^0.8.18;
File: contracts/tOFT/BaseTOFT.sol
2: pragma solidity ^0.8.18;
File: contracts/tOFT/BaseTOFTStorage.sol
2: pragma solidity ^0.8.18;
File: contracts/tOFT/TapiocaOFT.sol
2: pragma solidity ^0.8.18;
File: contracts/tOFT/mTapiocaOFT.sol
2: pragma solidity ^0.8.18;
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
2: pragma solidity ^0.8.18;
File: contracts/tOFT/modules/BaseTOFTMarketModule.sol
2: pragma solidity ^0.8.18;
File: contracts/tOFT/modules/BaseTOFTOptionsModule.sol
2: pragma solidity ^0.8.18;
File: contracts/tOFT/modules/BaseTOFTStrategyModule.sol
2: pragma solidity ^0.8.18;
File: contracts/Vesting.sol
2: pragma solidity ^0.8.18;
File: contracts/option-airdrop/AirdropBroker.sol
2: pragma solidity ^0.8.18;
File: contracts/option-airdrop/aoTAP.sol
2: pragma solidity ^0.8.18;
File: contracts/options/TapiocaOptionBroker.sol
2: pragma solidity ^0.8.18;
File: contracts/options/TapiocaOptionLiquidityProvision.sol
2: pragma solidity ^0.8.18;
File: contracts/options/oTAP.sol
2: pragma solidity ^0.8.18;
File: contracts/tokens/BaseTapOFT.sol
2: pragma solidity ^0.8.18;
File: contracts/tokens/LTap.sol
2: pragma solidity ^0.8.18;
File: contracts/tokens/TapOFT.sol
2: pragma solidity ^0.8.18;
File: contracts/twAML.sol
2: pragma solidity ^0.8.18;
File: contracts/Magnetar/MagnetarV2.sol
2: pragma solidity ^0.8.18;
File: contracts/Magnetar/MagnetarV2Storage.sol
2: pragma solidity ^0.8.18;
File: contracts/Magnetar/modules/MagnetarMarketModule.sol
2: pragma solidity ^0.8.18;
File: contracts/Multicall/Multicall3.sol
2: pragma solidity ^0.8.18;
File: contracts/Swapper/BaseSwapper.sol
2: pragma solidity ^0.8.18;
File: contracts/Swapper/CurveSwapper.sol
2: pragma solidity ^0.8.18;
File: contracts/Swapper/UniswapV2Swapper.sol
2: pragma solidity ^0.8.18;
File: contracts/Swapper/UniswapV3Swapper.sol
2: pragma solidity ^0.8.18;
File: contracts/TapiocaDeployer/TapiocaDeployer.sol
2: pragma solidity ^0.8.18;
File: contracts/oracle/Seer.sol
2: pragma solidity ^0.8.18;
File: contracts/oracle/implementations/ARBTriCryptoOracle.sol
2: pragma solidity ^0.8.9;
File: contracts/oracle/implementations/GLPOracle.sol
2: pragma solidity >=0.8.0;
File: contracts/oracle/implementations/SGOracle.sol
2: pragma solidity ^0.8.9;
File: contracts/aave/AaveStrategy.sol
2: pragma solidity ^0.8.18;
File: contracts/balancer/BalancerStrategy.sol
2: pragma solidity ^0.8.18;
File: contracts/compound/CompoundStrategy.sol
2: pragma solidity ^0.8.18;
File: contracts/convex/ConvexTricryptoStrategy.sol
2: pragma solidity ^0.8.18;
File: contracts/curve/TricryptoLPStrategy.sol
2: pragma solidity ^0.8.18;
File: contracts/curve/TricryptoNativeStrategy.sol
2: pragma solidity ^0.8.18;
File: contracts/glp/GlpStrategy.sol
2: pragma solidity ^0.8.18;
File: contracts/lido/LidoEthStrategy.sol
2: pragma solidity ^0.8.18;
File: contracts/stargate/StargateStrategy.sol
2: pragma solidity ^0.8.18;
File: contracts/yearn/YearnStrategy.sol
2: pragma solidity ^0.8.18;
File: contracts/BoringMath.sol
2: pragma solidity ^0.8.9;
File: contracts/NativeTokenFactory.sol
2: pragma solidity ^0.8.9;
File: contracts/YieldBox.sol
24: pragma solidity ^0.8.9;
File: contracts/YieldBoxPermit.sol
3: pragma solidity ^0.8.0;
File: contracts/YieldBoxRebase.sol
3: pragma solidity ^0.8.9;
File: contracts/YieldBoxURIBuilder.sol
2: pragma solidity ^0.8.9;
A copy-paste error or a typo may end up bricking protocol functionality, or sending tokens to an address with no known private key. Consider implementing a two-step procedure for updating protocol addresses, where the recipient is set as pending, and must 'accept' the assignment by making an affirmative call. A straight forward way of doing this would be to have the target contracts implement EIP-165, and to have the 'set' functions ensure that the recipient is of the right interface type.
There are 7 instances of this issue:
File: contracts/Penrose.sol
263 function setBigBangEthMarket(address _market) external onlyOwner {
264 bigBangEthMarket = _market;
265 emit BigBangEthMarketSet(_market);
266: }
455 function setFeeTo(address feeTo_) external onlyOwner {
456 feeTo = feeTo_;
457 emit FeeToUpdate(feeTo_);
458: }
File: contracts/option-airdrop/AirdropBroker.sol
308 function setTapOracle(
309 IOracle _tapOracle,
310 bytes calldata _tapOracleData
311 ) external onlyOwner {
312 tapOracle = _tapOracle;
313 tapOracleData = _tapOracleData;
314
315 emit SetTapOracle(_tapOracle, _tapOracleData);
316: }
357 function setPaymentTokenBeneficiary(
358 address _paymentTokenBeneficiary
359 ) external onlyOwner {
360 paymentTokenBeneficiary = _paymentTokenBeneficiary;
361: }
File: contracts/options/TapiocaOptionBroker.sol
446 function setTapOracle(
447 IOracle _tapOracle,
448 bytes calldata _tapOracleData
449 ) external onlyOwner {
450 tapOracle = _tapOracle;
451 tapOracleData = _tapOracleData;
452
453 emit SetTapOracle(_tapOracle, _tapOracleData);
454: }
471 function setPaymentTokenBeneficiary(
472 address _paymentTokenBeneficiary
473 ) external onlyOwner {
474 paymentTokenBeneficiary = _paymentTokenBeneficiary;
475: }
File: contracts/glp/GlpStrategy.sol
113 function setFeeRecipient(address recipient) external onlyOwner {
114 feeRecipient = recipient;
115: }
When a type is downcast to a smaller type, the higher order bits are truncated, effectively applying a modulo to the original value. Without any other checks, this wrapping will lead to unexpected behavior and bugs
There are 64 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
/// @audit uint64
521: _accrueInfo.debtRate = uint64(annumDebtRate / 31536000); //per second
/// @audit uint64
523: _accrueInfo.lastAccrued = uint64(block.timestamp);
/// @audit uint256 extraAmount -> uint128
535: _totalBorrow.elastic += uint128(extraAmount);
/// @audit uint256 borrowAmount -> uint128
822: totalBorrow.elastic -= uint128(borrowAmount);
/// @audit uint256 borrowPart -> uint128
823: totalBorrow.base -= uint128(borrowPart);
File: tapioca-bar-audit/contracts/markets/singularity/SGLCommon.sol
/// @audit uint64
79: _accrueInfo.lastAccrued = uint64(block.timestamp);
/// @audit uint256 extraAmount -> uint128
104: _totalBorrow.elastic += uint128(extraAmount);
/// @audit uint256 feeFraction -> uint128
108: _accrueInfo.feesEarnedFraction += uint128(feeFraction);
/// @audit uint256 feeFraction -> uint128
109: _totalAsset.base = _totalAsset.base + uint128(feeFraction);
/// @audit uint64
117 _accrueInfo.interestPerSecond = uint64(
118 (uint256(_accrueInfo.interestPerSecond) * interestElasticity) /
119 scale
120: );
/// @audit uint256 newInterestPerSecond -> uint64
135: _accrueInfo.interestPerSecond = uint64(newInterestPerSecond);
/// @audit uint256 fraction -> uint128
210: if (_totalAsset.base + uint128(fraction) < 1000) {
/// @audit uint256 share -> uint128
238: _totalAsset.elastic -= uint128(share);
/// @audit uint256 fraction -> uint128
239: _totalAsset.base -= uint128(fraction);
File: tapioca-bar-audit/contracts/markets/singularity/SGLLendingCommon.sol
/// @audit uint256 share -> uint128
76: _totalAsset.elastic -= uint128(share);
/// @audit uint256 share -> uint128
96: totalAsset.elastic = totalShare + uint128(share);
File: tapioca-bar-audit/contracts/markets/singularity/SGLLiquidation.sol
/// @audit uint256 allBorrowAmount -> uint128
154: _totalBorrow.elastic -= uint128(allBorrowAmount);
/// @audit uint256 allBorrowPart -> uint128
155: _totalBorrow.base -= uint128(allBorrowPart);
/// @audit uint128
195: totalAsset.elastic += uint128(returnedShare - callerShare);
/// @audit uint256 borrowAmount -> uint128
266: totalBorrow.elastic -= uint128(borrowAmount);
/// @audit uint256 borrowPart -> uint128
267: totalBorrow.base -= uint128(borrowPart);
/// @audit uint128
284: totalAsset.elastic += uint128(returnedShare - feeShare - callerShare);
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
/// @audit uint64
117: accrueInfo.interestPerSecond = uint64(startingInterestPerSecond); // 1% APR, with 1e18 being 100%
File: tapioca-bar-audit/contracts/Penrose.sol
/// @audit uint96
104 tapAssetId = uint96(
105 _yieldBox.registerAsset(
106 TokenType.ERC20,
107 address(tapToken_),
108 emptyStrategies[address(tapToken_)],
109 0
110 )
111: );
/// @audit uint96
122 wethAssetId = uint96(
123 _yieldBox.registerAsset(
124 TokenType.ERC20,
125 address(wethToken_),
126 emptyStrategies[address(wethToken_)],
127 0
128 )
129: );
/// @audit uint96
302 usdoAssetId = uint96(
303 yieldBox.registerAsset(
304 TokenType.ERC20,
305 _usdoToken,
306 emptyStrategies[_usdoToken],
307 0
308 )
309: );
File: tap-token-audit/contracts/governance/twTAP.sol
/// @audit uint256 expiry -> uint56
333: expiry: uint56(expiry),
/// @audit uint256 _amount -> uint88
334: tapAmount: uint88(_amount),
/// @audit uint256 multiplier -> uint24
335: multiplier: uint24(multiplier),
/// @audit uint256 w0 -> uint40
336: lastInactive: uint40(w0),
/// @audit uint256 w1 -> uint40
337: lastActive: uint40(w1)
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
/// @audit uint64
287: lastEpochUpdate = uint64(block.timestamp);
/// @audit uint256 _epochTAPValuation -> uint128
292: epochTAPValuation = uint128(_epochTAPValuation);
/// @audit uint128
398: uint128 expiry = uint128(lastEpochUpdate + EPOCH_DURATION); // Set expiry to the end of the epoch
/// @audit uint256 PHASE_1_DISCOUNT -> uint128
402: uint128(PHASE_1_DISCOUNT),
/// @audit uint128
433: uint128 expiry = uint128(lastEpochUpdate + EPOCH_DURATION); // Set expiry to the end of the epoch
/// @audit uint128
435: uint128 discount = uint128(PHASE_2_DISCOUNT_PER_USER[_role]) * 1e4;
/// @audit uint256 _tokenID -> uint160
448: address tokenIDToAddress = address(uint160(_tokenID));
/// @audit uint128
458: uint128 expiry = uint128(lastEpochUpdate + EPOCH_DURATION); // Set expiry to the end of the epoch
/// @audit uint256 PHASE_3_DISCOUNT -> uint128
460: uint128 discount = uint128(PHASE_3_DISCOUNT);
/// @audit uint128
473: uint128 expiry = uint128(lastEpochUpdate + EPOCH_DURATION); // Set expiry to the end of the epoch
/// @audit uint256 PHASE_4_DISCOUNT -> uint128
477: uint128(PHASE_4_DISCOUNT),
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
/// @audit uint256 target -> uint128
282: uint128(target),
File: tap-token-audit/contracts/options/TapiocaOptionLiquidityProvision.sol
/// @audit uint128
195: lockPosition.lockTime = uint128(block.timestamp);
/// @audit uint256 sglAssetID -> uint128
196: lockPosition.sglAssetID = uint128(sglAssetID);
/// @audit uint256 sglAssetID -> uint128
200: emit Mint(_to, uint128(sglAssetID), lockPosition);
File: tapioca-periph-audit/contracts/Swapper/CurveSwapper.sol
/// @audit int128 -> int256
/// @audit int256
72: int128(int256(tokenIndexes[0])),
/// @audit int128 -> int256
/// @audit int256
73: int128(int256(tokenIndexes[1])),
/// @audit int128 -> int256
/// @audit int256
125: int128(int256(tokenIndexes[0])),
/// @audit int128 -> int256
/// @audit int256
126: int128(int256(tokenIndexes[1])),
File: tapioca-periph-audit/contracts/Swapper/UniswapV3Swapper.sol
/// @audit uint256 amountIn -> uint128
101: uint128(amountIn),
/// @audit uint256 amountOut -> uint128
129: uint128(amountOut),
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
/// @audit uint256 lpRouterPid -> uint16
202: uint16(lpRouterPid),
/// @audit uint256 lpRouterPid -> uint16
254: uint16(lpRouterPid),
File: YieldBox/contracts/BoringMath.sol
/// @audit uint256 a -> uint128
7: c = uint128(a);
/// @audit uint256 a -> uint64
12: c = uint64(a);
/// @audit uint256 a -> uint32
17: c = uint32(a);
File: YieldBox/contracts/YieldBoxURIBuilder.sol
/// @audit uint160
37: uint256(uint160(asset.contractAddress)).toHexString(20),
/// @audit uint160
90: abi.encodePacked("ERC1155:", uint256(uint160(asset.contractAddress)).toHexString(20), "/", asset.tokenId.toString())
/// @audit uint160
106: ? abi.encodePacked(',"tokenAddress":"', uint256(uint160(asset.contractAddress)).toHexString(20), '"')
Division by large numbers may result in the result being zero, due to solidity not supporting fractions. Consider requiring a minimum amount for the numerator to ensure that it is always larger than the denominator
There are 121 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
187 uint256 _maxDebtPoint = (_ethMarketTotalDebt *
188: debtRateAgainstEthMarket) / 1e18;
192 uint256 debtPercentage = ((_currentDebt - debtStartPoint) *
193: DEBT_PRECISION) / (_maxDebtPoint - debtStartPoint);
194 uint256 debt = ((maxDebtRate - minDebtRate) * debtPercentage) /
195: DEBT_PRECISION +
521: _accrueInfo.debtRate = uint64(annumDebtRate / 31536000); //per second
531 (uint256(_totalBorrow.elastic) *
532 _accrueInfo.debtRate *
533 elapsedTime) /
534: 1e18;
645: feeShare = (extraShare * protocolFee) / FEE_PRECISION; // x% of profit goes to fee.
646: callerShare = (extraShare * callerReward) / FEE_PRECISION; // y% of profit goes to caller.
747: uint256 feeAmount = (amount * borrowOpeningFee) / FEE_PRECISION; // A flat % fee is charged for any borrow
781 uint256 collateralPartInAsset = (yieldBox.toAmount(
782 collateralId,
783 userCollateralShare[user],
784 false
785: ) * EXCHANGE_RATE_PRECISION) / _exchangeRate;
809 (borrowAmount * liquidationMultiplier) /
810: FEE_PRECISION;
813: (amountWithBonus * _exchangeRate) / EXCHANGE_RATE_PRECISION,
File: tapioca-bar-audit/contracts/markets/Market.sol
265: borrowPartScaled = borrowPart / (10 ** (borrowPartDecimals - 18));
274 collateralPartInAsset /
275: (10 ** (collateralPartDecimals - 18));
283 uint256 liquidationStartsAt = (collateralPartInAssetScaled *
284: collateralizationRate) / (10 ** ratesPrecision);
288 ((collateralizationRate * collateralPartInAssetScaled) /
289: (10 ** ratesPrecision));
291 (collateralizationRate *
292 ((10 ** ratesPrecision) + liquidationMultiplier)) /
293: (10 ** ratesPrecision)) * (10 ** (18 - ratesPrecision));
295: uint256 x = (numerator * 1e18) / denominator;
323: borrowPart = (borrowPart * _totalBorrow.elastic) / _totalBorrow.base;
390 yieldBox.toAmount(
391 collateralId,
392 (userCollateralShare[user] *
393 (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
394 collateralizationRate),
395 false
396 ) /
397: _exchangeRate;
393: (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
418: (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
423 (borrowPart * _totalBorrow.elastic * _exchangeRate) /
424: _totalBorrow.base;
438: max = (collateralAmount * EXCHANGE_RATE_PRECISION) / _exchangeRate;
439: min = (max * collateralizationRate) / FEE_PRECISION;
453 uint256 rewardPercentage = ((borrowed - startTVLInAsset) *
454: FEE_PRECISION) / (maxTVLInAsset - startTVLInAsset);
457 int256 reward = (diff * int256(rewardPercentage)) /
458: int256(FEE_PRECISION) +
477: return (shareRatio * userCollateralShare[user]) / (10 ** assetDecimals);
489: uint256 _quotient = ((_numerator / denominator) + 5) / 10;
File: tapioca-bar-audit/contracts/markets/singularity/SGLCommon.sol
63 : (uint256(_totalBorrow.elastic) * UTILIZATION_PRECISION) /
64: fullAssetAmount;
100 (uint256(_totalBorrow.elastic) *
101 _accrueInfo.interestPerSecond *
102 elapsedTime) /
103: 1e18;
106: uint256 feeAmount = (extraAmount * protocolFee) / FEE_PRECISION; // % of interest paid goes to fee
107: feeFraction = (feeAmount * _totalAsset.base) / fullAssetAmount;
113 uint256 underFactor = ((minimumTargetUtilization - utilization) *
114: FACTOR_PRECISION) / minimumTargetUtilization;
118 (uint256(_accrueInfo.interestPerSecond) * interestElasticity) /
119: scale
125 uint256 overFactor = ((utilization - maximumTargetUtilization) *
126: FACTOR_PRECISION) / fullUtilizationMinusMax;
129 uint256 newInterestPerSecond = (uint256(
130 _accrueInfo.interestPerSecond
131: ) * scale) / interestElasticity;
209: : (share * _totalAsset.base) / allShare;
235: share = (fraction * allShare) / _totalAsset.base;
File: tapioca-bar-audit/contracts/markets/singularity/SGLLendingCommon.sol
63: uint256 feeAmount = (amount * borrowOpeningFee) / FEE_PRECISION; // A flat % fee is charged for any borrow
File: tapioca-bar-audit/contracts/markets/singularity/SGLLiquidation.sol
81 uint256 collateralAmountInAsset = yieldBox.toAmount(
82 collateralId,
83 (collateralShare *
84 (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
85 lqCollateralizationRate),
86 false
87: ) / _exchangeRate;
84: (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
89: borrowPart = (borrowPart * _totalBorrow.elastic) / _totalBorrow.base;
126 (borrowAmount * liquidationMultiplier) /
127: FEE_PRECISION;
130: (amountWithBonus * _exchangeRate) / EXCHANGE_RATE_PRECISION,
182: uint256 callerShare = (extraShare * callerFee) / FEE_PRECISION; // 1% goes to caller
216 uint256 collateralPartInAsset = (yieldBox.toAmount(
217 collateralId,
218 userCollateralShare[user],
219 false
220: ) * EXCHANGE_RATE_PRECISION) / _exchangeRate;
236 (availableBorrowPart * liquidationBonusAmount) /
237: FEE_PRECISION;
253 (borrowAmount * liquidationMultiplier) /
254: FEE_PRECISION;
257: (amountWithBonus * _exchangeRate) / EXCHANGE_RATE_PRECISION,
278: feeShare = (extraShare * protocolFee) / FEE_PRECISION; // x% of profit goes to fee.
279: callerShare = (extraShare * callerReward) / FEE_PRECISION; // y% of profit goes to caller.
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
157: share = (amount * allShare) / totalAsset.base;
File: tapioca-bar-audit/contracts/usd0/USDO.sol
69: return (amount * flashMintFee) / FLASH_MINT_FEE_PRECISION;
File: tapiocaz-audit/contracts/Balancer.sol
339: return _amount - ((_amount * _slippage) / SLIPPAGE_PRECISION);
File: tapiocaz-audit/contracts/tOFT/BaseTOFTStorage.sol
57: _decimal / 2,
File: tap-token-audit/contracts/governance/twTAP.sol
151: return (block.timestamp - creation) / EPOCH_DURATION;
236: result[i] = ((votes * net) / DIST_PRECISION) - claimed[_tokenId][i];
280 (pool.averageMagnitude + magnitude) /
281: pool.totalParticipants; // compute new average magnitude
323: uint256 w1 = (expiry - creation) / EPOCH_DURATION;
446 (_amount * DIST_PRECISION) /
447: uint256(totals.netActiveVotes);
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
530: uint256 rawPaymentAmount = _otcAmountInUSD / _paymentTokenValuation;
535: paymentAmount = paymentAmount / (10 ** (18 - _paymentTokenDecimals));
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
245 (pool.averageMagnitude + magnitude) /
246: pool.totalParticipants; // compute new average magnitude
551: uint256 rawPaymentAmount = _otcAmountInUSD / _paymentTokenValuation;
555: paymentAmount = paymentAmount / (10 ** (18 - _paymentTokenDecimals));
File: tap-token-audit/contracts/tokens/TapOFT.sol
242: return ((timestamp - emissionsStartTime) / WEEK) + 1; // Starts at week 1
254: result = (dso_supply * decay_rate) / DECAY_RATE_DECIMAL;
File: tap-token-audit/contracts/twAML.sol
120: return mul >= 1e4 ? mul / 1e4 : _totalWeight;
141: uint256 target = (_magnitude * _dMax) / _cumulative;
150: uint256 x = y / 2 + 1;
153: x = (y / x + x) / 2;
File: tap-token-audit/contracts/Vesting.sol
172: return (total * (block.timestamp - start)) / duration;
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2.sol
105 (borrowAmount *
106 market.liquidationMultiplier() *
107 market.exchangeRate()) /
108: (liquidationMultiplierPrecision * exchangeRatePrecision),
161: (fraction * totalAssetElastic) / totalAssetBase,
186: fraction = allShare == 0 ? share : (share * totalAssetBase) / allShare;
File: tapioca-periph-audit/contracts/oracle/implementations/ARBTriCryptoOracle.sol
127: ? (_wbtcPrice * _btcPrice) / 1e18
132: _maxPrice = (3 * _vp * FixedPointMathLib.cbrt(_basePrices)) / 1 ether;
135: uint256 _g = (TRI_CRYPTO.gamma() * 1 ether) / GAMMA0;
136: uint256 _a = (TRI_CRYPTO.A() * 1 ether) / A0;
137: uint256 _discount = Math.max((_g ** 2 / 1 ether) * _a, 1e34); // handle qbrt nonconvergence
139: _discount = (FixedPointMathLib.sqrt(_discount) * DISCOUNT0) / 1 ether;
141: _maxPrice -= (_maxPrice * _discount) / 1 ether;
File: tapioca-periph-audit/contracts/oracle/implementations/SGOracle.sol
50 uint256 lpPrice = (SG_POOL.totalLiquidity() *
51: uint256(UNDERLYING.latestAnswer())) / SG_POOL.totalSupply();
File: tapioca-yieldbox-strategies-audit/contracts/aave/AaveStrategy.sol
113: result = result - (result * 50) / 10_000; //0.5%
193: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
122: toWithdraw = toWithdraw - (toWithdraw * 50) / 10_000; //0.5%
177: bptOut = bptOut - (bptOut * 50) / 10_000; //0.5%
202 uint256 toWithdraw = (((amount - queued) * (10 ** decimals)) /
203: pricePerShare);
250: bptIn = bptIn + (bptIn * 250) / 10_000; //2.5%
File: tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
116: uint256 invested = (shares * pricePerShare) / (10 ** 18);
146 uint256 toWithdraw = (((amount - queued) * (10 ** 18)) /
147: pricePerShare);
File: tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
143: result = result - (result * 50) / 10_000; //0.5%
154: uint256 minAmount = (calcWithdraw * 50) / 10_000; //0.5%
207: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
313: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
336: uint256 minAmount = calcWithdraw - (calcWithdraw * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
179: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
186: minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
116: result = result - (result * 50) / 10_000; //0.5%
170: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
188: uint256 minAmount = calcWithdraw - (calcWithdraw * 50) / 10_000; //0.5%
232: uint256 minAmount = calcWithdraw - (calcWithdraw * 50) / 10_000; //0.5%
249: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/glp/GlpStrategy.sol
171: uint256 fee = (wethAmount * FEE_BPS) / 10_000;
207 uint256 minTokenReserve = ((vestingNow + vestable) * avgTokenStake) /
208: totalVestable;
244 (totalVestable * tokenAvailable) /
245: avgTokenStake -
310: uint256 buffer = (freeEsGmx + stakedEsGmx) / 20;
File: tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
108: uint256 minAmount = (toWithdraw * 50) / 10_000; //0.5%
151: uint256 minAmount = toWithdraw - (toWithdraw * 250) / 10_000; //2.5%
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
133: result = result - (result * 50) / 10_000; //0.5%
182: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/yearn/YearnStrategy.sol
114: uint256 invested = (shares * pricePerShare) / (10 ** vault.decimals());
142 uint256 toWithdraw = (((amount - queued) *
143: (10 ** vault.decimals())) / pricePerShare);
File: YieldBox/contracts/BoringMath.sol
26: result = (value * mul) / div;
27: if (roundUp && (result * div) / mul < value) {
File: YieldBox/contracts/YieldBoxRebase.sol
32: share = (amount * totalShares_) / totalAmount;
35: if (roundUp && (share * totalAmount) / totalShares_ < amount) {
55: amount = (share * totalAmount) / totalShares_;
58: if (roundUp && (amount * totalShares_) / totalAmount < share) {
If the length of the arrays are not required to be of the same length, user operations may not be fully executed due to a mismatch in the number of items iterated over, versus the number of items provided in the second array
There are 9 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
309 function liquidate(
310 address[] calldata users,
311 uint256[] calldata maxBorrowParts,
312 ISwapper swapper,
313 bytes calldata collateralToAssetSwapData
314: ) external notPaused {
File: tapioca-bar-audit/contracts/markets/singularity/SGLLiquidation.sol
29 function liquidate(
30 address[] calldata users,
31 uint256[] calldata maxBorrowParts,
32 ISwapper swapper,
33 bytes calldata collateralToAssetSwapData,
34 bytes calldata usdoToBorrowedSwapData
35: ) external notPaused {
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
440 function liquidate(
441 address[] calldata users,
442 uint256[] calldata maxBorrowParts,
443 ISwapper swapper,
444 bytes calldata collateralToAssetSwapData,
445: bytes calldata usdoToBorrowedSwapData
File: tapioca-bar-audit/contracts/Penrose.sol
424 function executeMarketFn(
425 address[] calldata mc,
426 bytes[] memory data,
427 bool forceSuccess
428 )
429 external
430 onlyOwner
431 notPaused
432: returns (bool[] memory success, bytes[] memory result)
File: tap-token-audit/contracts/tokens/BaseTapOFT.sol
163 function claimRewards(
164 address to,
165 uint256 tokenID,
166 address[] memory rewardTokens,
167 uint16 lzDstChainId,
168 address zroPaymentAddress,
169 bytes calldata adapterParams,
170: IRewardClaimSendFromParams[] calldata rewardClaimSendParams
File: YieldBox/contracts/NativeTokenFactory.sol
127: function batchMint(uint256 tokenId, address[] calldata tos, uint256[] calldata amounts) public onlyOwner(tokenId) {
138: function batchBurn(uint256 tokenId, address[] calldata froms, uint256[] calldata amounts) public {
File: YieldBox/contracts/YieldBox.sol
307: function batchTransfer(address from, address to, uint256[] calldata assetIds_, uint256[] calldata shares_) public {
336: function transferMultiple(address from, address[] calldata tos, uint256 assetId, uint256[] calldata shares) public allowed(from, assetId) {
If the intention is for the Ether to be used, the function should call another function, otherwise it should revert (e.g. require(msg.sender == address(weth))
). Having no access control on the function means that someone may send Ether to the contract, and have no way to get anything back out, which is a loss of funds. If the concern is having to spend a small amount of gas to check the sender against an immutable address, the code should at least have a function to rescue unused Ether.
There are 10 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
644: receive() external payable {}
File: tapioca-bar-audit/contracts/usd0/BaseUSDOStorage.sol
68: receive() external payable {}
File: tapiocaz-audit/contracts/Balancer.sol
342: receive() external payable {}
File: tapiocaz-audit/contracts/tOFT/BaseTOFTStorage.sol
43: receive() external payable {}
File: tap-token-audit/contracts/tokens/BaseTapOFT.sol
330: receive() external payable virtual {}
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2Storage.sol
340: receive() external payable virtual {}
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
301: receive() external payable {}
File: tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
164: receive() external payable {}
File: tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
169: receive() external payable {}
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
271: receive() external payable {}
While OpenZeppelin draft contracts are safe to use and have been audited, their 'draft' status means that the EIPs they're based on are not finalized, and thus there may be breaking changes in even minor releases. If a bug is found in this version of OpenZeppelin, and the version that you're forced to upgrade to has breaking changes in the new version, you'll encounter unnecessary delays in porting and testing replacement contracts. Ensure that you have extensive test coverage of this area so that differences can be automatically detected, and have a plan in place for how you would fully test a new version of these contracts if they do indeed change unexpectedly. Consider creating a forked version of the file rather than importing it from the package, and manually patch your fork as changes are made.
There are 7 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
5: import {IERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
File: tapioca-bar-audit/contracts/usd0/BaseUSDO.sol
9: import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
File: tapioca-bar-audit/contracts/usd0/BaseUSDOStorage.sol
9: import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
File: tapiocaz-audit/contracts/tOFT/BaseTOFTStorage.sol
9: import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
File: tap-token-audit/contracts/tokens/BaseTapOFT.sol
5: import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
File: tap-token-audit/contracts/tokens/LTap.sol
5: import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
File: tap-token-audit/contracts/tokens/TapOFT.sol
4: import {ERC20Permit} from "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
Even if the function follows the best practice of check-effects-interaction, not using a reentrancy guard when there may be transfer hooks will open the users of this protocol up to read-only reentrancies with no way to protect against it, except by block-listing the whole protocol.
There are 8 instances of this issue:
File: contracts/tOFT/mTapiocaOFT.sol
/// @audit `extractUnderlying()`
148: IERC20(erc20).safeTransfer(msg.sender, _amount);
File: contracts/governance/twTAP.sol
/// @audit `distributeReward()`
448: rewardToken.safeTransferFrom(msg.sender, address(this), _amount);
File: contracts/option-airdrop/AirdropBroker.sol
/// @audit `collectPaymentTokens()`
377: paymentToken.transfer(
File: contracts/options/TapiocaOptionBroker.sol
/// @audit `collectPaymentTokens()`
491: paymentToken.transfer(
File: contracts/Swapper/CurveSwapper.sol
/// @audit `swap()`
140: IERC20(tokenOut).safeTransfer(to, amountOut);
File: contracts/YieldBox.sol
/// @audit `depositAsset()`
151: IERC1155(asset.contractAddress).safeTransferFrom(from, address(asset.strategy), asset.tokenId, amount, "");
/// @audit `depositAsset()`
144: IERC20(asset.contractAddress).safeTransferFrom(from, address(asset.strategy), amount);
/// @audit `depositNFTAsset()`
181: IERC721(asset.contractAddress).safeTransferFrom(from, address(asset.strategy), asset.tokenId);
Ownable2Step
and Ownable2StepUpgradeable
prevent the contract ownership from mistakenly being transferred to an address that cannot handle it (e.g. due to a typo in the address), by requiring that the recipient of the owner permissions actively accept via a contract call of its own.
There are 4 instances of this issue:
File: tapiocaz-audit/contracts/TapiocaWrapper.sol
26 contract TapiocaWrapper is Ownable {
27 struct ExecutionCall {
28 address toft;
29 bytes bytecode;
30: bool revertOnFailure;
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2.sol
30: contract MagnetarV2 is Ownable, MagnetarV2Storage {
File: tapioca-periph-audit/contracts/Multicall/Multicall3.sol
22 contract Multicall3 is Ownable {
23 struct Call {
24 address target;
25 bool allowFailure;
26: bytes callData;
File: tapioca-periph-audit/contracts/Swapper/BaseSwapper.sol
11: abstract contract BaseSwapper is Ownable, ReentrancyGuard, ISwapper {
Each time addRewardToken()
is called, new entries are added to the array, but doing so does not remove any old entries. By calling the function multiple times, an attacker can can increase their voting power indefinitely, without having to acquire new tokens.
There are 2 instances of this issue:
File: contracts/governance/twTAP.sol
455 function addRewardToken(IERC20 token) external onlyOwner returns (uint256) {
456 uint256 i = rewardTokens.length;
457 rewardTokens.push(token);
458 rewardTokenIndex[token] = i;
459 return i;
460: }
File: contracts/options/TapiocaOptionLiquidityProvision.sol
280 ) external onlyOwner updateTotalSGLPoolWeights {
281 require(assetID > 0, "tOLP: invalid asset ID");
282 require(
283 activeSingularities[singularity].sglAssetID == 0,
284 "tOLP: already registered"
285 );
286
287 activeSingularities[singularity].sglAssetID = assetID;
288 activeSingularities[singularity].poolWeight = weight > 0 ? weight : 1;
289 sglAssetIDToAddress[assetID] = singularity;
290 singularities.push(assetID);
291
292 emit RegisterSingularity(address(singularity), assetID);
293: }
According to EIP-2612, signatures used on exactly the deadline timestamp are supposed to be allowed. While the signature may or may not be used for the exact EIP-2612 use case (transfer approvals), for consistency's sake, all deadlines should follow this semantic. If the timestamp is an expiration rather than a deadline, consider whether it makes more sense to include the expiration timestamp as a valid timestamp, as is done for deadlines.
There are 3 instances of this issue:
File: contracts/governance/twTAP.sol
159: if (participant.expiry < block.timestamp) {
File: contracts/option-airdrop/AirdropBroker.sol
158: require(aoTapOption.expiry > block.timestamp, "adb: Option expired");
233: require(aoTapOption.expiry > block.timestamp, "adb: Option expired");
When there are hard forks, users often have to go through many hoops to ensure that they control ownership on every fork. Consider adding require(1 == chain.chainId)
, or the chain ID of whichever chain you prefer, to the functions below, or at least include the chain ID in the URI, so that there is no confusion about which chain is the owner of the NFT.
There are 2 instances of this issue:
File: contracts/option-airdrop/aoTAP.sol
68 function tokenURI(
69 uint256 _tokenId
70 ) public view override returns (string memory) {
71 return tokenURIs[_tokenId];
72: }
File: contracts/options/oTAP.sol
54 function tokenURI(
55 uint256 _tokenId
56 ) public view override returns (string memory) {
57 return tokenURIs[_tokenId];
58: }
The decimals()
function is not a part of the ERC-20 standard, and was added later as an optional extension. As such, some valid ERC20 tokens do not support this interface, so it is unsafe to blindly cast all tokens to this interface, and then call this function.
There are 4 instances of this issue:
File: contracts/option-airdrop/AirdropBroker.sol
189: _paymentToken.decimals()
506: _paymentToken.decimals()
File: contracts/options/TapiocaOptionBroker.sol
202: _paymentToken.decimals()
527: _paymentToken.decimals()
The EIP states that tokenURI()
"Throws if _tokenId
is not a valid NFT", which the code below does not do. If the NFT has not yet been minted, tokenURI()
should revert
There are 2 instances of this issue:
File: contracts/option-airdrop/aoTAP.sol
68 function tokenURI(
69 uint256 _tokenId
70 ) public view override returns (string memory) {
71 return tokenURIs[_tokenId];
72: }
File: contracts/options/oTAP.sol
54 function tokenURI(
55 uint256 _tokenId
56 ) public view override returns (string memory) {
57 return tokenURIs[_tokenId];
58: }
Code architecture, incentives, and error handling/reporting questions/issues should be resolved before deployment
There are 10 instances of this issue:
File: tap-token-audit/contracts/governance/twTAP.sol
233: // (TODO: Word better?)
289: // TODO: Strongly suspect this is never less. Prove it.
347: // TODO: Mint event?
398: // TODO: Make whole function unchecked
411: // TODO: Prove that math is safe
444: // TODO: Word this better
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
200: // uint256 compoundAmount = compoundAmount();//TODO: not view
File: tapioca-yieldbox-strategies-audit/contracts/glp/GlpStrategy.sol
238: // (TODO: Check that the multiplication does not overflow!)
241: // (TODO: Check edge case where the average calculation drops to
331: // TODO: Check the cast?
totalSupply()
being zero will result in a division by zero, causing the transaction to fail. The function should instead special-case this scenario, and avoid reverting.
There is one instance of this issue:
File: contracts/oracle/implementations/SGOracle.sol
/// @audit _get()
50 uint256 lpPrice = (SG_POOL.totalLiquidity() *
51: uint256(UNDERLYING.latestAnswer())) / SG_POOL.totalSupply();
Use latestRoundData()
instead so that you can tell whether the answer is stale or not. The latestAnswer()
function returns zero if it is unable to fetch data, which may be the case if ChainLink stops supporting this API. The API and its deprecation message no longer even appear on the ChainLink website, so it is dangerous to continue using it.
There are 5 instances of this issue:
File: tapioca-periph-audit/contracts/oracle/implementations/ARBTriCryptoOracle.sol
121: uint256 _btcPrice = uint256(BTC_FEED.latestAnswer()) * 1e10;
122: uint256 _wbtcPrice = uint256(WBTC_FEED.latestAnswer()) * 1e10;
123: uint256 _ethPrice = uint256(ETH_FEED.latestAnswer()) * 1e10;
124: uint256 _usdtPrice = uint256(USDT_FEED.latestAnswer()) * 1e10;
File: tapioca-periph-audit/contracts/oracle/implementations/SGOracle.sol
51: uint256(UNDERLYING.latestAnswer())) / SG_POOL.totalSupply();
Deprecated in favor of safeIncreaseAllowance()
and safeDecreaseAllowance()
. If only setting the initial allowance to the value that means infinite, safeIncreaseAllowance()
can be used instead. The function may currently work, but if a bug is found in this version of OpenZeppelin, and the version that you're forced to upgrade to no longer has this function, you'll encounter unnecessary delays in porting and testing replacement contracts.
There is one instance of this issue:
File: tapioca-periph-audit/contracts/Swapper/UniswapV3Swapper.sol
172: TransferHelper.safeApprove(tokenIn, address(swapRouter), amountIn);
The existing transferOwnership
function immediately transfers ownership to the new addres. Consider implementing a two-step variant, where the 'acceptor' of the ownership must call a separate function in order for the transfer to take effect. This can help to prevent mistakes where the wrong address is used, and ownership is irrecoverably lost.
There is one instance of this issue:
File: contracts/NativeTokenFactory.sol
56 function transferOwnership(uint256 tokenId, address newOwner, bool direct, bool renounce) public onlyOwner(tokenId) {
57 if (direct) {
58 // Checks
59 require(newOwner != address(0) || renounce, "NTF: zero address");
60
61 // Effects
62 emit OwnershipTransferred(tokenId, owner[tokenId], newOwner);
63 owner[tokenId] = newOwner;
64 pendingOwner[tokenId] = address(0);
65 } else {
66 // Effects
67 pendingOwner[tokenId] = newOwner;
68 }
69: }
When an action is triggered based on a user's action, not being able to filter based on who triggered the action makes event processing a lot more cumbersome. Including the msg.sender
the events of these types of action will make events much more useful to end users, especially when msg.sender
is not tx.origin
.
There are 21 instances of this issue:
see instances
File: contracts/Penrose.sol
274: emit PausedUpdated(paused, val);
File: contracts/markets/Market.sol
248: emit PausedUpdated(paused, val);
File: contracts/markets/MarketERC20.sol
185: emit Transfer(from, to, amount);
File: contracts/markets/bigBang/BigBang.sol
587: emit LogRemoveCollateral(user, address(swapper), collateralShare);
588: emit LogRepay(address(swapper), user, borrowAmount, borrowPart);
File: contracts/markets/singularity/SGLLiquidation.sol
134 emit LogRemoveCollateral(
135 user,
136 address(liquidationQueue),
137 collateralShare
138: );
139 emit LogRepay(
140 address(liquidationQueue),
141 user,
142 borrowAmount,
143 borrowPart
144: );
196 emit LogAddAsset(
197 address(liquidationQueue),
198 address(this),
199 returnedShare - callerShare,
200 0
201: );
286 emit LogAddAsset(
287 swapper,
288 address(this),
289 extraShare - feeShare - callerShare,
290 0
291: );
321: emit LogRemoveCollateral(user, address(swapper), collateralShare);
322: emit LogRepay(address(swapper), user, borrowAmount, borrowPart);
File: contracts/usd0/BaseUSDO.sol
117: emit PausedUpdated(paused, val);
File: contracts/usd0/USDO.sol
112: emit Minted(_to, _amount);
121: emit Burned(_from, _amount);
File: contracts/governance/twTAP.sol
301 emit AMLDivergence(
302 pool.cumulative,
303 pool.averageMagnitude,
304 pool.totalParticipants
305: );
346: emit Participate(_participant, _amount, multiplier);
File: contracts/options/TapiocaOptionBroker.sol
264 emit AMLDivergence(
265 epoch,
266 pool.cumulative,
267 pool.averageMagnitude,
268 pool.totalParticipants
269: ); // Register new voting power event
285 emit Participate(
286 epoch,
287 lock.sglAssetID,
288 pool.totalDeposited,
289 lock,
290 target
291: );
File: contracts/options/TapiocaOptionLiquidityProvision.sol
200: emit Mint(_to, uint128(sglAssetID), lockPosition);
249: emit Burn(_to, lockPosition.sglAssetID, lockPosition);
File: contracts/NativeTokenFactory.sol
80: emit OwnershipTransferred(tokenId, owner[tokenId], _pendingOwner);
The default value for variables is zero, so initializing them to zero is superfluous.
There are 129 instances of this issue:
see instances
File: contracts/Penrose.sol
437: for (uint256 i = 0; i < len; ) {
492: for (uint256 i = 0; i < length; ) {
512: uint256 amount = 0;
546: uint256 marketsLength = 0;
550: for (uint256 i = 0; i < _masterContractLength; ) {
569: for (uint256 j = 0; j < clonesOfLength; ) {
564: for (uint256 i = 0; i < _masterContractLength; ) {
File: contracts/markets/bigBang/BigBang.sol
215: for (uint256 i = 0; i < calls.length; i++) {
527: uint256 extraAmount = 0;
603: uint256 minAssetMount = 0;
665: uint256 liquidatedCount = 0;
666: for (uint256 i = 0; i < users.length; i++) {
File: contracts/markets/singularity/SGLLiquidation.sol
44: uint256 needed = 0;
45: for (uint256 i = 0; i < maxBorrowParts.length; i++) {
107: for (uint256 i = 0; i < users.length; i++) {
337: uint256 minAssetAmount = 0;
383: uint256 liquidatedCount = 0;
384: for (uint256 i = 0; i < users.length; i++) {
File: contracts/markets/singularity/Singularity.sol
187: for (uint256 i = 0; i < calls.length; i++) {
File: contracts/usd0/modules/USDOLeverageModule.sol
255: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/usd0/modules/USDOMarketModule.sol
244: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/usd0/modules/USDOOptionsModule.sol
245: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/Penrose.sol
437: for (uint256 i = 0; i < len; ) {
492: for (uint256 i = 0; i < length; ) {
512: uint256 amount = 0;
546: uint256 marketsLength = 0;
550: for (uint256 i = 0; i < _masterContractLength; ) {
569: for (uint256 j = 0; j < clonesOfLength; ) {
564: for (uint256 i = 0; i < _masterContractLength; ) {
File: contracts/markets/bigBang/BigBang.sol
215: for (uint256 i = 0; i < calls.length; i++) {
527: uint256 extraAmount = 0;
603: uint256 minAssetMount = 0;
665: uint256 liquidatedCount = 0;
666: for (uint256 i = 0; i < users.length; i++) {
File: contracts/markets/singularity/SGLLiquidation.sol
44: uint256 needed = 0;
45: for (uint256 i = 0; i < maxBorrowParts.length; i++) {
107: for (uint256 i = 0; i < users.length; i++) {
337: uint256 minAssetAmount = 0;
383: uint256 liquidatedCount = 0;
384: for (uint256 i = 0; i < users.length; i++) {
File: contracts/markets/singularity/Singularity.sol
187: for (uint256 i = 0; i < calls.length; i++) {
File: contracts/usd0/modules/USDOLeverageModule.sol
255: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/usd0/modules/USDOMarketModule.sol
244: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/usd0/modules/USDOOptionsModule.sol
245: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/TapiocaWrapper.sol
98: for (uint256 i = 0; i < harvestableTapiocaOFTs.length; i++) {
140: for (uint256 i = 0; i < _call.length; i++) {
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
285: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/tOFT/modules/BaseTOFTMarketModule.sol
261: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/tOFT/modules/BaseTOFTOptionsModule.sol
260: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/TapiocaWrapper.sol
98: for (uint256 i = 0; i < harvestableTapiocaOFTs.length; i++) {
140: for (uint256 i = 0; i < _call.length; i++) {
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
285: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/tOFT/modules/BaseTOFTMarketModule.sol
261: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/tOFT/modules/BaseTOFTOptionsModule.sol
260: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/Vesting.sol
29: uint256 public seeded = 0;
File: contracts/governance/twTAP.sol
196: for (uint256 i = 0; i < len; ) {
413: for (uint256 i = 0; i < len; ) {
487: for (uint256 i = 0; i < len; ++i) {
507: for (uint256 i = 0; i < len; ) {
File: contracts/option-airdrop/AirdropBroker.sol
336: for (uint256 i = 0; i < _users.length; i++) {
332: for (uint256 i = 0; i < _users.length; i++) {
375: for (uint256 i = 0; i < len; ++i) {
File: contracts/options/TapiocaOptionBroker.sol
489: for (uint256 i = 0; i < len; ++i) {
565: for (uint256 i = 0; i < len; ++i) {
File: contracts/options/TapiocaOptionLiquidityProvision.sol
136: for (uint256 i = 0; i < len; ++i) {
308: for (uint256 i = 0; i < sglLength; i++) {
339: for (uint256 i = 0; i < len; i++) {
File: contracts/tokens/BaseTapOFT.sol
228: for (uint i = 0; i < len; ) {
333: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/governance/twTAP.sol
196: for (uint256 i = 0; i < len; ) {
413: for (uint256 i = 0; i < len; ) {
487: for (uint256 i = 0; i < len; ++i) {
507: for (uint256 i = 0; i < len; ) {
File: contracts/option-airdrop/AirdropBroker.sol
336: for (uint256 i = 0; i < _users.length; i++) {
332: for (uint256 i = 0; i < _users.length; i++) {
375: for (uint256 i = 0; i < len; ++i) {
File: contracts/options/TapiocaOptionBroker.sol
489: for (uint256 i = 0; i < len; ++i) {
565: for (uint256 i = 0; i < len; ++i) {
File: contracts/options/TapiocaOptionLiquidityProvision.sol
136: for (uint256 i = 0; i < len; ++i) {
308: for (uint256 i = 0; i < sglLength; i++) {
339: for (uint256 i = 0; i < len; i++) {
File: contracts/tokens/BaseTapOFT.sol
228: for (uint i = 0; i < len; ) {
333: for (uint256 i = 0; i < approvals.length; ) {
File: contracts/Magnetar/MagnetarV2.sol
202: for (uint256 i = 0; i < length; i++) {
973: for (uint256 i = 0; i < len; i++) {
1004: for (uint256 i = 0; i < len; i++) {
File: contracts/Magnetar/modules/MagnetarMarketModule.sol
401: uint256 fraction = 0;
414: uint256 tOLPTokenId = 0;
508: uint256 tOLPId = 0;
571: uint256 _removeAmount = 0;
File: contracts/Multicall/Multicall3.sol
47: for (uint256 i = 0; i < length; ) {
70: for (uint256 i = 0; i < length; ) {
File: contracts/Magnetar/MagnetarV2.sol
202: for (uint256 i = 0; i < length; i++) {
973: for (uint256 i = 0; i < len; i++) {
1004: for (uint256 i = 0; i < len; i++) {
File: contracts/Magnetar/modules/MagnetarMarketModule.sol
401: uint256 fraction = 0;
414: uint256 tOLPTokenId = 0;
508: uint256 tOLPId = 0;
571: uint256 _removeAmount = 0;
File: contracts/Multicall/Multicall3.sol
47: for (uint256 i = 0; i < length; ) {
70: for (uint256 i = 0; i < length; ) {
File: contracts/balancer/BalancerStrategy.sol
156: for (uint256 i = 0; i < poolTokens.length; i++) {
225: for (uint256 i = 0; i < poolTokens.length; i++) {
277: for (uint256 i = 0; i < poolTokens.length; i++) {
File: contracts/convex/ConvexTricryptoStrategy.sol
195: for (uint256 i = 0; i < tokens.length; i++) {
255: for (uint256 i = 0; i < tempData.tokens.length; i++) {
273: for (uint256 i = 0; i < tempData.tokens.length; i++) {
280: for (uint256 i = 0; i < tempData.tokens.length; i++) {
File: contracts/curve/TricryptoLPStrategy.sol
109: uint256 claimable = 0;
File: contracts/balancer/BalancerStrategy.sol
156: for (uint256 i = 0; i < poolTokens.length; i++) {
225: for (uint256 i = 0; i < poolTokens.length; i++) {
277: for (uint256 i = 0; i < poolTokens.length; i++) {
File: contracts/convex/ConvexTricryptoStrategy.sol
195: for (uint256 i = 0; i < tokens.length; i++) {
255: for (uint256 i = 0; i < tempData.tokens.length; i++) {
273: for (uint256 i = 0; i < tempData.tokens.length; i++) {
280: for (uint256 i = 0; i < tempData.tokens.length; i++) {
File: contracts/curve/TricryptoLPStrategy.sol
109: uint256 claimable = 0;
File: contracts/NativeTokenFactory.sol
129: for (uint256 i = 0; i < len; i++) {
141: for (uint256 i = 0; i < len; i++) {
File: contracts/YieldBox.sol
309: for (uint256 i = 0; i < len; i++) {
320: for (uint256 i = 0; i < len; i++) {
339: for (uint256 i = 0; i < len; i++) {
345: for (uint256 i = 0; i < len; i++) {
File: contracts/NativeTokenFactory.sol
129: for (uint256 i = 0; i < len; i++) {
141: for (uint256 i = 0; i < len; i++) {
File: contracts/YieldBox.sol
309: for (uint256 i = 0; i < len; i++) {
320: for (uint256 i = 0; i < len; i++) {
339: for (uint256 i = 0; i < len; i++) {
345: for (uint256 i = 0; i < len; i++) {
Consider moving to solidity version 0.8.18 or later, and using named mappings to make it easier to understand the purpose of each mapping
There are 57 instances of this issue:
see instances
File: contracts/Penrose.sol
61: mapping(address => bool) public isSingularityMasterContractRegistered;
63: mapping(address => bool) public isBigBangMasterContractRegistered;
65: mapping(address => bool) public isMarketRegistered;
79: mapping(address => IStrategy) public emptyStrategies;
File: contracts/markets/Market.sol
57: mapping(address => uint256) public userBorrowPart;
59: mapping(address => uint256) public userCollateralShare;
File: contracts/markets/MarketERC20.sol
48: mapping(address => uint256) public override balanceOf;
50: mapping(address => mapping(address => uint256)) public override allowance;
52: mapping(address => mapping(address => uint256)) public allowanceBorrow;
54: mapping(address => uint256) private _nonces;
File: contracts/markets/bigBang/BigBang.sol
46: mapping(address => mapping(address => bool)) public operators;
File: contracts/markets/singularity/SGLStorage.sol
49: mapping(address => mapping(bytes32 => uint256)) internal _yieldBoxShares;
File: contracts/usd0/BaseUSDOStorage.sol
25: mapping(uint256 => mapping(address => bool)) public allowedMinter;
28: mapping(uint256 => mapping(address => bool)) public allowedBurner;
File: contracts/Balancer.sol
49: mapping(address => mapping(uint16 => OFTData)) public connectedOFTs;
File: contracts/TapiocaWrapper.sol
41: mapping(address => ITapiocaOFT) public tapiocaOFTsByErc20;
File: contracts/tOFT/mTapiocaOFT.sol
17: mapping(uint256 => bool) public connectedChains;
21: mapping(address => bool) public balancers;
File: contracts/Vesting.sol
38: mapping(address => UserData) public users;
File: contracts/governance/twTAP.sol
59: mapping(uint256 => uint256) totalDistPerVote;
79: mapping(uint256 => Participation) public participants; // tokenId => part.
100: mapping(uint256 => mapping(uint256 => uint256)) public claimed;
109: mapping(uint256 => WeekTotals) public weekTotals;
File: contracts/option-airdrop/AirdropBroker.sol
57: mapping(uint256 => mapping(uint256 => uint256)) public aoTAPCalls; // oTAPTokenID => epoch => amountExercised
61: mapping(address => mapping(uint256 => bool)) public userParticipation; // user address => phase => participated
68: mapping(address => uint256) public phase1Users;
92: mapping(address => uint256) public phase4Users;
File: contracts/option-airdrop/aoTAP.sol
36: mapping(uint256 => AirdropTapOption) public options; // tokenId => Option
37: mapping(uint256 => string) public tokenURIs; // tokenId => tokenURI
File: contracts/options/TapiocaOptionBroker.sol
64: mapping(uint256 => Participation) public participants; // tOLPTokenID => Participation
65: mapping(uint256 => mapping(uint256 => uint256)) public oTAPCalls; // oTAPTokenID => epoch => amountExercised
67: mapping(uint256 => mapping(uint256 => uint256)) public singularityGauges; // epoch => sglAssetId => availableTAP
73: mapping(uint256 => TWAMLPool) public twAML; // sglAssetId => twAMLPool
File: contracts/options/TapiocaOptionLiquidityProvision.sol
56: mapping(uint256 => LockPosition) public lockPositions; // TokenID => LockPosition
62: mapping(uint256 => IERC20) public sglAssetIDToAddress; // Singularity market YieldBox asset ID => Singularity market address
File: contracts/options/oTAP.sol
34: mapping(uint256 => TapOption) public options; // tokenId => Option
35: mapping(uint256 => string) public tokenURIs; // tokenId => tokenURI
File: contracts/tokens/TapOFT.sol
57: mapping(uint256 => uint256) public emissionForWeek;
61: mapping(uint256 => uint256) public mintedInWeek;
File: contracts/Magnetar/MagnetarV2Storage.sol
29: mapping(address => mapping(address => bool)) public isApprovedForAll;
File: contracts/NativeTokenFactory.sol
24: mapping(uint256 => NativeToken) public nativeTokens;
25: mapping(uint256 => address) public owner;
26: mapping(uint256 => address) public pendingOwner;
File: contracts/YieldBoxPermit.sol
24: mapping(address => Counters.Counter) private _nonces;
Consider using just one method in a single file
There are 4 instances of this issue:
File: contracts/markets/MarketERC20.sol
24 contract MarketERC20 is IERC20, IERC20Permit, EIP712 {
25 // ************ //
26 // *** VARS *** //
27 // ************ //
28: // solhint-disable-next-line var-name-mixedcase
File: contracts/Vesting.sol
10: contract Vesting is BoringOwnable, ReentrancyGuard {
File: contracts/Swapper/BaseSwapper.sol
11: abstract contract BaseSwapper is Ownable, ReentrancyGuard, ISwapper {
File: contracts/Swapper/CurveSwapper.sol
23: contract CurveSwapper is BaseSwapper {
Doing so will significantly increase centralization, but will help to prevent hackers from using stolen tokens
There are 55 instances of this issue:
see instances
File: contracts/Penrose.sol
32 contract Penrose is BoringOwnable, BoringFactory {
33 // ************ //
34 // *** VARS *** //
35 // ************ //
36: /// @notice returns the Conservator address
File: contracts/markets/MarketERC20.sol
24 contract MarketERC20 is IERC20, IERC20Permit, EIP712 {
25 // ************ //
26 // *** VARS *** //
27 // ************ //
28: // solhint-disable-next-line var-name-mixedcase
File: contracts/markets/bigBang/BigBang.sol
39: contract BigBang is BoringOwnable, Market {
File: contracts/markets/singularity/SGLBorrow.sol
8: contract SGLBorrow is SGLLendingCommon {
File: contracts/markets/singularity/SGLCollateral.sol
8: contract SGLCollateral is SGLLendingCommon {
File: contracts/markets/singularity/SGLCommon.sol
9: contract SGLCommon is SGLStorage {
File: contracts/markets/singularity/SGLLendingCommon.sol
8: contract SGLLendingCommon is SGLCommon {
File: contracts/markets/singularity/SGLLeverage.sol
10: contract SGLLeverage is SGLLendingCommon {
File: contracts/markets/singularity/SGLLiquidation.sol
10: contract SGLLiquidation is SGLCommon {
File: contracts/markets/singularity/SGLStorage.sol
34: contract SGLStorage is BoringOwnable, Market {
File: contracts/markets/singularity/Singularity.sol
37: contract Singularity is SGLCommon {
File: contracts/usd0/BaseUSDO.sol
46: contract BaseUSDO is BaseUSDOStorage, ERC20Permit {
File: contracts/usd0/BaseUSDOStorage.sol
17 contract BaseUSDOStorage is OFTV2 {
18: /// @notice the YieldBox address.
File: contracts/usd0/USDO.sol
24: contract USDO is BaseUSDO, IERC3156FlashLender {
File: contracts/usd0/modules/USDOLeverageModule.sol
19: contract USDOLeverageModule is BaseUSDOStorage {
File: contracts/usd0/modules/USDOMarketModule.sol
21: contract USDOMarketModule is BaseUSDOStorage {
File: contracts/usd0/modules/USDOOptionsModule.sol
16: contract USDOOptionsModule is BaseUSDOStorage {
File: contracts/Balancer.sol
34 contract Balancer is Owned {
35 // ************ //
36 // *** VARS *** //
37 // ************ //
38 /// @notice current OFT => chain => destination OFT
39 /// @dev chain ids (https://stargateprotocol.gitbook.io/stargate/developers/chain-ids):
40 /// - Ethereum: 101
41 /// - BNB: 102
42 /// - Avalanche: 106
43 /// - Polygon: 109
44 /// - Arbitrum: 110
45 /// - Optimism: 111
46 /// - Fantom: 112
47 /// - Metis: 151
48: /// pool ids https://stargateprotocol.gitbook.io/stargate/developers/pool-ids
File: contracts/TapiocaWrapper.sol
26: contract TapiocaWrapper is Ownable {
File: contracts/tOFT/BaseTOFT.sol
15: contract BaseTOFT is BaseTOFTStorage, ERC20Permit {
File: contracts/tOFT/BaseTOFTStorage.sol
21 contract BaseTOFTStorage is OFTV2 {
22 // ************ //
23 // *** VARS *** //
24 // ************ //
25: /// @notice The YieldBox address.
File: contracts/tOFT/TapiocaOFT.sol
21: contract TapiocaOFT is BaseTOFT {
File: contracts/tOFT/mTapiocaOFT.sol
9: contract mTapiocaOFT is BaseTOFT {
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
21: contract BaseTOFTLeverageModule is BaseTOFTStorage {
File: contracts/tOFT/modules/BaseTOFTMarketModule.sol
20: contract BaseTOFTMarketModule is BaseTOFTStorage {
File: contracts/tOFT/modules/BaseTOFTOptionsModule.sol
16: contract BaseTOFTOptionsModule is BaseTOFTStorage {
File: contracts/tOFT/modules/BaseTOFTStrategyModule.sol
16: contract BaseTOFTStrategyModule is BaseTOFTStorage {
File: contracts/Vesting.sol
10: contract Vesting is BoringOwnable, ReentrancyGuard {
File: contracts/governance/twTAP.sol
71: contract TwTAP is TWAML, ONFT721, ERC721Permit {
File: contracts/option-airdrop/AirdropBroker.sol
43: contract AirdropBroker is Pausable, BoringOwnable, FullMath {
File: contracts/option-airdrop/aoTAP.sol
32: contract AOTAP is ERC721, ERC721Permit, BaseBoringBatchable, BoringOwnable {
File: contracts/options/TapiocaOptionBroker.sol
53: contract TapiocaOptionBroker is Pausable, BoringOwnable, TWAML {
File: contracts/options/TapiocaOptionLiquidityProvision.sol
48 contract TapiocaOptionLiquidityProvision is
49 ERC721,
50 ERC721Permit,
51 BaseBoringBatchable,
52 Pausable,
53 BoringOwnable
54: {
File: contracts/options/oTAP.sol
30: contract OTAP is ERC721, ERC721Permit, BaseBoringBatchable {
File: contracts/tokens/LTap.sol
23: contract LTap is BoringOwnable, ERC20Permit {
File: contracts/tokens/TapOFT.sol
26 contract TapOFT is BaseTapOFT, ERC20Permit {
27 // ==========
28 // *DATA*
29 // ==========
30
31 // Allocation:
32 // =========
33 // * DSO: 53,313,405
34 // * DAO: 8m
35 // * Contributors: 15m
36 // * Early supporters: 3,686,595
37 // * Supporters: 12.5m
38 // * LBP: 5m
39 // * Airdrop: 2.5m
40: // == 100M ==
File: contracts/Magnetar/MagnetarV2.sol
30: contract MagnetarV2 is Ownable, MagnetarV2Storage {
File: contracts/Magnetar/modules/MagnetarMarketModule.sol
20: contract MagnetarMarketModule is MagnetarV2Storage {
File: contracts/Swapper/CurveSwapper.sol
23: contract CurveSwapper is BaseSwapper {
File: contracts/Swapper/UniswapV2Swapper.sol
21: contract UniswapV2Swapper is BaseSwapper {
File: contracts/Swapper/UniswapV3Swapper.sol
28: contract UniswapV3Swapper is BaseSwapper {
File: contracts/oracle/Seer.sol
7: contract Seer is ITOracle, OracleMulti {
File: contracts/aave/AaveStrategy.sol
29: contract AaveStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/balancer/BalancerStrategy.sol
28: contract BalancerStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/compound/CompoundStrategy.sol
28: contract CompoundStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/convex/ConvexTricryptoStrategy.sol
31 contract ConvexTricryptoStrategy is
32 BaseERC20Strategy,
33 BoringOwnable,
34 ReentrancyGuard
35: {
File: contracts/curve/TricryptoLPStrategy.sol
30 contract TricryptoLPStrategy is
31 BaseERC20Strategy,
32 BoringOwnable,
33 ReentrancyGuard
34: {
File: contracts/curve/TricryptoNativeStrategy.sol
30 contract TricryptoNativeStrategy is
31 BaseERC20Strategy,
32 BoringOwnable,
33 ReentrancyGuard
34: {
File: contracts/glp/GlpStrategy.sol
23: contract GlpStrategy is BaseERC20Strategy, BoringOwnable {
File: contracts/lido/LidoEthStrategy.sol
30: contract LidoEthStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/stargate/StargateStrategy.sol
35: contract StargateStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/yearn/YearnStrategy.sol
30: contract YearnStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/NativeTokenFactory.sol
21: contract NativeTokenFactory is AssetRegister {
File: contracts/YieldBox.sol
50 contract YieldBox is YieldBoxPermit, BoringBatchable, NativeTokenFactory, ERC721TokenReceiver, ERC1155TokenReceiver {
51 // ******************* //
52 // *** CONSTRUCTOR *** //
53: // ******************* //
File: contracts/YieldBoxURIBuilder.sol
11: contract YieldBoxURIBuilder {
According to the Solidity Style Guide, Non-external
/public
variable and function names should begin with an underscore
There are 89 instances of this issue:
see instances
File: contracts/markets/Market.sol
82: uint256 internal EXCHANGE_RATE_PRECISION; //not costant, but can only be set in the 'init' method
83: uint256 internal constant FEE_PRECISION = 1e5;
84: uint256 internal constant FEE_PRECISION_DECIMALS = 5;
129: bool internal initialized;
File: contracts/markets/bigBang/BigBang.sol
57: uint256 private constant DEBT_PRECISION = 1e18;
File: contracts/markets/singularity/SGLStorage.sol
50 bytes32 internal ASSET_SIG =
51: 0x0bd4060688a1800ae986e4840aebc924bb40b5bf44de4583df2257220b54b77c; // keccak256("asset")
52 bytes32 internal COLLATERAL_SIG =
53: 0x7d1dc38e60930664f8cbf495da6556ca091d2f92d6550877750c049864b18230; // keccak256("collateral")
143: uint256 internal constant FULL_UTILIZATION = 1e18;
144: uint256 internal constant UTILIZATION_PRECISION = 1e18;
146: uint256 internal constant FACTOR_PRECISION = 1e18;
File: contracts/usd0/BaseUSDOStorage.sol
37: uint256 internal constant FLASH_MINT_FEE_PRECISION = 1e6;
38 bytes32 internal constant FLASH_MINT_CALLBACK_SUCCESS =
39: keccak256("ERC3156FlashBorrower.onFlashLoan");
41: uint16 internal constant PT_MARKET_MULTIHOP_BUY = 772;
42: uint16 internal constant PT_MARKET_REMOVE_ASSET = 773;
43: uint16 internal constant PT_YB_SEND_SGL_LEND_OR_REPAY = 774;
44: uint16 internal constant PT_LEVERAGE_MARKET_UP = 775;
45: uint16 internal constant PT_TAP_EXERCISE = 777;
46: uint16 internal constant PT_SEND_FROM = 778;
File: contracts/Balancer.sol
63: uint256 private constant SLIPPAGE_PRECISION = 1e5;
File: contracts/TapiocaWrapper.sol
39: ITapiocaOFT[] private harvestableTapiocaOFTs;
File: contracts/tOFT/BaseTOFTStorage.sol
34: uint16 internal constant PT_YB_SEND_STRAT = 770;
35: uint16 internal constant PT_YB_RETRIEVE_STRAT = 771;
36: uint16 internal constant PT_MARKET_REMOVE_COLLATERAL = 772;
37: uint16 internal constant PT_MARKET_MULTIHOP_SELL = 773;
38: uint16 internal constant PT_YB_SEND_SGL_BORROW = 775;
39: uint16 internal constant PT_LEVERAGE_MARKET_DOWN = 776;
40: uint16 internal constant PT_TAP_EXERCISE = 777;
41: uint16 internal constant PT_SEND_FROM = 778;
File: contracts/governance/twTAP.sol
81: uint256 constant MIN_WEIGHT_FACTOR = 10; // In BPS, 0.1%
82: uint256 constant dMAX = 100 * 1e4; // 10% - 100% voting power multiplier
83: uint256 constant dMIN = 10 * 1e4;
95: uint256 constant DIST_PRECISION = 2 ** 128;
112: string private baseURI;
File: contracts/options/TapiocaOptionBroker.sol
75: uint256 constant MIN_WEIGHT_FACTOR = 10; // In BPS, 0.1%
76: uint256 constant dMAX = 50 * 1e4; // 5% - 50% discount
77: uint256 constant dMIN = 5 * 1e4;
File: contracts/tokens/BaseTapOFT.sol
37: uint16 internal constant PT_LOCK_TWTAP = 870;
38: uint16 internal constant PT_UNLOCK_TWTAP = 871;
39: uint16 internal constant PT_CLAIM_REWARDS = 872;
File: contracts/tokens/LTap.sol
24: IERC20 tapToken;
File: contracts/tokens/TapOFT.sol
45: uint256 constant decay_rate = 8800000000000000; // 0.88%
46: uint256 constant DECAY_RATE_DECIMAL = 1e18;
File: contracts/twAML.sol
6 function muldiv(
7 uint256 a,
8 uint256 b,
9 uint256 denominator
10: ) internal pure returns (uint256 result) {
115 function computeMinWeight(
116 uint256 _totalWeight,
117 uint256 _minWeightFactor
118: ) internal pure returns (uint256) {
123 function computeMagnitude(
124 uint256 _timeWeight,
125 uint256 _cumulative
126: ) internal pure returns (uint256) {
132 function computeTarget(
133 uint256 _dMin,
134 uint256 _dMax,
135 uint256 _magnitude,
136 uint256 _cumulative
137: ) internal pure returns (uint256) {
147: function sqrt(uint256 y) internal pure returns (uint256 z) {
File: contracts/Magnetar/MagnetarV2Storage.sol
298: uint16 internal constant PERMIT_ALL = 1;
299: uint16 internal constant PERMIT = 2;
301: uint16 internal constant YB_DEPOSIT_ASSET = 100;
302: uint16 internal constant YB_WITHDRAW_TO = 102;
304: uint16 internal constant MARKET_ADD_COLLATERAL = 200;
305: uint16 internal constant MARKET_BORROW = 201;
306: uint16 internal constant MARKET_LEND = 203;
307: uint16 internal constant MARKET_REPAY = 204;
308: uint16 internal constant MARKET_YBDEPOSIT_AND_LEND = 205;
309: uint16 internal constant MARKET_YBDEPOSIT_COLLATERAL_AND_BORROW = 206;
310: uint16 internal constant MARKET_REMOVE_ASSET = 207;
311: uint16 internal constant MARKET_DEPOSIT_REPAY_REMOVE_COLLATERAL = 208;
312: uint16 internal constant MARKET_BUY_COLLATERAL = 209;
313: uint16 internal constant MARKET_SELL_COLLATERAL = 210;
314: uint16 internal constant MARKET_MULTIHOP_BUY = 211;
315: uint16 internal constant MARKET_MULTIHOP_SELL = 212;
317: uint16 internal constant TOFT_WRAP = 300;
318: uint16 internal constant TOFT_SEND_FROM = 301;
319: uint16 internal constant TOFT_SEND_APPROVAL = 302;
320: uint16 internal constant TOFT_SEND_AND_BORROW = 303;
321: uint16 internal constant TOFT_SEND_AND_LEND = 304;
322: uint16 internal constant TOFT_DEPOSIT_TO_STRATEGY = 305;
323: uint16 internal constant TOFT_RETRIEVE_FROM_STRATEGY = 306;
324: uint16 internal constant TOFT_REMOVE_AND_REPAY = 307;
326: uint16 internal constant TAP_EXERCISE_OPTION = 400;
File: contracts/Swapper/UniswapV3Swapper.sol
34: IYieldBox private immutable yieldBox;
File: contracts/oracle/implementations/GLPOracle.sol
8: IGmxGlpManager private immutable glpManager;
File: contracts/glp/GlpStrategy.sol
30: IERC20 private immutable gmx;
31: IERC20 private immutable esGmx;
32: IERC20 private immutable weth;
34: IGmxRewardTracker private immutable feeGmxTracker;
35: IGlpManager private immutable glpManager;
36: IGmxRewardRouterV2 private immutable glpRewardRouter;
37: IGmxRewardRouterV2 private immutable gmxRewardRouter;
38: IGmxVester private immutable glpVester;
39: IGmxVester private immutable gmxVester;
40: IGmxRewardTracker private immutable stakedGlpTracker;
41: IGmxRewardTracker private immutable stakedGmxTracker;
43 IUniswapV3Pool private constant gmxWethPool =
44: IUniswapV3Pool(0x80A9ae39310abf666A87C743d6ebBD0E8C42158E);
45: uint160 internal constant UNI_MIN_SQRT_RATIO = 4295128739;
46 uint160 internal constant UNI_MAX_SQRT_RATIO =
47: 1461446703485210103287273052203988822378723970342;
49: uint256 internal constant FEE_BPS = 100;
There are 15 instances of this issue:
File: contracts/markets/Market.sol
77: uint256 public liquidationMultiplier = 12000; //12%
File: contracts/markets/bigBang/BigBang.sol
148: callerFee = 90000; // 90%
149: protocolFee = 10000; // 10%
150: collateralizationRate = 75000; // 75%
168: liquidationMultiplier = 12000; //12%
521: _accrueInfo.debtRate = uint64(annumDebtRate / 31536000); //per second
File: contracts/markets/singularity/SGLStorage.sol
55: uint256 public lqCollateralizationRate = 25000; // 25%
File: contracts/markets/singularity/Singularity.sol
112: minimumInterestPerSecond = 951293760; // approx 3% APR
113: maximumInterestPerSecond = 2536783360; // approx 8% APR
123: protocolFee = 10000; // 10%
127: liquidationMultiplier = 12000; //12%
129: collateralizationRate = 75000;
130: lqCollateralizationRate = 25000;
File: contracts/tokens/TapOFT.sol
45: uint256 constant decay_rate = 8800000000000000; // 0.88%
49: uint256 public constant WEEK = 604800;
Note that there may be cases where a variable appears to be used, but this is only because there are multiple definitions of the varible in different files. In such cases, the variable definition should be moved into a separate file. The instances below are the unused variables.
There are 4 instances of this issue:
File: contracts/markets/MarketERC20.sol
45: bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;
File: contracts/governance/twTAP.sol
112: string private baseURI;
File: contracts/Magnetar/MagnetarV2Storage.sol
315: uint16 internal constant MARKET_MULTIHOP_SELL = 212;
319: uint16 internal constant TOFT_SEND_APPROVAL = 302;
abi.encodeCall()
has compiler type safety, whereas the other two functions do not
There are 58 instances of this issue:
see instances
File: contracts/markets/singularity/Singularity.sol
244: abi.encodeWithSelector(
262: abi.encodeWithSelector(
284: abi.encodeWithSelector(SGLBorrow.borrow.selector, from, to, amount)
304: abi.encodeWithSelector(
331: abi.encodeWithSelector(
361: abi.encodeWithSelector(
391: abi.encodeWithSelector(
418: abi.encodeWithSelector(
449: abi.encodeWithSelector(
File: contracts/usd0/BaseUSDO.sol
168: abi.encodeWithSelector(
196: abi.encodeWithSelector(
227: abi.encodeWithSelector(
263: abi.encodeWithSelector(
293: abi.encodeWithSelector(
325: abi.encodeWithSelector(
482: abi.encodeWithSelector(
466: abi.encodeWithSelector(
454: abi.encodeWithSelector(
442: abi.encodeWithSelector(
426: abi.encodeWithSelector(
410: abi.encodeWithSelector(
File: contracts/usd0/modules/USDOLeverageModule.sol
170: abi.encodeWithSelector(
File: contracts/usd0/modules/USDOMarketModule.sol
169: abi.encodeWithSelector(
File: contracts/usd0/modules/USDOOptionsModule.sol
175: abi.encodeWithSelector(
File: contracts/tOFT/BaseTOFT.sol
109: abi.encodeWithSelector(
137: abi.encodeWithSelector(
167: abi.encodeWithSelector(
202: abi.encodeWithSelector(
235: abi.encodeWithSelector(
267: abi.encodeWithSelector(
302: abi.encodeWithSelector(
332: abi.encodeWithSelector(
554: abi.encodeWithSelector(
539: abi.encodeWithSelector(
527: abi.encodeWithSelector(
515: abi.encodeWithSelector(
499: abi.encodeWithSelector(
483: abi.encodeWithSelector(
470: abi.encodeWithSelector(
453: abi.encodeWithSelector(
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
185: abi.encodeWithSelector(
File: contracts/tOFT/modules/BaseTOFTMarketModule.sol
161: abi.encodeWithSelector(
File: contracts/tOFT/modules/BaseTOFTOptionsModule.sol
190: abi.encodeWithSelector(
File: contracts/tOFT/modules/BaseTOFTStrategyModule.sol
153: abi.encodeWithSelector(
File: contracts/Magnetar/MagnetarV2.sol
609: abi.encodeWithSelector(
592: abi.encodeWithSelector(
571: abi.encodeWithSelector(
536: abi.encodeWithSelector(
353: abi.encodeWithSelector(
746: abi.encodeWithSelector(
787: abi.encodeWithSelector(
825: abi.encodeWithSelector(
867: abi.encodeWithSelector(
897: abi.encodeWithSelector(
File: contracts/Swapper/BaseSwapper.sol
100: abi.encodeWithSelector(0x095ea7b3, to, value)
File: contracts/convex/ConvexTricryptoStrategy.sol
357: abi.encodeWithSelector(
370: abi.encodeWithSelector(
File: contracts/curve/TricryptoLPStrategy.sol
106: abi.encodeWithSignature("claimable_tokens(address)", address(this))
Doing so will prevent typo bugs
There are 92 instances of this issue:
see instances
File: contracts/Penrose.sol
175: isSingularityMasterContractRegistered[mc] == true,
183: isBigBangMasterContractRegistered[mc] == true,
322: isSingularityMasterContractRegistered[mcAddress] == false,
344: isBigBangMasterContractRegistered[mcAddress] == false,
509: if (feeShares == 0) return;
File: contracts/markets/Market.sol
314: if (borrowPart == 0) return (0, 0, 0);
408: if (borrowPart == 0) return true;
410: if (collateralShare == 0) return false;
447: if (borrowed == 0) return 0;
448: if (startTVLInAsset == 0) return 0;
485: if (numerator == 0 || denominator == 0) {
File: contracts/markets/MarketERC20.sol
140: if (amount != 0 || msg.sender == to) {
165: if (amount != 0) {
File: contracts/markets/bigBang/BigBang.sol
182: if (totalBorrow.elastic == 0) return minDebtRate;
516: if (elapsedTime == 0) {
550: if (share == 0) {
751: totalBorrowCap == 0 || totalBorrow.elastic <= totalBorrowCap,
820: require(borrowAmount != 0, "SGL: solvent");
File: contracts/markets/singularity/SGLBorrow.sol
26: if (amount == 0) return (0, 0);
File: contracts/markets/singularity/SGLCommon.sol
61: utilization = fullAssetAmount == 0
68: if (elapsedTime == 0) {
81: if (_totalBorrow.base == 0) {
207: fraction = allShare == 0
229: if (totalAsset.base == 0) {
240: require(_totalAsset.base >= 1000, "SGL: min limit");
File: contracts/markets/singularity/SGLLendingCommon.sol
23: if (share == 0) {
67: totalBorrowCap == 0 || totalBorrow.base <= totalBorrowCap,
75: require(_totalAsset.base >= 1000, "SGL: min limit");
File: contracts/markets/singularity/SGLLiquidation.sol
76: if (borrowPart == 0) return 0;
115: if (borrowAmount == 0) {
152: require(allBorrowAmount != 0, "SGL: solvent");
264: require(borrowAmount != 0, "SGL: solvent");
File: contracts/Balancer.sol
118: if (_slippage >= 1e5) revert SlippageNotValid();
206: if (msg.value == 0) revert FeeAmountNotSet();
226: if (!isNative && _ercData.length == 0) revert PoolInfoRequired();
File: contracts/TapiocaWrapper.sol
86: if (tapiocaOFTs.length == 0) {
File: contracts/tOFT/BaseTOFT.sol
85: if (_decimalCache == 0) return 18; //temporary fix for LZ _sharedDecimals check
File: contracts/Vesting.sol
111: if (start == 0 || seeded == 0) revert NotStarted();
113: if (_claimable == 0) revert NothingToClaim();
133: if (_amount == 0) revert AmountNotValid();
153: if (_seededAmount == 0) revert NoTokens();
168: if (start == 0) return 0;
File: contracts/governance/twTAP.sol
179: if (votes == 0) {
File: contracts/option-airdrop/AirdropBroker.sol
176: tapAmount = _tapAmount == 0 ? eligibleTapAmount : _tapAmount;
177: require(tapAmount >= 1e18, "adb: Too low");
204: require(cachedEpoch <= 4, "adb: Airdrop ended");
207: if (cachedEpoch == 1) {
209: } else if (cachedEpoch == 2) {
211: } else if (cachedEpoch == 3) {
213: } else if (cachedEpoch == 4) {
257: uint256 chosenAmount = _tapAmount == 0 ? eligibleTapAmount : _tapAmount;
258: require(chosenAmount >= 1e18, "adb: Too low");
331: if (_phase == 1) {
335: } else if (_phase == 4) {
426: userParticipation[msg.sender][subPhase] == false,
450: userParticipation[tokenIDToAddress][3] == false,
File: contracts/options/TapiocaOptionBroker.sol
189: tapAmount = _tapAmount == 0 ? eligibleTapAmount : _tapAmount;
190: require(tapAmount >= 1e18, "tOB: Too low");
390: uint256 chosenAmount = _tapAmount == 0 ? eligibleTapAmount : _tapAmount;
391: require(chosenAmount >= 1e18, "tOB: Too low");
File: contracts/options/TapiocaOptionLiquidityProvision.sol
283: activeSingularities[singularity].sglAssetID == 0,
File: contracts/tokens/TapOFT.sol
176: if (timestamp == 0) {
File: contracts/twAML.sol
32: if (prod1 == 0) {
120: return mul >= 1e4 ? mul / 1e4 : _totalWeight;
138: if (_cumulative == 0) {
155: } else if (y != 0) {
File: contracts/Magnetar/MagnetarV2.sol
186: fraction = allShare == 0 ? share : (share * totalAssetBase) / allShare;
File: contracts/Magnetar/modules/MagnetarMarketModule.sol
402: if (lendAmount == 0 && depositData.deposit) {
454: if (participateData.tOLPTokenId != 0) {
455: if (tOLPTokenId != 0) {
468: require(tOLPTokenId != 0, "Magnetar: tOLPTokenId 0");
554: if (removeAndRepayData.unlockData.tokenId != 0) {
555: if (tOLPId != 0) {
690: if (dstChainId == 0) {
File: contracts/Swapper/BaseSwapper.sol
103: success && (data.length == 0 || abi.decode(data, (bool))),
132: amountIn = amounts.amountIn == 0
137: amountOut = amounts.amountOut == 0
File: contracts/Swapper/UniswapV2Swapper.sol
147: if (data.length == 0) {
File: contracts/Swapper/UniswapV3Swapper.sol
175: if (data.length == 0) {
File: contracts/TapiocaDeployer/TapiocaDeployer.sol
33: bytecode.length != 0,
File: contracts/convex/ConvexTricryptoStrategy.sol
190: if (data.length == 0) return;
312: if (calcAmount >= 1e18) {
377: success && (data.length == 0 || abi.decode(data, (bool))),
File: contracts/glp/GlpStrategy.sol
186: if (available == 0) {
194: if (vestable == 0) {
265: if (vestable == 0) {
294: if (vestable == 0) {
318: if (gmxAmount == 0) {
File: contracts/YieldBox.sol
131: if (share == 0) {
280: if (share == 0) {
If the plan for your project does not include eventually giving up all ownership control, consider overwriting OpenZeppelin's Ownable
's renounceOwnership()
function in order to disable it.
There are 24 instances of this issue:
see instances
File: contracts/Penrose.sol
32: contract Penrose is BoringOwnable, BoringFactory {
File: contracts/markets/Market.sol
14: abstract contract Market is MarketERC20, BoringOwnable {
File: contracts/markets/bigBang/BigBang.sol
39: contract BigBang is BoringOwnable, Market {
File: contracts/markets/singularity/SGLStorage.sol
34: contract SGLStorage is BoringOwnable, Market {
File: contracts/TapiocaWrapper.sol
26: contract TapiocaWrapper is Ownable {
File: contracts/Vesting.sol
10: contract Vesting is BoringOwnable, ReentrancyGuard {
File: contracts/option-airdrop/AirdropBroker.sol
43: contract AirdropBroker is Pausable, BoringOwnable, FullMath {
File: contracts/option-airdrop/aoTAP.sol
32: contract AOTAP is ERC721, ERC721Permit, BaseBoringBatchable, BoringOwnable {
File: contracts/options/TapiocaOptionBroker.sol
53: contract TapiocaOptionBroker is Pausable, BoringOwnable, TWAML {
File: contracts/options/TapiocaOptionLiquidityProvision.sol
53: BoringOwnable
File: contracts/tokens/LTap.sol
23: contract LTap is BoringOwnable, ERC20Permit {
File: contracts/Magnetar/MagnetarV2.sol
30: contract MagnetarV2 is Ownable, MagnetarV2Storage {
File: contracts/Multicall/Multicall3.sol
22: contract Multicall3 is Ownable {
File: contracts/Swapper/BaseSwapper.sol
11: abstract contract BaseSwapper is Ownable, ReentrancyGuard, ISwapper {
File: contracts/aave/AaveStrategy.sol
29: contract AaveStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/balancer/BalancerStrategy.sol
28: contract BalancerStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/compound/CompoundStrategy.sol
28: contract CompoundStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/convex/ConvexTricryptoStrategy.sol
33: BoringOwnable,
File: contracts/curve/TricryptoLPStrategy.sol
32: BoringOwnable,
File: contracts/curve/TricryptoNativeStrategy.sol
32: BoringOwnable,
File: contracts/glp/GlpStrategy.sol
23: contract GlpStrategy is BaseERC20Strategy, BoringOwnable {
File: contracts/lido/LidoEthStrategy.sol
30: contract LidoEthStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/stargate/StargateStrategy.sol
35: contract StargateStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
File: contracts/yearn/YearnStrategy.sol
30: contract YearnStrategy is BaseERC20Strategy, BoringOwnable, ReentrancyGuard {
Adding a way to quickly halt protocol functionality in an emergency, rather than having to pause individual contracts one-by-one, will make in-progress hack mitigation faster and much less stressful.
There are 18 instances of this issue:
see instances
File: contracts/Penrose.sol
32 contract Penrose is BoringOwnable, BoringFactory {
33 // ************ //
34 // *** VARS *** //
35 // ************ //
36 /// @notice returns the Conservator address
37 address public conservator;
38 /// @notice returns the pause state of the contract
39 bool public paused;
40 /// @notice returns the YieldBox contract
41 YieldBox public immutable yieldBox;
42 /// @notice returns the TAP contract
43 IERC20 public immutable tapToken;
44 /// @notice returns TAP asset id registered in the YieldBox contract
45 uint256 public immutable tapAssetId;
46 /// @notice returns USDO contract
47 IERC20 public usdoToken;
48 /// @notice returns USDO asset id registered in the YieldBox contract
49 uint256 public usdoAssetId;
50 /// @notice returns the WETH contract
51 IERC20 public immutable wethToken;
52 /// @notice returns WETH asset id registered in the YieldBox contract
53 uint256 public immutable wethAssetId;
54
55 /// @notice Singularity master contracts
56 IPenrose.MasterContract[] public singularityMasterContracts;
57 /// @notice BigBang master contracts
58 IPenrose.MasterContract[] public bigbangMasterContracts;
59
60 // Used to check if a Singularity master contract is registered
61 mapping(address => bool) public isSingularityMasterContractRegistered;
62 // Used to check if a BigBang master contract is registered
63 mapping(address => bool) public isBigBangMasterContractRegistered;
64 // Used to check if a SGL/BB is a real market
65 mapping(address => bool) public isMarketRegistered;
66
67 /// @notice protocol fees
68 address public feeTo;
69
70 /// @notice whitelisted swappers
71 mapping(ISwapper => bool) public swappers;
72
73 /// @notice BigBang ETH market address
74 address public bigBangEthMarket;
75 /// @notice BigBang ETH market debt rate
76 uint256 public bigBangEthDebtRate;
77
78 /// @notice registered empty strategies
79 mapping(address => IStrategy) public emptyStrategies;
80
81 /// @notice creates a Penrose contract
82 /// @param _yieldBox YieldBox contract address
83 /// @param tapToken_ TapOFT contract address
84 /// @param wethToken_ WETH contract address
85 /// @param _owner owner address
86 constructor(
87 YieldBox _yieldBox,
88 IERC20 tapToken_,
89 IERC20 wethToken_,
90 address _owner
91 ) {
92 yieldBox = _yieldBox;
93 tapToken = tapToken_;
94 owner = _owner;
95
96 emptyStrategies[address(tapToken_)] = IStrategy(
97 address(
98 new ERC20WithoutStrategy(
99 IYieldBox(address(_yieldBox)),
100 tapToken_
101 )
102 )
103 );
104 tapAssetId = uint96(
105 _yieldBox.registerAsset(
106 TokenType.ERC20,
107 address(tapToken_),
108 emptyStrategies[address(tapToken_)],
109 0
110 )
111 );
112
113 wethToken = wethToken_;
114 emptyStrategies[address(wethToken_)] = IStrategy(
115 address(
116 new ERC20WithoutStrategy(
117 IYieldBox(address(_yieldBox)),
118 wethToken_
119 )
120 )
121 );
122 wethAssetId = uint96(
123 _yieldBox.registerAsset(
124 TokenType.ERC20,
125 address(wethToken_),
126 emptyStrategies[address(wethToken_)],
127 0
128 )
129 );
130
131 bigBangEthDebtRate = 5e15;
132 }
133
134 // **************//
135 // *** EVENTS *** //
136 // ************** //
137 /// @notice event emitted when fees are extracted
138 event ProtocolWithdrawal(IMarket[] markets, uint256 timestamp);
139 /// @notice event emitted when Singularity master contract is registered
140 event RegisterSingularityMasterContract(
141 address location,
142 IPenrose.ContractType risk
143 );
144 /// @notice event emitted when BigBang master contract is registered
145 event RegisterBigBangMasterContract(
146 address location,
147 IPenrose.ContractType risk
148 );
149 /// @notice event emitted when Singularity is registered
150 event RegisterSingularity(address location, address masterContract);
151 /// @notice event emitted when BigBang is registered
152 event RegisterBigBang(address location, address masterContract);
153 /// @notice event emitted when feeTo address is updated
154 event FeeToUpdate(address newFeeTo);
155 /// @notice event emitted when ISwapper address is updated
156 event SwapperUpdate(address swapper, bool isRegistered);
157 /// @notice event emitted when USDO address is updated
158 event UsdoTokenUpdated(address indexed usdoToken, uint256 assetId);
159 /// @notice event emitted when conservator is updated
160 event ConservatorUpdated(address indexed old, address indexed _new);
161 /// @notice event emitted when pause state is updated
162 event PausedUpdated(bool oldState, bool newState);
163 /// @notice event emitted when BigBang ETH market address is updated
164 event BigBangEthMarketSet(address indexed _newAddress);
165 /// @notice event emitted when BigBang ETH market debt rate is updated
166 event BigBangEthMarketDebtRate(uint256 _rate);
167 /// @notice event emitted when fees are deposited to YieldBox
168 event LogYieldBoxFeesDeposit(uint256 feeShares, uint256 ethAmount);
169
170 // ******************//
171 // *** MODIFIERS *** //
172 // ***************** //
173 modifier registeredSingularityMasterContract(address mc) {
174 require(
175 isSingularityMasterContractRegistered[mc] == true,
176 "Penrose: MC not registered"
177 );
178 _;
179 }
180
181 modifier registeredBigBangMasterContract(address mc) {
182 require(
183 isBigBangMasterContractRegistered[mc] == true,
184 "Penrose: MC not registered"
185 );
186 _;
187 }
188
189 modifier notPaused() {
190 require(!paused, "Penrose: paused");
191 _;
192 }
193
194 // ********************** //
195 // *** VIEW FUNCTIONS *** //
196 // ********************** //
197 /// @notice Get all the Singularity contract addresses
198 /// @return markets list of available markets
199 function singularityMarkets()
200 public
201 view
202 returns (address[] memory markets)
203 {
204 markets = _getMasterContractLength(singularityMasterContracts);
205 }
206
207 /// @notice Get all the BigBang contract addresses
208 /// @return markets list of available markets
209 function bigBangMarkets() public view returns (address[] memory markets) {
210 markets = _getMasterContractLength(bigbangMasterContracts);
211 }
212
213 /// @notice Get the length of `singularityMasterContracts`
214 function singularityMasterContractLength() public view returns (uint256) {
215 return singularityMasterContracts.length;
216 }
217
218 /// @notice Get the length of `bigbangMasterContracts`
219 function bigBangMasterContractLength() public view returns (uint256) {
220 return bigbangMasterContracts.length;
221 }
222
223 // ************************ //
224 // *** PUBLIC FUNCTIONS *** //
225 // ************************ //
226 /// @notice Loop through the master contracts and call `_depositFeesToYieldBox()` to each one of their clones.
227 /// @dev `swappers_` can have one element that'll be used for all clones. Or one swapper per MasterContract.
228 /// @dev Fees are withdrawn in TAP and sent to the FeeDistributor contract
229 /// @param markets_ Singularity &/ BigBang markets array
230 /// @param swappers_ one or more swappers to convert the asset to TAP.
231 /// @param swapData_ swap data for each swapper
232 function withdrawAllMarketFees(
233 IMarket[] calldata markets_,
234 ISwapper[] calldata swappers_,
235 IPenrose.SwapData[] calldata swapData_
236 ) public notPaused {
237 require(
238 markets_.length == swappers_.length &&
239 swappers_.length == swapData_.length,
240 "Penrose: length mismatch"
241 );
242 require(address(swappers_[0]) != address(0), "Penrose: zero address");
243 require(address(markets_[0]) != address(0), "Penrose: zero address");
244
245 _withdrawAllProtocolFees(swappers_, swapData_, markets_);
246
247 emit ProtocolWithdrawal(markets_, block.timestamp);
248 }
249
250 // *********************** //
251 // *** OWNER FUNCTIONS *** //
252 // *********************** //
253 /// @notice sets the main BigBang market debt rate
254 /// @dev can only be called by the owner
255 /// @param _rate the new rate
256 function setBigBangEthMarketDebtRate(uint256 _rate) external onlyOwner {
257 bigBangEthDebtRate = _rate;
258 emit BigBangEthMarketDebtRate(_rate);
259 }
260
261 /// @notice sets the main BigBang market
262 /// @dev needed for the variable debt computation
263 function setBigBangEthMarket(address _market) external onlyOwner {
264 bigBangEthMarket = _market;
265 emit BigBangEthMarketSet(_market);
266 }
267
268 /// @notice updates the pause state of the contract
269 /// @dev can only be called by the conservator
270 /// @param val the new value
271 function updatePause(bool val) external {
272 require(msg.sender == conservator, "Penrose: unauthorized");
273 require(val != paused, "Penrose: same state");
274 emit PausedUpdated(paused, val);
275 paused = val;
276 }
277
278 /// @notice Set the Conservator address
279 /// @dev Conservator can pause the contract
280 /// @param _conservator The new address
281 function setConservator(address _conservator) external onlyOwner {
282 require(_conservator != address(0), "Penrose: address not valid");
283 emit ConservatorUpdated(conservator, _conservator);
284 conservator = _conservator;
285 }
286
287 /// @notice Set the USDO token
288 /// @dev sets usdoToken and usdoAssetId
289 /// can only by called by the owner
290 /// @param _usdoToken the USDO token address
291 function setUsdoToken(address _usdoToken) external onlyOwner {
292 usdoToken = IERC20(_usdoToken);
293
294 emptyStrategies[_usdoToken] = IStrategy(
295 address(
296 new ERC20WithoutStrategy(
297 IYieldBox(address(yieldBox)),
298 IERC20(_usdoToken)
299 )
300 )
301 );
302 usdoAssetId = uint96(
303 yieldBox.registerAsset(
304 TokenType.ERC20,
305 _usdoToken,
306 emptyStrategies[_usdoToken],
307 0
308 )
309 );
310 emit UsdoTokenUpdated(_usdoToken, usdoAssetId);
311 }
312
313 /// @notice Register a Singularity master contract
314 /// @dev can only be called by the owner
315 /// @param mcAddress The address of the contract
316 /// @param contractType_ The risk type of the contract
317 function registerSingularityMasterContract(
318 address mcAddress,
319 IPenrose.ContractType contractType_
320 ) external onlyOwner {
321 require(
322 isSingularityMasterContractRegistered[mcAddress] == false,
323 "Penrose: MC registered"
324 );
325
326 IPenrose.MasterContract memory mc;
327 mc.location = mcAddress;
328 mc.risk = contractType_;
329 singularityMasterContracts.push(mc);
330 isSingularityMasterContractRegistered[mcAddress] = true;
331
332 emit RegisterSingularityMasterContract(mcAddress, contractType_);
333 }
334
335 /// @notice Register a BigBang master contract
336 /// @dev can only be called by the owner
337 /// @param mcAddress The address of the contract
338 /// @param contractType_ The risk type of the contract
339 function registerBigBangMasterContract(
340 address mcAddress,
341 IPenrose.ContractType contractType_
342 ) external onlyOwner {
343 require(
344 isBigBangMasterContractRegistered[mcAddress] == false,
345 "Penrose: MC registered"
346 );
347
348 IPenrose.MasterContract memory mc;
349 mc.location = mcAddress;
350 mc.risk = contractType_;
351 bigbangMasterContracts.push(mc);
352 isBigBangMasterContractRegistered[mcAddress] = true;
353
354 emit RegisterBigBangMasterContract(mcAddress, contractType_);
355 }
356
357 /// @notice Registers a Singularity market
358 /// @dev can only be called by the owner
359 /// @param mc The address of the master contract which must be already registered
360 /// @param data The init data of the Singularity
361 /// @param useCreate2 Whether to use create2 or not
362 function registerSingularity(
363 address mc,
364 bytes calldata data,
365 bool useCreate2
366 )
367 external
368 payable
369 onlyOwner
370 registeredSingularityMasterContract(mc)
371 returns (address _contract)
372 {
373 _contract = deploy(mc, data, useCreate2);
374 isMarketRegistered[_contract] = true;
375 emit RegisterSingularity(_contract, mc);
376 }
377
378 /// @notice Registers an existing Singularity market (without deployment)
379 /// @dev can only be called by the owner
380 /// @param mc The address of the master contract which must be already registered
381 function addSingularity(
382 address mc,
383 address _contract
384 ) external onlyOwner registeredSingularityMasterContract(mc) {
385 isMarketRegistered[_contract] = true;
386 clonesOf[mc].push(_contract);
387 emit RegisterSingularity(_contract, mc);
388 }
389
390 /// @notice Registers a BigBang market
391 /// @dev can only be called by the owner
392 /// @param mc The address of the master contract which must be already registered
393 /// @param data The init data of the BigBang contract
394 /// @param useCreate2 Whether to use create2 or not
395 function registerBigBang(
396 address mc,
397 bytes calldata data,
398 bool useCreate2
399 )
400 external
401 payable
402 onlyOwner
403 registeredBigBangMasterContract(mc)
404 returns (address _contract)
405 {
406 _contract = deploy(mc, data, useCreate2);
407 isMarketRegistered[_contract] = true;
408 emit RegisterBigBang(_contract, mc);
409 }
410
411 /// @notice Registers an existing BigBang market (without deployment)
412 /// @dev can only be called by the owner
413 /// @param mc The address of the master contract which must be already registered
414 function addBigBang(
415 address mc,
416 address _contract
417 ) external onlyOwner registeredBigBangMasterContract(mc) {
418 isMarketRegistered[_contract] = true;
419 clonesOf[mc].push(_contract);
420 emit RegisterBigBang(_contract, mc);
421 }
422
423 /// @notice Execute an only owner function inside of a Singularity or a BigBang market
424 function executeMarketFn(
425 address[] calldata mc,
426 bytes[] memory data,
427 bool forceSuccess
428 )
429 external
430 onlyOwner
431 notPaused
432 returns (bool[] memory success, bytes[] memory result)
433 {
434 uint256 len = mc.length;
435 success = new bool[](len);
436 result = new bytes[](len);
437 for (uint256 i = 0; i < len; ) {
438 require(
439 isSingularityMasterContractRegistered[
440 masterContractOf[mc[i]]
441 ] || isBigBangMasterContractRegistered[masterContractOf[mc[i]]],
442 "Penrose: MC not registered"
443 );
444 (success[i], result[i]) = mc[i].call(data[i]);
445 if (forceSuccess) {
446 require(success[i], _getRevertMsg(result[i]));
447 }
448 ++i;
449 }
450 }
451
452 /// @notice Set protocol fees address
453 /// @dev can only be called by the owner
454 /// @param feeTo_ the new feeTo address
455 function setFeeTo(address feeTo_) external onlyOwner {
456 feeTo = feeTo_;
457 emit FeeToUpdate(feeTo_);
458 }
459
460 /// @notice Used to register and enable or disable swapper contracts used in closed liquidations.
461 /// @dev can only be called by the owner
462 /// @param swapper The address of the swapper contract that conforms to `ISwapper`.
463 /// @param enable True to enable the swapper. To disable use False.
464 function setSwapper(ISwapper swapper, bool enable) external onlyOwner {
465 swappers[swapper] = enable;
466 emit SwapperUpdate(address(swapper), enable);
467 }
468
469 // ************************* //
470 // *** PRIVATE FUNCTIONS *** //
471 // ************************* //
472 function _getRevertMsg(
473 bytes memory _returnData
474 ) private pure returns (string memory) {
475 // If the _res length is less than 68, then the transaction failed silently (without a revert message)
476 if (_returnData.length < 68) return "SGL: no return data";
477 // solhint-disable-next-line no-inline-assembly
478 assembly {
479 // Slice the sighash.
480 _returnData := add(_returnData, 0x04)
481 }
482 return abi.decode(_returnData, (string)); // All that remains is the revert string
483 }
484
485 function _withdrawAllProtocolFees(
486 ISwapper[] calldata swappers_,
487 IPenrose.SwapData[] calldata swapData_,
488 IMarket[] memory markets_
489 ) private {
490 uint256 length = markets_.length;
491 unchecked {
492 for (uint256 i = 0; i < length; ) {
493 _depositFeesToYieldBox(markets_[i], swappers_[i], swapData_[i]);
494 ++i;
495 }
496 }
497 }
498
499 /// @notice Withdraw the balance of `feeTo`, swap asset into TAP and deposit it to yieldBox of `feeTo`
500 function _depositFeesToYieldBox(
501 IMarket market,
502 ISwapper swapper,
503 IPenrose.SwapData calldata dexData
504 ) private {
505 require(swappers[swapper], "Penrose: Invalid swapper");
506 require(isMarketRegistered[address(market)], "Penrose: Invalid market");
507
508 uint256 feeShares = market.refreshPenroseFees(feeTo);
509 if (feeShares == 0) return;
510
511 uint256 assetId = market.assetId();
512 uint256 amount = 0;
513 if (assetId != wethAssetId) {
514 yieldBox.transfer(
515 address(this),
516 address(swapper),
517 assetId,
518 feeShares
519 );
520
521 ISwapper.SwapData memory swapData = swapper.buildSwapData(
522 assetId,
523 wethAssetId,
524 0,
525 feeShares,
526 true,
527 true
528 );
529 (amount, ) = swapper.swap(
530 swapData,
531 dexData.minAssetAmount,
532 feeTo,
533 ""
534 );
535 } else {
536 yieldBox.transfer(address(this), feeTo, assetId, feeShares);
537 }
538
539 emit LogYieldBoxFeesDeposit(feeShares, amount);
540 }
541
542 function _getMasterContractLength(
543 IPenrose.MasterContract[] memory array
544 ) public view returns (address[] memory markets) {
545 uint256 _masterContractLength = array.length;
546 uint256 marketsLength = 0;
547
548 unchecked {
549 // We first compute the length of the markets array
550 for (uint256 i = 0; i < _masterContractLength; ) {
551 marketsLength += clonesOfCount(array[i].location);
552
553 ++i;
554 }
555 }
556
557 markets = new address[](marketsLength);
558
559 uint256 marketIndex;
560 uint256 clonesOfLength;
561
562 unchecked {
563 // We populate the array
564 for (uint256 i = 0; i < _masterContractLength; ) {
565 address mcLocation = array[i].location;
566 clonesOfLength = clonesOfCount(mcLocation);
567
568 // Loop through clones of the current MC.
569 for (uint256 j = 0; j < clonesOfLength; ) {
570 markets[marketIndex] = clonesOf[mcLocation][j];
571 ++marketIndex;
572 ++j;
573 }
574 ++i;
575 }
576 }
577 }
578: }
File: contracts/markets/Market.sol
14 abstract contract Market is MarketERC20, BoringOwnable {
15 using RebaseLibrary for Rebase;
16
17 // ************ //
18 // *** VARS *** //
19 // ************ //
20 /// @notice returns YieldBox address
21 YieldBox public yieldBox;
22 /// @notice returns Penrose address
23 IPenrose public penrose;
24
25 /// @notice collateral token address
26 IERC20 public collateral;
27 /// @notice collateral token YieldBox id
28 uint256 public collateralId;
29 /// @notice asset token address
30 IERC20 public asset;
31 /// @notice asset token YieldBox id
32 uint256 public assetId;
33
34 /// @notice contract's pause state
35 bool public paused;
36 /// @notice conservator's addresss
37 /// @dev conservator can pause/unpause the contract
38 address public conservator;
39
40 /// @notice oracle address
41 IOracle public oracle;
42 /// @notice oracleData
43 bytes public oracleData;
44 /// @notice Exchange and interest rate tracking.
45 /// This is 'cached' here because calls to Oracles can be very expensive.
46 /// Asset -> collateral = assetAmount * exchangeRate.
47 uint256 public exchangeRate;
48
49 /// @notice total amount borrowed
50 /// @dev elastic = Total token amount to be repayed by borrowers, base = Total parts of the debt held by borrowers
51 Rebase public totalBorrow;
52 /// @notice total collateral supplied
53 uint256 public totalCollateralShare;
54 /// @notice max borrow cap
55 uint256 public totalBorrowCap;
56 /// @notice borrow amount per user
57 mapping(address => uint256) public userBorrowPart;
58 /// @notice collateral share per user
59 mapping(address => uint256) public userCollateralShare;
60
61 /// @notice liquidation caller rewards
62 uint256 public callerFee; // 90%
63 /// @notice liquidation protocol rewards
64 uint256 public protocolFee; // 10%
65 /// @notice min % a liquidator can receive in rewards
66 uint256 public minLiquidatorReward = 1e3; //1%
67 /// @notice max % a liquidator can receive in rewards
68 uint256 public maxLiquidatorReward = 1e4; //10%
69 /// @notice max liquidatable bonus amount
70 /// @dev max % added to the amount that can be liquidated
71 uint256 public liquidationBonusAmount = 1e4; //10%
72 /// @notice collateralization rate
73 uint256 public collateralizationRate; // 75%
74 /// @notice borrowing opening fee
75 uint256 public borrowOpeningFee = 50; //0.05%
76 /// @notice liquidation multiplier used to compute liquidator rewards
77 uint256 public liquidationMultiplier = 12000; //12%
78
79 // ***************** //
80 // *** CONSTANTS *** //
81 // ***************** //
82 uint256 internal EXCHANGE_RATE_PRECISION; //not costant, but can only be set in the 'init' method
83 uint256 internal constant FEE_PRECISION = 1e5;
84 uint256 internal constant FEE_PRECISION_DECIMALS = 5;
85
86 // ************** //
87 // *** EVENTS *** //
88 // ************** //
89 /// @notice event emitted when conservator is updated
90 event ConservatorUpdated(address indexed old, address indexed _new);
91 /// @notice event emitted when pause state is changed
92 event PausedUpdated(bool oldState, bool newState);
93 /// @notice event emitted when cached exchange rate is updated
94 event LogExchangeRate(uint256 rate);
95 /// @notice event emitted when borrow cap is updated
96 event LogBorrowCapUpdated(uint256 _oldVal, uint256 _newVal);
97 /// @notice event emitted when oracle data is updated
98 event OracleDataUpdated();
99 /// @notice event emitted when oracle is updated
100 event OracleUpdated();
101 /// @notice event emitted when a position is liquidated
102 event Liquidated(
103 address liquidator,
104 address[] users,
105 uint256 liquidatorReward,
106 uint256 protocolReward,
107 uint256 repayedAmount,
108 uint256 collateralShareRemoved
109 );
110 /// @notice event emitted when borrow opening fee is updated
111 event LogBorrowingFee(uint256 _oldVal, uint256 _newVal);
112 /// @notice event emitted when the liquidation multiplier rate is updated
113 event LiquidationMultiplierUpdated(uint256 oldVal, uint256 newVal);
114
115 modifier notPaused() {
116 require(!paused, "Market: paused");
117 _;
118 }
119 /// @dev Checks if the user is solvent in the closed liquidation case at the end of the function body.
120 modifier solvent(address from) {
121 updateExchangeRate();
122 _accrue();
123
124 _;
125
126 require(_isSolvent(from, exchangeRate), "Market: insolvent");
127 }
128
129 bool internal initialized;
130 modifier onlyOnce() {
131 require(!initialized, "Market: initialized");
132 _;
133 initialized = true;
134 }
135
136 // *********************** //
137 // *** OWNER FUNCTIONS *** //
138 // *********************** //
139 /// @notice sets the borrowing opening fee
140 /// @dev can only be called by the owner
141 /// @param _val the new value
142 function setBorrowOpeningFee(uint256 _val) external onlyOwner {
143 require(_val <= FEE_PRECISION, "Market: not valid");
144 emit LogBorrowingFee(borrowOpeningFee, _val);
145 borrowOpeningFee = _val;
146 }
147
148 /// @notice sets max borrowable amount
149 /// @dev can only be called by the owner
150 /// @param _cap the new value
151 function setBorrowCap(uint256 _cap) external notPaused onlyOwner {
152 emit LogBorrowCapUpdated(totalBorrowCap, _cap);
153 totalBorrowCap = _cap;
154 }
155
156 /// @notice sets common market configuration
157 /// @dev values are updated only if > 0 or not address(0)
158 function setMarketConfig(
159 uint256 _borrowOpeningFee,
160 IOracle _oracle,
161 bytes calldata _oracleData,
162 address _conservator,
163 uint256 _callerFee,
164 uint256 _protocolFee,
165 uint256 _liquidationBonusAmount,
166 uint256 _minLiquidatorReward,
167 uint256 _maxLiquidatorReward,
168 uint256 _totalBorrowCap,
169 uint256 _collateralizationRate
170 ) external onlyOwner {
171 if (_borrowOpeningFee > 0) {
172 require(_borrowOpeningFee <= FEE_PRECISION, "Market: not valid");
173 emit LogBorrowingFee(borrowOpeningFee, _borrowOpeningFee);
174 borrowOpeningFee = _borrowOpeningFee;
175 }
176
177 if (address(_oracle) != address(0)) {
178 oracle = _oracle;
179 emit OracleUpdated();
180 }
181
182 if (_oracleData.length > 0) {
183 oracleData = _oracleData;
184 emit OracleDataUpdated();
185 }
186
187 if (_conservator != address(0)) {
188 emit ConservatorUpdated(conservator, _conservator);
189 conservator = _conservator;
190 }
191
192 if (_callerFee > 0) {
193 require(_callerFee <= FEE_PRECISION, "Market: not valid");
194 callerFee = _callerFee;
195 }
196
197 if (_protocolFee > 0) {
198 require(_protocolFee <= FEE_PRECISION, "Market: not valid");
199 protocolFee = _protocolFee;
200 }
201
202 if (_liquidationBonusAmount > 0) {
203 require(
204 _liquidationBonusAmount < FEE_PRECISION,
205 "Market: not valid"
206 );
207 liquidationBonusAmount = _liquidationBonusAmount;
208 }
209
210 if (_minLiquidatorReward > 0) {
211 require(_minLiquidatorReward < FEE_PRECISION, "Market: not valid");
212 require(
213 _minLiquidatorReward < maxLiquidatorReward,
214 "Market: not valid"
215 );
216 minLiquidatorReward = _minLiquidatorReward;
217 }
218
219 if (_maxLiquidatorReward > 0) {
220 require(_maxLiquidatorReward < FEE_PRECISION, "Market: not valid");
221 require(
222 _maxLiquidatorReward > minLiquidatorReward,
223 "Market: not valid"
224 );
225 maxLiquidatorReward = _maxLiquidatorReward;
226 }
227
228 if (_totalBorrowCap > 0) {
229 emit LogBorrowCapUpdated(totalBorrowCap, _totalBorrowCap);
230 totalBorrowCap = _totalBorrowCap;
231 }
232
233 if (_collateralizationRate > 0) {
234 require(
235 _collateralizationRate <= FEE_PRECISION,
236 "Market: not valid"
237 );
238 collateralizationRate = _collateralizationRate;
239 }
240 }
241
242 /// @notice updates the pause state of the contract
243 /// @dev can only be called by the conservator
244 /// @param val the new value
245 function updatePause(bool val) external {
246 require(msg.sender == conservator, "Market: unauthorized");
247 require(val != paused, "Market: same state");
248 emit PausedUpdated(paused, val);
249 paused = val;
250 }
251
252 // ********************** //
253 // *** VIEW FUNCTIONS *** //
254 // ********************** //
255 /// @notice returns the maximum liquidatable amount for user
256 function computeClosingFactor(
257 uint256 borrowPart,
258 uint256 collateralPartInAsset,
259 uint256 borrowPartDecimals,
260 uint256 collateralPartDecimals,
261 uint256 ratesPrecision
262 ) public view returns (uint256) {
263 uint256 borrowPartScaled = borrowPart;
264 if (borrowPartDecimals > 18) {
265 borrowPartScaled = borrowPart / (10 ** (borrowPartDecimals - 18));
266 }
267 if (borrowPartDecimals < 18) {
268 borrowPartScaled = borrowPart * (10 ** (18 - borrowPartDecimals));
269 }
270
271 uint256 collateralPartInAssetScaled = collateralPartInAsset;
272 if (collateralPartDecimals > 18) {
273 collateralPartInAssetScaled =
274 collateralPartInAsset /
275 (10 ** (collateralPartDecimals - 18));
276 }
277 if (collateralPartDecimals < 18) {
278 collateralPartInAssetScaled =
279 collateralPartInAsset *
280 (10 ** (18 - collateralPartDecimals));
281 }
282
283 uint256 liquidationStartsAt = (collateralPartInAssetScaled *
284 collateralizationRate) / (10 ** ratesPrecision);
285 if (borrowPartScaled < liquidationStartsAt) return 0;
286
287 uint256 numerator = borrowPartScaled -
288 ((collateralizationRate * collateralPartInAssetScaled) /
289 (10 ** ratesPrecision));
290 uint256 denominator = ((10 ** ratesPrecision) -
291 (collateralizationRate *
292 ((10 ** ratesPrecision) + liquidationMultiplier)) /
293 (10 ** ratesPrecision)) * (10 ** (18 - ratesPrecision));
294
295 uint256 x = (numerator * 1e18) / denominator;
296 return x;
297 }
298
299 /// @notice return the amount of collateral for a `user` to be solvent, min TVL and max TVL. Returns 0 if user already solvent.
300 /// @dev we use a `CLOSED_COLLATERIZATION_RATE` that is a safety buffer when making the user solvent again,
301 /// to prevent from being liquidated. This function is valid only if user is not solvent by `_isSolvent()`.
302 /// @param user The user to check solvency.
303 /// @param _exchangeRate the exchange rate asset/collateral.
304 /// @return amountToSolvency the amount of collateral to be solvent.
305 function computeTVLInfo(
306 address user,
307 uint256 _exchangeRate
308 )
309 public
310 view
311 returns (uint256 amountToSolvency, uint256 minTVL, uint256 maxTVL)
312 {
313 uint256 borrowPart = userBorrowPart[user];
314 if (borrowPart == 0) return (0, 0, 0);
315
316 Rebase memory _totalBorrow = totalBorrow;
317
318 uint256 collateralAmountInAsset = _computeMaxBorrowableAmount(
319 user,
320 _exchangeRate
321 );
322
323 borrowPart = (borrowPart * _totalBorrow.elastic) / _totalBorrow.base;
324
325 amountToSolvency = borrowPart >= collateralAmountInAsset
326 ? borrowPart - collateralAmountInAsset
327 : 0;
328
329 (minTVL, maxTVL) = _computeMaxAndMinLTVInAsset(
330 userCollateralShare[user],
331 _exchangeRate
332 );
333 }
334
335 /// @notice Gets the exchange rate. I.e how much collateral to buy 1e18 asset.
336 /// @dev This function is supposed to be invoked if needed because Oracle queries can be expensive.
337 /// Oracle should consider USDO at 1$
338 /// @return updated True if `exchangeRate` was updated.
339 /// @return rate The new exchange rate.
340 function updateExchangeRate() public returns (bool updated, uint256 rate) {
341 (updated, rate) = oracle.get("");
342
343 if (updated) {
344 require(rate > 0, "Market: invalid rate");
345 exchangeRate = rate;
346 emit LogExchangeRate(rate);
347 } else {
348 // Return the old rate if fetching wasn't successful
349 rate = exchangeRate;
350 }
351 }
352
353 /// @notice computes the possible liquidator reward
354 /// @notice user the user for which a liquidation operation should be performed
355 /// @param _exchangeRate the exchange rate asset/collateral to use for internal computations
356 function computeLiquidatorReward(
357 address user,
358 uint256 _exchangeRate
359 ) public view returns (uint256) {
360 (uint256 minTVL, uint256 maxTVL) = _computeMaxAndMinLTVInAsset(
361 userCollateralShare[user],
362 _exchangeRate
363 );
364 return _getCallerReward(userBorrowPart[user], minTVL, maxTVL);
365 }
366
367 // ************************** //
368 // *** INTERNAL FUNCTIONS *** //
369 // ************************** //
370 function _accrue() internal virtual;
371
372 function _getRevertMsg(
373 bytes memory _returnData
374 ) internal pure returns (string memory) {
375 // If the _res length is less than 68, then the transaction failed silently (without a revert message)
376 if (_returnData.length < 68) return "Market: no return data";
377 // solhint-disable-next-line no-inline-assembly
378 assembly {
379 // Slice the sighash.
380 _returnData := add(_returnData, 0x04)
381 }
382 return abi.decode(_returnData, (string)); // All that remains is the revert string
383 }
384
385 function _computeMaxBorrowableAmount(
386 address user,
387 uint256 _exchangeRate
388 ) internal view returns (uint256 collateralAmountInAsset) {
389 collateralAmountInAsset =
390 yieldBox.toAmount(
391 collateralId,
392 (userCollateralShare[user] *
393 (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
394 collateralizationRate),
395 false
396 ) /
397 _exchangeRate;
398 }
399
400 /// @notice Concrete implementation of `isSolvent`. Includes a parameter to allow caching `exchangeRate`.
401 /// @param _exchangeRate The exchange rate. Used to cache the `exchangeRate` between calls.
402 function _isSolvent(
403 address user,
404 uint256 _exchangeRate
405 ) internal view returns (bool) {
406 // accrue must have already been called!
407 uint256 borrowPart = userBorrowPart[user];
408 if (borrowPart == 0) return true;
409 uint256 collateralShare = userCollateralShare[user];
410 if (collateralShare == 0) return false;
411
412 Rebase memory _totalBorrow = totalBorrow;
413
414 return
415 yieldBox.toAmount(
416 collateralId,
417 collateralShare *
418 (EXCHANGE_RATE_PRECISION / FEE_PRECISION) *
419 collateralizationRate,
420 false
421 ) >=
422 // Moved exchangeRate here instead of dividing the other side to preserve more precision
423 (borrowPart * _totalBorrow.elastic * _exchangeRate) /
424 _totalBorrow.base;
425 }
426
427 /// @notice Returns the min and max LTV for user in asset price
428 function _computeMaxAndMinLTVInAsset(
429 uint256 collateralShare,
430 uint256 _exchangeRate
431 ) internal view returns (uint256 min, uint256 max) {
432 uint256 collateralAmount = yieldBox.toAmount(
433 collateralId,
434 collateralShare,
435 false
436 );
437
438 max = (collateralAmount * EXCHANGE_RATE_PRECISION) / _exchangeRate;
439 min = (max * collateralizationRate) / FEE_PRECISION;
440 }
441
442 function _getCallerReward(
443 uint256 borrowed,
444 uint256 startTVLInAsset,
445 uint256 maxTVLInAsset
446 ) internal view returns (uint256) {
447 if (borrowed == 0) return 0;
448 if (startTVLInAsset == 0) return 0;
449
450 if (borrowed < startTVLInAsset) return 0;
451 if (borrowed >= maxTVLInAsset) return minLiquidatorReward;
452
453 uint256 rewardPercentage = ((borrowed - startTVLInAsset) *
454 FEE_PRECISION) / (maxTVLInAsset - startTVLInAsset);
455
456 int256 diff = int256(minLiquidatorReward) - int256(maxLiquidatorReward);
457 int256 reward = (diff * int256(rewardPercentage)) /
458 int256(FEE_PRECISION) +
459 int256(maxLiquidatorReward);
460
461 return uint256(reward);
462 }
463
464 function _computeAllowanceAmountInAsset(
465 address user,
466 uint256 _exchangeRate,
467 uint256 borrowAmount,
468 uint256 assetDecimals
469 ) internal view returns (uint256) {
470 uint256 maxBorrowabe = _computeMaxBorrowableAmount(user, _exchangeRate);
471
472 uint256 shareRatio = _getRatio(
473 borrowAmount,
474 maxBorrowabe,
475 assetDecimals
476 );
477 return (shareRatio * userCollateralShare[user]) / (10 ** assetDecimals);
478 }
479
480 function _getRatio(
481 uint256 numerator,
482 uint256 denominator,
483 uint256 precision
484 ) private pure returns (uint256) {
485 if (numerator == 0 || denominator == 0) {
486 return 0;
487 }
488 uint256 _numerator = numerator * 10 ** (precision + 1);
489 uint256 _quotient = ((_numerator / denominator) + 5) / 10;
490 return (_quotient);
491 }
492: }
File: contracts/markets/bigBang/BigBang.sol
39 contract BigBang is BoringOwnable, Market {
40 using RebaseLibrary for Rebase;
41 using BoringERC20 for IERC20;
42
43 // ************ //
44 // *** VARS *** //
45 // ************ //
46 mapping(address => mapping(address => bool)) public operators;
47
48 IBigBang.AccrueInfo public accrueInfo;
49
50 uint256 public totalFees;
51
52 bool private _isEthMarket;
53 uint256 public maxDebtRate;
54 uint256 public minDebtRate;
55 uint256 public debtRateAgainstEthMarket;
56 uint256 public debtStartPoint;
57 uint256 private constant DEBT_PRECISION = 1e18;
58
59 // ************** //
60 // *** EVENTS *** //
61 // ************** //
62 /// @notice event emitted when accrue is called
63 event LogAccrue(uint256 accruedAmount, uint64 rate);
64 /// @notice event emitted when collateral is added
65 event LogAddCollateral(
66 address indexed from,
67 address indexed to,
68 uint256 share
69 );
70 /// @notice event emitted when collateral is removed
71 event LogRemoveCollateral(
72 address indexed from,
73 address indexed to,
74 uint256 share
75 );
76 /// @notice event emitted when borrow is performed
77 event LogBorrow(
78 address indexed from,
79 address indexed to,
80 uint256 amount,
81 uint256 feeAmount,
82 uint256 part
83 );
84 /// @notice event emitted when a repay operation is performed
85 event LogRepay(
86 address indexed from,
87 address indexed to,
88 uint256 amount,
89 uint256 part
90 );
91 /// @notice event emitted when the minimum debt rate is updated
92 event MinDebtRateUpdated(uint256 oldVal, uint256 newVal);
93 /// @notice event emitted when the maximum debt rate is updated
94 event MaxDebtRateUpdated(uint256 oldVal, uint256 newVal);
95 /// @notice event emitted when the debt rate against the main market is updated
96 event DebtRateAgainstEthUpdated(uint256 oldVal, uint256 newVal);
97
98 constructor() MarketERC20("Tapioca BigBang") {}
99
100 /// @notice The init function that acts as a constructor
101 function init(bytes calldata data) external onlyOnce {
102 (
103 IPenrose tapiocaBar_,
104 IERC20 _collateral,
105 uint256 _collateralId,
106 IOracle _oracle,
107 uint256 _exchangeRatePrecision,
108 uint256 _debtRateAgainstEth,
109 uint256 _debtRateMin,
110 uint256 _debtRateMax,
111 uint256 _debtStartPoint
112 ) = abi.decode(
113 data,
114 (
115 IPenrose,
116 IERC20,
117 uint256,
118 IOracle,
119 uint256,
120 uint256,
121 uint256,
122 uint256,
123 uint256
124 )
125 );
126
127 penrose = tapiocaBar_;
128 yieldBox = YieldBox(tapiocaBar_.yieldBox());
129 owner = address(penrose);
130
131 address _asset = penrose.usdoToken();
132
133 require(
134 address(_collateral) != address(0) &&
135 address(_asset) != address(0) &&
136 address(_oracle) != address(0),
137 "BigBang: bad pair"
138 );
139
140 asset = IERC20(_asset);
141 assetId = penrose.usdoAssetId();
142 collateral = _collateral;
143 collateralId = _collateralId;
144 oracle = _oracle;
145
146 updateExchangeRate();
147
148 callerFee = 90000; // 90%
149 protocolFee = 10000; // 10%
150 collateralizationRate = 75000; // 75%
151
152 EXCHANGE_RATE_PRECISION = _exchangeRatePrecision > 0
153 ? _exchangeRatePrecision
154 : 1e18;
155
156 _isEthMarket = collateralId == penrose.wethAssetId();
157 if (!_isEthMarket) {
158 debtRateAgainstEthMarket = _debtRateAgainstEth;
159 maxDebtRate = _debtRateMax;
160 minDebtRate = _debtRateMin;
161 debtStartPoint = _debtStartPoint;
162 }
163
164 minLiquidatorReward = 1e3;
165 maxLiquidatorReward = 1e4;
166 liquidationBonusAmount = 1e4;
167 borrowOpeningFee = 50; // 0.05%
168 liquidationMultiplier = 12000; //12%
169 }
170
171 // ********************** //
172 // *** VIEW FUNCTIONS *** //
173 // ********************** //
174 /// @notice returns total market debt
175 function getTotalDebt() external view returns (uint256) {
176 return totalBorrow.elastic;
177 }
178
179 /// @notice returns the current debt rate
180 function getDebtRate() public view returns (uint256) {
181 if (_isEthMarket) return penrose.bigBangEthDebtRate(); // default 0.5%
182 if (totalBorrow.elastic == 0) return minDebtRate;
183
184 uint256 _ethMarketTotalDebt = BigBang(penrose.bigBangEthMarket())
185 .getTotalDebt();
186 uint256 _currentDebt = totalBorrow.elastic;
187 uint256 _maxDebtPoint = (_ethMarketTotalDebt *
188 debtRateAgainstEthMarket) / 1e18;
189
190 if (_currentDebt >= _maxDebtPoint) return maxDebtRate;
191
192 uint256 debtPercentage = ((_currentDebt - debtStartPoint) *
193 DEBT_PRECISION) / (_maxDebtPoint - debtStartPoint);
194 uint256 debt = ((maxDebtRate - minDebtRate) * debtPercentage) /
195 DEBT_PRECISION +
196 minDebtRate;
197
198 if (debt > maxDebtRate) return maxDebtRate;
199
200 return debt;
201 }
202
203 // ************************ //
204 // *** PUBLIC FUNCTIONS *** //
205 // ************************ //
206 /// @notice Allows batched call to BingBang.
207 /// @param calls An array encoded call data.
208 /// @param revertOnFail If True then reverts after a failed call and stops doing further calls.
209 function execute(
210 bytes[] calldata calls,
211 bool revertOnFail
212 ) external returns (bool[] memory successes, string[] memory results) {
213 successes = new bool[](calls.length);
214 results = new string[](calls.length);
215 for (uint256 i = 0; i < calls.length; i++) {
216 (bool success, bytes memory result) = address(this).delegatecall(
217 calls[i]
218 );
219 require(success || !revertOnFail, _getRevertMsg(result));
220 successes[i] = success;
221 results[i] = _getRevertMsg(result);
222 }
223 }
224
225 /// @notice allows 'operator' to act on behalf of the sender
226 /// @param status true/false
227 function updateOperator(address operator, bool status) external {
228 operators[msg.sender][operator] = status;
229 }
230
231 /// @notice Accrues the interest on the borrowed tokens and handles the accumulation of fees.
232 function accrue() public {
233 _accrue();
234 }
235
236 /// @notice Sender borrows `amount` and transfers it to `to`.
237 /// @param from Account to borrow for.
238 /// @param to The receiver of borrowed tokens.
239 /// @param amount Amount to borrow.
240 /// @return part Total part of the debt held by borrowers.
241 /// @return share Total amount in shares borrowed.
242 function borrow(
243 address from,
244 address to,
245 uint256 amount
246 ) public notPaused solvent(from) returns (uint256 part, uint256 share) {
247 uint256 allowanceShare = _computeAllowanceAmountInAsset(
248 from,
249 exchangeRate,
250 amount,
251 asset.safeDecimals()
252 );
253 _allowedBorrow(from, allowanceShare);
254 (part, share) = _borrow(from, to, amount);
255 }
256
257 /// @notice Repays a loan.
258 /// @dev The bool param is not used but we added it to respect the ISingularity interface for MarketsHelper compatibility
259 /// @param from Address to repay from.
260 /// @param to Address of the user this payment should go.
261 /// @param part The amount to repay. See `userBorrowPart`.
262 /// @return amount The total amount repayed.
263 function repay(
264 address from,
265 address to,
266 bool,
267 uint256 part
268 ) public notPaused allowedBorrow(from, part) returns (uint256 amount) {
269 updateExchangeRate();
270
271 accrue();
272
273 amount = _repay(from, to, part);
274 }
275
276 /// @notice Adds `collateral` from msg.sender to the account `to`.
277 /// @param from Account to transfer shares from.
278 /// @param to The receiver of the tokens.
279 /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.
280 /// False if tokens from msg.sender in `yieldBox` should be transferred.
281 /// @param share The amount of shares to add for `to`.
282 function addCollateral(
283 address from,
284 address to,
285 bool skim,
286 uint256 amount,
287 uint256 share
288 ) public allowedBorrow(from, share) notPaused {
289 _addCollateral(from, to, skim, amount, share);
290 }
291
292 /// @notice Removes `share` amount of collateral and transfers it to `to`.
293 /// @param from Account to debit collateral from.
294 /// @param to The receiver of the shares.
295 /// @param share Amount of shares to remove.
296 function removeCollateral(
297 address from,
298 address to,
299 uint256 share
300 ) public notPaused solvent(from) allowedBorrow(from, share) {
301 _removeCollateral(from, to, share);
302 }
303
304 /// @notice Entry point for liquidations.
305 /// @param users An array of user addresses.
306 /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
307 /// @param swapper Contract address of the `MultiSwapper` implementation. See `setSwapper`.
308 /// @param collateralToAssetSwapData Extra swap data
309 function liquidate(
310 address[] calldata users,
311 uint256[] calldata maxBorrowParts,
312 ISwapper swapper,
313 bytes calldata collateralToAssetSwapData
314 ) external notPaused {
315 // Oracle can fail but we still need to allow liquidations
316 (, uint256 _exchangeRate) = updateExchangeRate();
317 _accrue();
318
319 _closedLiquidation(
320 users,
321 maxBorrowParts,
322 swapper,
323 _exchangeRate,
324 collateralToAssetSwapData
325 );
326 }
327
328 /// @notice Lever up: Borrow more and buy collateral with it.
329 /// @param from The user who buys
330 /// @param borrowAmount Amount of extra asset borrowed
331 /// @param supplyAmount Amount of asset supplied (down payment)
332 /// @param minAmountOut Mininal collateral amount to receive
333 /// @param swapper Swapper to execute the purchase
334 /// @param dexData Additional data to pass to the swapper
335 /// @return amountOut Actual collateral amount purchased
336 function buyCollateral(
337 address from,
338 uint256 borrowAmount,
339 uint256 supplyAmount,
340 uint256 minAmountOut,
341 ISwapper swapper,
342 bytes calldata dexData
343 ) external notPaused solvent(from) returns (uint256 amountOut) {
344 require(penrose.swappers(swapper), "SGL: Invalid swapper");
345
346 // Let this fail first to save gas:
347 uint256 supplyShare = yieldBox.toShare(assetId, supplyAmount, true);
348 if (supplyShare > 0) {
349 yieldBox.transfer(from, address(swapper), assetId, supplyShare);
350 }
351
352 uint256 borrowShare;
353 (, borrowShare) = _borrow(from, address(swapper), borrowAmount);
354
355 ISwapper.SwapData memory swapData = swapper.buildSwapData(
356 assetId,
357 collateralId,
358 0,
359 supplyShare + borrowShare,
360 true,
361 true
362 );
363
364 uint256 collateralShare;
365 (amountOut, collateralShare) = swapper.swap(
366 swapData,
367 minAmountOut,
368 from,
369 dexData
370 );
371 require(amountOut >= minAmountOut, "SGL: not enough");
372
373 _allowedBorrow(from, collateralShare);
374 _addCollateral(from, from, false, 0, collateralShare);
375 }
376
377 /// @notice Lever down: Sell collateral to repay debt; excess goes to YB
378 /// @param from The user who sells
379 /// @param share Collateral YieldBox-shares to sell
380 /// @param minAmountOut Mininal proceeds required for the sale
381 /// @param swapper Swapper to execute the sale
382 /// @param dexData Additional data to pass to the swapper
383 /// @return amountOut Actual asset amount received in the sale
384 function sellCollateral(
385 address from,
386 uint256 share,
387 uint256 minAmountOut,
388 ISwapper swapper,
389 bytes calldata dexData
390 ) external notPaused solvent(from) returns (uint256 amountOut) {
391 require(penrose.swappers(swapper), "SGL: Invalid swapper");
392
393 _allowedBorrow(from, share);
394 _removeCollateral(from, address(swapper), share);
395 ISwapper.SwapData memory swapData = swapper.buildSwapData(
396 collateralId,
397 assetId,
398 0,
399 share,
400 true,
401 true
402 );
403 uint256 shareOut;
404 (amountOut, shareOut) = swapper.swap(
405 swapData,
406 minAmountOut,
407 from,
408 dexData
409 );
410 // As long as the ratio is correct, we trust `amountOut` resp.
411 // `shareOut`, because all money received by the swapper gets used up
412 // one way or another, or the transaction will revert.
413 require(amountOut >= minAmountOut, "SGL: not enough");
414 uint256 partOwed = userBorrowPart[from];
415 uint256 amountOwed = totalBorrow.toElastic(partOwed, true);
416 uint256 shareOwed = yieldBox.toShare(assetId, amountOwed, true);
417 if (shareOwed <= shareOut) {
418 _repay(from, from, partOwed);
419 } else {
420 //repay as much as we can
421 uint256 partOut = totalBorrow.toBase(amountOut, false);
422 _repay(from, from, partOut);
423 }
424 }
425
426 function transfer(
427 address to,
428 uint256 amount
429 ) public override returns (bool) {}
430
431 function transferFrom(
432 address from,
433 address to,
434 uint256 amount
435 ) public override returns (bool) {}
436
437 // ************************* //
438 // *** OWNER FUNCTIONS ***** //
439 // ************************* //
440
441 /// @notice Transfers fees to penrose
442 function refreshPenroseFees(
443 address
444 ) external onlyOwner notPaused returns (uint256 feeShares) {
445 uint256 balance = asset.balanceOf(address(this));
446 totalFees += balance;
447 feeShares = yieldBox.toShare(assetId, totalFees, false);
448
449 if (totalFees > 0) {
450 asset.approve(address(yieldBox), totalFees);
451
452 yieldBox.depositAsset(
453 assetId,
454 address(this),
455 msg.sender,
456 totalFees,
457 0
458 );
459
460 totalFees = 0;
461 }
462 }
463
464 /// @notice sets BigBang specific configuration
465 /// @dev values are updated only if > 0 or not address(0)
466 function setBigBangConfig(
467 uint256 _minDebtRate,
468 uint256 _maxDebtRate,
469 uint256 _debtRateAgainstEthMarket,
470 uint256 _liquidationMultiplier
471 ) external onlyOwner {
472 _isEthMarket = collateralId == penrose.wethAssetId();
473
474 if (!_isEthMarket) {
475 if (_minDebtRate > 0) {
476 require(_minDebtRate < maxDebtRate, "BigBang: not valid");
477 emit MinDebtRateUpdated(minDebtRate, _minDebtRate);
478 minDebtRate = _minDebtRate;
479 }
480
481 if (_maxDebtRate > 0) {
482 require(_maxDebtRate > minDebtRate, "BigBang: not valid");
483 emit MaxDebtRateUpdated(maxDebtRate, _maxDebtRate);
484 maxDebtRate = _maxDebtRate;
485 }
486
487 if (_debtRateAgainstEthMarket > 0) {
488 emit DebtRateAgainstEthUpdated(
489 debtRateAgainstEthMarket,
490 _debtRateAgainstEthMarket
491 );
492 debtRateAgainstEthMarket = _debtRateAgainstEthMarket;
493 }
494
495 if (_liquidationMultiplier > 0) {
496 require(
497 _liquidationMultiplier < FEE_PRECISION,
498 "BigBang: not valid"
499 );
500 emit LiquidationMultiplierUpdated(
501 liquidationMultiplier,
502 _liquidationMultiplier
503 );
504 liquidationMultiplier = _liquidationMultiplier;
505 }
506 }
507 }
508
509 // ************************* //
510 // *** PRIVATE FUNCTIONS *** //
511 // ************************* //
512 function _accrue() internal override {
513 IBigBang.AccrueInfo memory _accrueInfo = accrueInfo;
514 // Number of seconds since accrue was called
515 uint256 elapsedTime = block.timestamp - _accrueInfo.lastAccrued;
516 if (elapsedTime == 0) {
517 return;
518 }
519 //update debt rate
520 uint256 annumDebtRate = getDebtRate();
521 _accrueInfo.debtRate = uint64(annumDebtRate / 31536000); //per second
522
523 _accrueInfo.lastAccrued = uint64(block.timestamp);
524
525 Rebase memory _totalBorrow = totalBorrow;
526
527 uint256 extraAmount = 0;
528
529 // Calculate fees
530 extraAmount =
531 (uint256(_totalBorrow.elastic) *
532 _accrueInfo.debtRate *
533 elapsedTime) /
534 1e18;
535 _totalBorrow.elastic += uint128(extraAmount);
536
537 totalBorrow = _totalBorrow;
538 accrueInfo = _accrueInfo;
539
540 emit LogAccrue(extraAmount, _accrueInfo.debtRate);
541 }
542
543 function _addCollateral(
544 address from,
545 address to,
546 bool skim,
547 uint256 amount,
548 uint256 share
549 ) internal {
550 if (share == 0) {
551 share = yieldBox.toShare(collateralId, amount, false);
552 }
553 userCollateralShare[to] += share;
554 uint256 oldTotalCollateralShare = totalCollateralShare;
555 totalCollateralShare = oldTotalCollateralShare + share;
556 _addTokens(from, collateralId, share, oldTotalCollateralShare, skim);
557 emit LogAddCollateral(skim ? address(yieldBox) : from, to, share);
558 }
559
560 function _liquidateUser(
561 address user,
562 uint256 maxBorrowPart,
563 ISwapper swapper,
564 uint256 _exchangeRate,
565 bytes calldata _dexData
566 ) private {
567 if (_isSolvent(user, _exchangeRate)) return;
568
569 (
570 uint256 startTVLInAsset,
571 uint256 maxTVLInAsset
572 ) = _computeMaxAndMinLTVInAsset(
573 userCollateralShare[user],
574 _exchangeRate
575 );
576 uint256 callerReward = _getCallerReward(
577 userBorrowPart[user],
578 startTVLInAsset,
579 maxTVLInAsset
580 );
581
582 (
583 uint256 borrowAmount,
584 uint256 borrowPart,
585 uint256 collateralShare
586 ) = _updateBorrowAndCollateralShare(user, maxBorrowPart, _exchangeRate);
587 emit LogRemoveCollateral(user, address(swapper), collateralShare);
588 emit LogRepay(address(swapper), user, borrowAmount, borrowPart);
589
590 uint256 borrowShare = yieldBox.toShare(assetId, borrowAmount, true);
591
592 // Closed liquidation using a pre-approved swapper
593 require(penrose.swappers(swapper), "BigBang: Invalid swapper");
594
595 // Swaps the users collateral for the borrowed asset
596 yieldBox.transfer(
597 address(this),
598 address(swapper),
599 collateralId,
600 collateralShare
601 );
602
603 uint256 minAssetMount = 0;
604 if (_dexData.length > 0) {
605 minAssetMount = abi.decode(_dexData, (uint256));
606 }
607
608 uint256 balanceBefore = yieldBox.balanceOf(address(this), assetId);
609
610 ISwapper.SwapData memory swapData = swapper.buildSwapData(
611 collateralId,
612 assetId,
613 0,
614 collateralShare,
615 true,
616 true
617 );
618 swapper.swap(swapData, minAssetMount, address(this), "");
619 uint256 balanceAfter = yieldBox.balanceOf(address(this), assetId);
620
621 uint256 returnedShare = balanceAfter - balanceBefore;
622 (uint256 feeShare, uint256 callerShare) = _extractLiquidationFees(
623 returnedShare,
624 borrowShare,
625 callerReward
626 );
627 address[] memory _users = new address[](1);
628 _users[0] = user;
629 emit Liquidated(
630 msg.sender,
631 _users,
632 callerShare,
633 feeShare,
634 borrowAmount,
635 collateralShare
636 );
637 }
638
639 function _extractLiquidationFees(
640 uint256 returnedShare,
641 uint256 borrowShare,
642 uint256 callerReward
643 ) private returns (uint256 feeShare, uint256 callerShare) {
644 uint256 extraShare = returnedShare - borrowShare;
645 feeShare = (extraShare * protocolFee) / FEE_PRECISION; // x% of profit goes to fee.
646 callerShare = (extraShare * callerReward) / FEE_PRECISION; // y% of profit goes to caller.
647
648 yieldBox.transfer(address(this), penrose.feeTo(), assetId, feeShare);
649 yieldBox.transfer(address(this), msg.sender, assetId, callerShare);
650 }
651
652 /// @notice Handles the liquidation of users' balances, once the users' amount of collateral is too low.
653 /// @dev Closed liquidations Only, 90% of extra shares goes to caller and 10% to protocol
654 /// @param users An array of user addresses.
655 /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
656 /// @param swapper Contract address of the `MultiSwapper` implementation. See `setSwapper`.
657 /// @param swapData Swap necessar data
658 function _closedLiquidation(
659 address[] calldata users,
660 uint256[] calldata maxBorrowParts,
661 ISwapper swapper,
662 uint256 _exchangeRate,
663 bytes calldata swapData
664 ) private {
665 uint256 liquidatedCount = 0;
666 for (uint256 i = 0; i < users.length; i++) {
667 address user = users[i];
668 if (!_isSolvent(user, _exchangeRate)) {
669 liquidatedCount++;
670 _liquidateUser(
671 user,
672 maxBorrowParts[i],
673 swapper,
674 _exchangeRate,
675 swapData
676 );
677 }
678 }
679
680 require(liquidatedCount > 0, "SGL: no users found");
681 }
682
683 /// @dev Helper function to move tokens.
684 /// @param from Account to debit tokens from, in `yieldBox`.
685 /// @param _tokenId The ERC-20 token asset ID in yieldBox.
686 /// @param share The amount in shares to add.
687 /// @param total Grand total amount to deduct from this contract's balance. Only applicable if `skim` is True.
688 /// Only used for accounting checks.
689 /// @param skim If True, only does a balance check on this contract.
690 /// False if tokens from msg.sender in `yieldBox` should be transferred.
691 function _addTokens(
692 address from,
693 uint256 _tokenId,
694 uint256 share,
695 uint256 total,
696 bool skim
697 ) internal {
698 if (skim) {
699 require(
700 share <= yieldBox.balanceOf(address(this), _tokenId) - total,
701 "BigBang: too much"
702 );
703 } else {
704 yieldBox.transfer(from, address(this), _tokenId, share);
705 }
706 }
707
708 /// @dev Concrete implementation of `removeCollateral`.
709 function _removeCollateral(
710 address from,
711 address to,
712 uint256 share
713 ) internal {
714 userCollateralShare[from] -= share;
715 totalCollateralShare -= share;
716 emit LogRemoveCollateral(from, to, share);
717 yieldBox.transfer(address(this), to, collateralId, share);
718 }
719
720 /// @dev Concrete implementation of `repay`.
721 function _repay(
722 address from,
723 address to,
724 uint256 part
725 ) internal returns (uint256 amount) {
726 (totalBorrow, amount) = totalBorrow.sub(part, true);
727
728 userBorrowPart[to] -= part;
729
730 uint256 toWithdraw = (amount - part); //acrrued
731 uint256 toBurn = amount - toWithdraw;
732 yieldBox.withdraw(assetId, from, address(this), amount, 0);
733 //burn USDO
734 if (toBurn > 0) {
735 IUSDOBase(address(asset)).burn(address(this), toBurn);
736 }
737
738 emit LogRepay(from, to, amount, part);
739 }
740
741 /// @dev Concrete implementation of `borrow`.
742 function _borrow(
743 address from,
744 address to,
745 uint256 amount
746 ) internal returns (uint256 part, uint256 share) {
747 uint256 feeAmount = (amount * borrowOpeningFee) / FEE_PRECISION; // A flat % fee is charged for any borrow
748
749 (totalBorrow, part) = totalBorrow.add(amount + feeAmount, true);
750 require(
751 totalBorrowCap == 0 || totalBorrow.elastic <= totalBorrowCap,
752 "BigBang: borrow cap reached"
753 );
754
755 userBorrowPart[from] += part;
756
757 //mint USDO
758 IUSDOBase(address(asset)).mint(address(this), amount);
759
760 //deposit borrowed amount to user
761 asset.approve(address(yieldBox), amount);
762 yieldBox.depositAsset(assetId, address(this), to, amount, 0);
763
764 share = yieldBox.toShare(assetId, amount, false);
765
766 emit LogBorrow(from, to, amount, feeAmount, part);
767 }
768
769 function _updateBorrowAndCollateralShare(
770 address user,
771 uint256 maxBorrowPart,
772 uint256 _exchangeRate
773 )
774 private
775 returns (
776 uint256 borrowAmount,
777 uint256 borrowPart,
778 uint256 collateralShare
779 )
780 {
781 uint256 collateralPartInAsset = (yieldBox.toAmount(
782 collateralId,
783 userCollateralShare[user],
784 false
785 ) * EXCHANGE_RATE_PRECISION) / _exchangeRate;
786
787 uint256 borrowAssetDecimals = asset.safeDecimals();
788 uint256 collateralDecimals = collateral.safeDecimals();
789
790 uint256 availableBorrowPart = computeClosingFactor(
791 userBorrowPart[user],
792 collateralPartInAsset,
793 borrowAssetDecimals,
794 collateralDecimals,
795 FEE_PRECISION_DECIMALS
796 );
797 borrowPart = maxBorrowPart > availableBorrowPart
798 ? availableBorrowPart
799 : maxBorrowPart;
800
801 if (borrowPart > userBorrowPart[user]) {
802 borrowPart = userBorrowPart[user];
803 }
804
805 userBorrowPart[user] = userBorrowPart[user] - borrowPart;
806
807 borrowAmount = totalBorrow.toElastic(borrowPart, false);
808 uint256 amountWithBonus = borrowAmount +
809 (borrowAmount * liquidationMultiplier) /
810 FEE_PRECISION;
811 collateralShare = yieldBox.toShare(
812 collateralId,
813 (amountWithBonus * _exchangeRate) / EXCHANGE_RATE_PRECISION,
814 false
815 );
816 if (collateralShare > userCollateralShare[user]) {
817 collateralShare = userCollateralShare[user];
818 }
819 userCollateralShare[user] -= collateralShare;
820 require(borrowAmount != 0, "SGL: solvent");
821
822 totalBorrow.elastic -= uint128(borrowAmount);
823 totalBorrow.base -= uint128(borrowPart);
824 }
825: }
File: contracts/markets/singularity/Singularity.sol
37 contract Singularity is SGLCommon {
38 using RebaseLibrary for Rebase;
39
40 // ************ //
41 // *** VARS *** //
42 // ************ //
43 /// @notice enum representing each type of module associated with a Singularity market
44 /// @dev modules are contracts that holds a portion of the market's logic
45 enum Module {
46 Base,
47 Borrow,
48 Collateral,
49 Liquidation,
50 Leverage
51 }
52 /// @notice returns the liquidation module
53 SGLLiquidation public liquidationModule;
54 /// @notice returns the borrow module
55 SGLBorrow public borrowModule;
56 /// @notice returns the collateral module
57 SGLCollateral public collateralModule;
58 /// @notice returns the leverage module
59 SGLLeverage public leverageModule;
60
61 /// @notice The init function that acts as a constructor
62 function init(bytes calldata data) external onlyOnce {
63 (
64 address _liquidationModule,
65 address _borrowModule,
66 address _collateralModule,
67 address _leverageModule,
68 IPenrose tapiocaBar_,
69 IERC20 _asset,
70 uint256 _assetId,
71 IERC20 _collateral,
72 uint256 _collateralId,
73 IOracle _oracle,
74 uint256 _exchangeRatePrecision
75 ) = abi.decode(
76 data,
77 (
78 address,
79 address,
80 address,
81 address,
82 IPenrose,
83 IERC20,
84 uint256,
85 IERC20,
86 uint256,
87 IOracle,
88 uint256
89 )
90 );
91
92 liquidationModule = SGLLiquidation(_liquidationModule);
93 collateralModule = SGLCollateral(_collateralModule);
94 borrowModule = SGLBorrow(_borrowModule);
95 leverageModule = SGLLeverage(_leverageModule);
96 penrose = tapiocaBar_;
97 yieldBox = YieldBox(tapiocaBar_.yieldBox());
98 owner = address(penrose);
99
100 require(
101 address(_collateral) != address(0) &&
102 address(_asset) != address(0) &&
103 address(_oracle) != address(0),
104 "SGL: bad pair"
105 );
106 asset = _asset;
107 collateral = _collateral;
108 assetId = _assetId;
109 collateralId = _collateralId;
110 oracle = _oracle;
111
112 minimumInterestPerSecond = 951293760; // approx 3% APR
113 maximumInterestPerSecond = 2536783360; // approx 8% APR
114 interestElasticity = 7200e36; // Half or double in 28800 seconds (1 hours) if linear
115 startingInterestPerSecond = minimumInterestPerSecond;
116
117 accrueInfo.interestPerSecond = uint64(startingInterestPerSecond); // 1% APR, with 1e18 being 100%
118
119 updateExchangeRate();
120
121 //default fees
122 callerFee = 1000; // 1%
123 protocolFee = 10000; // 10%
124 borrowOpeningFee = 50; // 0.05%
125
126 //liquidation
127 liquidationMultiplier = 12000; //12%
128
129 collateralizationRate = 75000;
130 lqCollateralizationRate = 25000;
131 EXCHANGE_RATE_PRECISION = _exchangeRatePrecision > 0
132 ? _exchangeRatePrecision
133 : 1e18;
134
135 minLiquidatorReward = 1e3;
136 maxLiquidatorReward = 1e4;
137 liquidationBonusAmount = 1e4;
138
139 minimumTargetUtilization = 3e17;
140 maximumTargetUtilization = 5e17;
141 fullUtilizationMinusMax = FULL_UTILIZATION - maximumTargetUtilization;
142 }
143
144 // ********************** //
145 // *** VIEW FUNCTIONS *** //
146 // ********************** //
147 /// @notice transforms amount to shares for a market's permit operation
148 /// @param amount the amount to transform
149 /// @param tokenId the YieldBox asset id
150 /// @return share amount transformed into shares
151 function computeAllowedLendShare(
152 uint256 amount,
153 uint256 tokenId
154 ) external view returns (uint256 share) {
155 uint256 allShare = totalAsset.elastic +
156 yieldBox.toShare(tokenId, totalBorrow.elastic, true);
157 share = (amount * allShare) / totalAsset.base;
158 }
159
160 /// @notice returns Total yieldBox shares for user
161 /// @param _user The user to check shares for
162 /// @param _assetId The asset id to check shares for
163 /// @return shares value
164 function yieldBoxShares(
165 address _user,
166 uint256 _assetId
167 ) external view returns (uint256) {
168 bytes32 sig = _assetId == assetId ? ASSET_SIG : COLLATERAL_SIG;
169 return
170 yieldBox.balanceOf(_user, _assetId) + _yieldBoxShares[_user][sig];
171 }
172
173 // ************************ //
174 // *** PUBLIC FUNCTIONS *** //
175 // ************************ //
176 /// @notice Allows batched call to Singularity.
177 /// @param calls An array encoded call data.
178 /// @param revertOnFail If True then reverts after a failed call and stops doing further calls.
179 /// @return successes count of successful operations
180 /// @return results array of revert messages
181 function execute(
182 bytes[] calldata calls,
183 bool revertOnFail
184 ) external returns (bool[] memory successes, string[] memory results) {
185 successes = new bool[](calls.length);
186 results = new string[](calls.length);
187 for (uint256 i = 0; i < calls.length; i++) {
188 (bool success, bytes memory result) = address(this).delegatecall(
189 calls[i]
190 );
191 require(success || !revertOnFail, _getRevertMsg(result));
192 successes[i] = success;
193 results[i] = _getRevertMsg(result);
194 }
195 }
196
197 /// @notice Adds assets to the lending pair.
198 /// @param from Address to add asset from.
199 /// @param to The address of the user to receive the assets.
200 /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.
201 /// False if tokens from msg.sender in `yieldBox` should be transferred.
202 /// @param share The amount of shares to add.
203 /// @return fraction Total fractions added.
204 function addAsset(
205 address from,
206 address to,
207 bool skim,
208 uint256 share
209 ) public notPaused allowedLend(from, share) returns (uint256 fraction) {
210 _accrue();
211 fraction = _addAsset(from, to, skim, share);
212 }
213
214 /// @notice Removes an asset from msg.sender and transfers it to `to`.
215 /// @param from Account to debit Assets from.
216 /// @param to The user that receives the removed assets.
217 /// @param fraction The amount/fraction of assets held to remove.
218 /// @return share The amount of shares transferred to `to`.
219 function removeAsset(
220 address from,
221 address to,
222 uint256 fraction
223 ) public notPaused returns (uint256 share) {
224 _accrue();
225 share = _removeAsset(from, to, fraction, true);
226 _allowedLend(from, share);
227 }
228
229 /// @notice Adds `collateral` from msg.sender to the account `to`.
230 /// @param from Account to transfer shares from.
231 /// @param to The receiver of the tokens.
232 /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.
233 /// False if tokens from msg.sender in `yieldBox` should be transferred.
234 /// @param share The amount of shares to add for `to`.
235 function addCollateral(
236 address from,
237 address to,
238 bool skim,
239 uint256 amount,
240 uint256 share
241 ) public {
242 _executeModule(
243 Module.Collateral,
244 abi.encodeWithSelector(
245 SGLCollateral.addCollateral.selector,
246 from,
247 to,
248 skim,
249 amount,
250 share
251 )
252 );
253 }
254
255 /// @notice Removes `share` amount of collateral and transfers it to `to`.
256 /// @param from Account to debit collateral from.
257 /// @param to The receiver of the shares.
258 /// @param share Amount of shares to remove.
259 function removeCollateral(address from, address to, uint256 share) public {
260 _executeModule(
261 Module.Collateral,
262 abi.encodeWithSelector(
263 SGLCollateral.removeCollateral.selector,
264 from,
265 to,
266 share
267 )
268 );
269 }
270
271 /// @notice Sender borrows `amount` and transfers it to `to`.
272 /// @param from Account to borrow for.
273 /// @param to The receiver of borrowed tokens.
274 /// @param amount Amount to borrow.
275 /// @return part Total part of the debt held by borrowers.
276 /// @return share Total amount in shares borrowed.
277 function borrow(
278 address from,
279 address to,
280 uint256 amount
281 ) public returns (uint256 part, uint256 share) {
282 bytes memory result = _executeModule(
283 Module.Borrow,
284 abi.encodeWithSelector(SGLBorrow.borrow.selector, from, to, amount)
285 );
286 (part, share) = abi.decode(result, (uint256, uint256));
287 }
288
289 /// @notice Repays a loan.
290 /// @param from Address to repay from.
291 /// @param to Address of the user this payment should go.
292 /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.
293 /// False if tokens from msg.sender in `yieldBox` should be transferred.
294 /// @param part The amount to repay. See `userBorrowPart`.
295 /// @return amount The total amount repayed.
296 function repay(
297 address from,
298 address to,
299 bool skim,
300 uint256 part
301 ) public returns (uint256 amount) {
302 bytes memory result = _executeModule(
303 Module.Borrow,
304 abi.encodeWithSelector(
305 SGLBorrow.repay.selector,
306 from,
307 to,
308 skim,
309 part
310 )
311 );
312 amount = abi.decode(result, (uint256));
313 }
314
315 /// @notice Lever down: Sell collateral to repay debt; excess goes to YB
316 /// @param from The user who sells
317 /// @param share Collateral YieldBox-shares to sell
318 /// @param minAmountOut Mininal proceeds required for the sale
319 /// @param swapper Swapper to execute the sale
320 /// @param dexData Additional data to pass to the swapper
321 /// @return amountOut Actual asset amount received in the sale
322 function sellCollateral(
323 address from,
324 uint256 share,
325 uint256 minAmountOut,
326 ISwapper swapper,
327 bytes calldata dexData
328 ) external returns (uint256 amountOut) {
329 bytes memory result = _executeModule(
330 Module.Leverage,
331 abi.encodeWithSelector(
332 SGLLeverage.sellCollateral.selector,
333 from,
334 share,
335 minAmountOut,
336 swapper,
337 dexData
338 )
339 );
340 amountOut = abi.decode(result, (uint256));
341 }
342
343 /// @notice Lever up: Borrow more and buy collateral with it.
344 /// @param from The user who buys
345 /// @param borrowAmount Amount of extra asset borrowed
346 /// @param supplyAmount Amount of asset supplied (down payment)
347 /// @param minAmountOut Mininal collateral amount to receive
348 /// @param swapper Swapper to execute the purchase
349 /// @param dexData Additional data to pass to the swapper
350 /// @return amountOut Actual collateral amount purchased
351 function buyCollateral(
352 address from,
353 uint256 borrowAmount,
354 uint256 supplyAmount,
355 uint256 minAmountOut,
356 ISwapper swapper,
357 bytes calldata dexData
358 ) external returns (uint256 amountOut) {
359 bytes memory result = _executeModule(
360 Module.Leverage,
361 abi.encodeWithSelector(
362 SGLLeverage.buyCollateral.selector,
363 from,
364 borrowAmount,
365 supplyAmount,
366 minAmountOut,
367 swapper,
368 dexData
369 )
370 );
371 amountOut = abi.decode(result, (uint256));
372 }
373
374 /// @notice Level up cross-chain: Borrow more and buy collateral with it.
375 /// @param from The user who sells
376 /// @param collateralAmount Extra collateral to be added
377 /// @param borrowAmount Borrowed amount that will be swapped into collateral
378 /// @param swapData Swap data used on destination chain for swapping USDO to the underlying TOFT token
379 /// @param lzData LayerZero specific data
380 /// @param externalData External contracts used for the cross chain operation
381 function multiHopBuyCollateral(
382 address from,
383 uint256 collateralAmount,
384 uint256 borrowAmount,
385 IUSDOBase.ILeverageSwapData calldata swapData,
386 IUSDOBase.ILeverageLZData calldata lzData,
387 IUSDOBase.ILeverageExternalContractsData calldata externalData
388 ) external payable {
389 _executeModule(
390 Module.Leverage,
391 abi.encodeWithSelector(
392 SGLLeverage.multiHopBuyCollateral.selector,
393 from,
394 collateralAmount,
395 borrowAmount,
396 swapData,
397 lzData,
398 externalData
399 )
400 );
401 }
402
403 /// @notice Level up cross-chain: Borrow more and buy collateral with it.
404 /// @param from The user who sells
405 /// @param share Collateral YieldBox-shares to sell
406 /// @param swapData Swap data used on destination chain for swapping USDO to the underlying TOFT token
407 /// @param lzData LayerZero specific data
408 /// @param externalData External contracts used for the cross chain operation
409 function multiHopSellCollateral(
410 address from,
411 uint256 share,
412 IUSDOBase.ILeverageSwapData calldata swapData,
413 IUSDOBase.ILeverageLZData calldata lzData,
414 IUSDOBase.ILeverageExternalContractsData calldata externalData
415 ) external payable {
416 _executeModule(
417 Module.Leverage,
418 abi.encodeWithSelector(
419 SGLLeverage.multiHopSellCollateral.selector,
420 from,
421 share,
422 swapData,
423 lzData,
424 externalData
425 )
426 );
427 }
428
429 /// @notice Entry point for liquidations.
430 /// @dev Will call `closedLiquidation()` if not LQ exists or no LQ bid avail exists. Otherwise use LQ.
431 /// @param users An array of user addresses.
432 /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
433 /// Ignore for `orderBookLiquidation()`
434 /// @param swapper Contract address of the `MultiSwapper` implementation. See `setSwapper`.
435 /// Ignore for `orderBookLiquidation()`
436 /// @param collateralToAssetSwapData Extra swap data
437 /// Ignore for `orderBookLiquidation()`
438 /// @param usdoToBorrowedSwapData Extra swap data
439 /// Ignore for `closedLiquidation()`
440 function liquidate(
441 address[] calldata users,
442 uint256[] calldata maxBorrowParts,
443 ISwapper swapper,
444 bytes calldata collateralToAssetSwapData,
445 bytes calldata usdoToBorrowedSwapData
446 ) external {
447 _executeModule(
448 Module.Liquidation,
449 abi.encodeWithSelector(
450 SGLLiquidation.liquidate.selector,
451 users,
452 maxBorrowParts,
453 swapper,
454 collateralToAssetSwapData,
455 usdoToBorrowedSwapData
456 )
457 );
458 }
459
460 /// @notice Withdraw the fees accumulated in `accrueInfo.feesEarnedFraction` to the balance of `feeTo`.
461 function withdrawFeesEarned() public {
462 _accrue();
463 address _feeTo = penrose.feeTo();
464 uint256 _feesEarnedFraction = accrueInfo.feesEarnedFraction;
465 balanceOf[_feeTo] += _feesEarnedFraction;
466 emit Transfer(address(0), _feeTo, _feesEarnedFraction);
467 accrueInfo.feesEarnedFraction = 0;
468 emit LogWithdrawFees(_feeTo, _feesEarnedFraction);
469 }
470
471 // *********************** //
472 // *** OWNER FUNCTIONS *** //
473 // *********************** //
474 /// @notice Transfers fees to penrose
475 /// @dev can only be called by the owner
476 /// @param feeTo fees receiver
477 function refreshPenroseFees(
478 address feeTo
479 ) external onlyOwner notPaused returns (uint256 feeShares) {
480 if (accrueInfo.feesEarnedFraction > 0) {
481 withdrawFeesEarned();
482 }
483
484 feeShares = _removeAsset(feeTo, msg.sender, balanceOf[feeTo], false);
485 }
486
487 /// @notice sets Singularity specific configuration
488 /// @dev values are updated only if > 0 or not address(0)
489 function setSingularityConfig(
490 uint256 _lqCollateralizationRate,
491 uint256 _liquidationMultiplier,
492 uint256 _minimumTargetUtilization,
493 uint256 _maximumTargetUtilization,
494 uint64 _minimumInterestPerSecond,
495 uint64 _maximumInterestPerSecond,
496 uint256 _interestElasticity
497 ) external onlyOwner {
498 if (_minimumTargetUtilization > 0) {
499 emit MinimumTargetUtilizationUpdated(
500 minimumTargetUtilization,
501 _minimumTargetUtilization
502 );
503 minimumTargetUtilization = _minimumTargetUtilization;
504 }
505
506 if (_maximumTargetUtilization > 0) {
507 require(
508 _maximumTargetUtilization < FULL_UTILIZATION,
509 "SGL: not valid"
510 );
511 emit MaximumTargetUtilizationUpdated(
512 maximumTargetUtilization,
513 _maximumTargetUtilization
514 );
515 maximumTargetUtilization = _maximumTargetUtilization;
516 fullUtilizationMinusMax =
517 FULL_UTILIZATION -
518 maximumTargetUtilization;
519 }
520
521 if (_minimumInterestPerSecond > 0) {
522 require(
523 _minimumInterestPerSecond < maximumInterestPerSecond,
524 "SGL: not valid"
525 );
526 emit MinimumInterestPerSecondUpdated(
527 minimumInterestPerSecond,
528 _minimumInterestPerSecond
529 );
530 minimumInterestPerSecond = _minimumInterestPerSecond;
531 }
532
533 if (_maximumInterestPerSecond > 0) {
534 require(
535 _maximumInterestPerSecond > minimumInterestPerSecond,
536 "SGL: not valid"
537 );
538 emit MaximumInterestPerSecondUpdated(
539 maximumInterestPerSecond,
540 _maximumInterestPerSecond
541 );
542 maximumInterestPerSecond = _maximumInterestPerSecond;
543 }
544
545 if (_interestElasticity > 0) {
546 emit InterestElasticityUpdated(
547 interestElasticity,
548 _interestElasticity
549 );
550 interestElasticity = _interestElasticity;
551 }
552
553 if (_lqCollateralizationRate > 0) {
554 require(
555 _lqCollateralizationRate <= FEE_PRECISION,
556 "SGL: not valid"
557 );
558 emit LqCollateralizationRateUpdated(
559 lqCollateralizationRate,
560 _lqCollateralizationRate
561 );
562 lqCollateralizationRate = _lqCollateralizationRate;
563 }
564
565 if (_liquidationMultiplier > 0) {
566 require(_liquidationMultiplier < FEE_PRECISION, "SGL: not valid");
567 emit LiquidationMultiplierUpdated(
568 liquidationMultiplier,
569 _liquidationMultiplier
570 );
571 liquidationMultiplier = _liquidationMultiplier;
572 }
573 }
574
575 /// @notice sets LQ specific confinguration
576 function setLiquidationQueueConfig(
577 ILiquidationQueue _liquidationQueue,
578 address _bidExecutionSwapper,
579 address _usdoSwapper
580 ) external onlyOwner {
581 if (address(_liquidationQueue) != address(0)) {
582 require(_liquidationQueue.onlyOnce(), "SGL: LQ not initalized");
583 liquidationQueue = _liquidationQueue;
584 }
585
586 if (_bidExecutionSwapper != address(0)) {
587 emit BidExecutionSwapperUpdated(_bidExecutionSwapper);
588 liquidationQueue.setBidExecutionSwapper(_bidExecutionSwapper);
589 }
590
591 if (_usdoSwapper != address(0)) {
592 emit UsdoSwapperUpdated(_usdoSwapper);
593 liquidationQueue.setUsdoSwapper(_usdoSwapper);
594 }
595 }
596
597 // ************************* //
598 // *** PRIVATE FUNCTIONS *** //
599 // ************************* //
600 function _extractModule(Module _module) private view returns (address) {
601 address module;
602 if (_module == Module.Borrow) {
603 module = address(borrowModule);
604 } else if (_module == Module.Collateral) {
605 module = address(collateralModule);
606 } else if (_module == Module.Liquidation) {
607 module = address(liquidationModule);
608 } else if (_module == Module.Leverage) {
609 module = address(leverageModule);
610 }
611 if (module == address(0)) {
612 revert("SGL: module not set");
613 }
614
615 return module;
616 }
617
618 function _executeModule(
619 Module _module,
620 bytes memory _data
621 ) private returns (bytes memory returnData) {
622 bool success = true;
623 address module = _extractModule(_module);
624
625 (success, returnData) = module.delegatecall(_data);
626 if (!success) {
627 revert(_getRevertMsg(returnData));
628 }
629 }
630
631 function _executeViewModule(
632 Module _module,
633 bytes memory _data
634 ) private view returns (bytes memory returnData) {
635 bool success = true;
636 address module = _extractModule(_module);
637
638 (success, returnData) = module.staticcall(_data);
639 if (!success) {
640 revert(_getRevertMsg(returnData));
641 }
642 }
643
644 receive() external payable {}
645: }
File: contracts/usd0/BaseUSDO.sol
46 contract BaseUSDO is BaseUSDOStorage, ERC20Permit {
47 using SafeERC20 for IERC20;
48 using BytesLib for bytes;
49 // ************ //
50 // *** VARS *** //
51 // ************ //
52 enum Module {
53 Leverage,
54 Market,
55 Options
56 }
57
58 /// @notice returns the leverage module
59 USDOLeverageModule public leverageModule;
60
61 /// @notice returns the market module
62 USDOMarketModule public marketModule;
63
64 /// @notice returns the options module
65 USDOOptionsModule public optionsModule;
66
67 constructor(
68 address _lzEndpoint,
69 IYieldBoxBase _yieldBox,
70 address _owner,
71 address payable _leverageModule,
72 address payable _marketModule,
73 address payable _optionsModule
74 ) BaseUSDOStorage(_lzEndpoint, _yieldBox) ERC20Permit("USDO") {
75 leverageModule = USDOLeverageModule(_leverageModule);
76 marketModule = USDOMarketModule(_marketModule);
77 optionsModule = USDOOptionsModule(_optionsModule);
78
79 transferOwnership(_owner);
80 }
81
82 // *********************** //
83 // *** OWNER FUNCTIONS *** //
84 // *********************** //
85 /// @notice set the max allowed USDO mintable through flashloan
86 /// @dev can only be called by the owner
87 /// @param _val the new amount
88 function setMaxFlashMintable(uint256 _val) external onlyOwner {
89 emit MaxFlashMintUpdated(maxFlashMint, _val);
90 maxFlashMint = _val;
91 }
92
93 /// @notice set the flashloan fee
94 /// @dev can only be called by the owner
95 /// @param _val the new fee
96 function setFlashMintFee(uint256 _val) external onlyOwner {
97 require(_val < FLASH_MINT_FEE_PRECISION, "USDO: fee too big");
98 emit FlashMintFeeUpdated(flashMintFee, _val);
99 flashMintFee = _val;
100 }
101
102 /// @notice set the Conservator address
103 /// @dev conservator can pause the contract
104 /// @param _conservator the new address
105 function setConservator(address _conservator) external onlyOwner {
106 require(_conservator != address(0), "USDO: address not valid");
107 emit ConservatorUpdated(conservator, _conservator);
108 conservator = _conservator;
109 }
110
111 /// @notice updates the pause state of the contract
112 /// @dev can only be called by the conservator
113 /// @param val the new value
114 function updatePause(bool val) external {
115 require(msg.sender == conservator, "USDO: unauthorized");
116 require(val != paused, "USDO: same state");
117 emit PausedUpdated(paused, val);
118 paused = val;
119 }
120
121 /// @notice sets/unsets address as minter
122 /// @dev can only be called by the owner
123 /// @param _for role receiver
124 /// @param _status true/false
125 function setMinterStatus(address _for, bool _status) external onlyOwner {
126 allowedMinter[_getChainId()][_for] = _status;
127 emit SetMinterStatus(_for, _status);
128 }
129
130 /// @notice sets/unsets address as burner
131 /// @dev can only be called by the owner
132 /// @param _for role receiver
133 /// @param _status true/false
134 function setBurnerStatus(address _for, bool _status) external onlyOwner {
135 allowedBurner[_getChainId()][_for] = _status;
136 emit SetBurnerStatus(_for, _status);
137 }
138
139 // ************************ //
140 // *** VIEW FUNCTIONS *** //
141 // ************************ //
142 /// @notice returns token's decimals
143 function decimals() public pure override returns (uint8) {
144 return 18;
145 }
146
147 // ************************ //
148 // *** PUBLIC FUNCTIONS *** //
149 // ************************ //
150
151 /// @notice triggers a sendFrom to another layer from destination
152 /// @param lzDstChainId LZ destination id
153 /// @param airdropAdapterParams airdrop params
154 /// @param zroPaymentAddress ZRO payment address
155 /// @param amount amount to send back
156 /// @param sendFromData data needed to trigger sendFrom on destination
157 /// @param approvals approvals array
158 function triggerSendFrom(
159 uint16 lzDstChainId,
160 bytes calldata airdropAdapterParams,
161 address zroPaymentAddress,
162 uint256 amount,
163 ISendFrom.LzCallParams calldata sendFromData,
164 ICommonData.IApproval[] calldata approvals
165 ) external payable {
166 _executeModule(
167 Module.Options,
168 abi.encodeWithSelector(
169 USDOOptionsModule.triggerSendFrom.selector,
170 lzDstChainId,
171 airdropAdapterParams,
172 zroPaymentAddress,
173 amount,
174 sendFromData,
175 approvals
176 ),
177 false
178 );
179 }
180
181 /// @notice Exercise an oTAP position
182 /// @param optionsData oTap exerciseOptions data
183 /// @param lzData data needed for the cross chain transer
184 /// @param tapSendData needed for withdrawing Tap token
185 /// @param approvals array
186 function exerciseOption(
187 ITapiocaOptionsBrokerCrossChain.IExerciseOptionsData
188 calldata optionsData,
189 ITapiocaOptionsBrokerCrossChain.IExerciseLZData calldata lzData,
190 ITapiocaOptionsBrokerCrossChain.IExerciseLZSendTapData
191 calldata tapSendData,
192 ICommonData.IApproval[] calldata approvals
193 ) external payable {
194 _executeModule(
195 Module.Options,
196 abi.encodeWithSelector(
197 USDOOptionsModule.exerciseOption.selector,
198 optionsData,
199 lzData,
200 tapSendData,
201 approvals
202 ),
203 false
204 );
205 }
206
207 /// @notice inits multiHopBuyCollateral
208 /// @param from The user who sells
209 /// @param collateralAmount Extra collateral to be added
210 /// @param borrowAmount Borrowed amount that will be swapped into collateral
211 /// @param swapData Swap data used on destination chain for swapping USDO to the underlying TOFT token
212 /// @param lzData LayerZero specific data
213 /// @param externalData External contracts used for the cross chain operation
214 /// @param approvals array
215 function initMultiHopBuy(
216 address from,
217 uint256 collateralAmount,
218 uint256 borrowAmount,
219 IUSDOBase.ILeverageSwapData calldata swapData,
220 IUSDOBase.ILeverageLZData calldata lzData,
221 IUSDOBase.ILeverageExternalContractsData calldata externalData,
222 bytes calldata airdropAdapterParams,
223 ICommonData.IApproval[] memory approvals
224 ) external payable {
225 _executeModule(
226 Module.Leverage,
227 abi.encodeWithSelector(
228 USDOLeverageModule.initMultiHopBuy.selector,
229 from,
230 collateralAmount,
231 borrowAmount,
232 swapData,
233 lzData,
234 externalData,
235 airdropAdapterParams,
236 approvals
237 ),
238 false
239 );
240 }
241
242 /// @notice calls removeAssetAndRepay on Magnetar from the destination layer
243 /// @param from sending address
244 /// @param to receiver address
245 /// @param lzDstChainId LayerZero destination chain id
246 /// @param zroPaymentAddress ZRO payment address
247 /// @param adapterParams LZ adapter params
248 /// @param externalData external addresses needed for the operation
249 /// @param removeAndRepayData removeAssetAndRepay params
250 /// @param approvals approvals params
251 function removeAsset(
252 address from,
253 address to,
254 uint16 lzDstChainId,
255 address zroPaymentAddress,
256 bytes calldata adapterParams,
257 ICommonData.ICommonExternalContracts calldata externalData,
258 IUSDOBase.IRemoveAndRepay calldata removeAndRepayData,
259 ICommonData.IApproval[] calldata approvals
260 ) external payable {
261 _executeModule(
262 Module.Market,
263 abi.encodeWithSelector(
264 USDOMarketModule.removeAsset.selector,
265 from,
266 to,
267 lzDstChainId,
268 zroPaymentAddress,
269 adapterParams,
270 externalData,
271 removeAndRepayData,
272 approvals
273 ),
274 false
275 );
276 }
277
278 /// @notice sends USDO to a specific chain and performs a leverage up operation
279 /// @param amount the amount to use
280 /// @param leverageFor the receiver address
281 /// @param lzData LZ specific data
282 /// @param swapData ISwapper specific data
283 /// @param externalData external contracts used for the flow
284 function sendForLeverage(
285 uint256 amount,
286 address leverageFor,
287 IUSDOBase.ILeverageLZData calldata lzData,
288 IUSDOBase.ILeverageSwapData calldata swapData,
289 IUSDOBase.ILeverageExternalContractsData calldata externalData
290 ) external payable {
291 _executeModule(
292 Module.Leverage,
293 abi.encodeWithSelector(
294 USDOLeverageModule.sendForLeverage.selector,
295 amount,
296 leverageFor,
297 lzData,
298 swapData,
299 externalData
300 ),
301 false
302 );
303 }
304
305 /// @notice sends to YieldBox over layer and lends asset to market
306 /// @param _from sending address
307 /// @param _to receiver address
308 /// @param lzDstChainId LayerZero destination chain id
309 /// @param lendParams lend specific params
310 /// @param approvals approvals specific params
311 /// @param withdrawParams parameter to withdraw the SGL collateral
312 /// @param adapterParams adapter params of the withdrawn collateral
313 function sendAndLendOrRepay(
314 address _from,
315 address _to,
316 uint16 lzDstChainId,
317 address zroPaymentAddress,
318 IUSDOBase.ILendOrRepayParams calldata lendParams,
319 ICommonData.IApproval[] calldata approvals,
320 ICommonData.IWithdrawParams calldata withdrawParams,
321 bytes calldata adapterParams
322 ) external payable {
323 _executeModule(
324 Module.Market,
325 abi.encodeWithSelector(
326 USDOMarketModule.sendAndLendOrRepay.selector,
327 _from,
328 _to,
329 lzDstChainId,
330 zroPaymentAddress,
331 lendParams,
332 approvals,
333 withdrawParams,
334 adapterParams
335 ),
336 false
337 );
338 }
339
340 // ************************* //
341 // *** PRIVATE FUNCTIONS *** //
342 // ************************* //
343
344 function _extractModule(Module _module) private view returns (address) {
345 address module;
346 if (_module == Module.Leverage) {
347 module = address(leverageModule);
348 } else if (_module == Module.Market) {
349 module = address(marketModule);
350 } else if (_module == Module.Options) {
351 module = address(optionsModule);
352 }
353
354 if (module == address(0)) {
355 revert("USDO: module not found");
356 }
357
358 return module;
359 }
360
361 function _executeModule(
362 Module _module,
363 bytes memory _data,
364 bool _forwardRevert
365 ) private returns (bool success, bytes memory returnData) {
366 success = true;
367 address module = _extractModule(_module);
368
369 (success, returnData) = module.delegatecall(_data);
370 if (!success && !_forwardRevert) {
371 revert(_getRevertMsg(returnData));
372 }
373 }
374
375 function _executeOnDestination(
376 Module _module,
377 bytes memory _data,
378 uint16 _srcChainId,
379 bytes memory _srcAddress,
380 uint64 _nonce,
381 bytes memory _payload
382 ) private {
383 (bool success, bytes memory returnData) = _executeModule(
384 _module,
385 _data,
386 true
387 );
388 if (!success) {
389 _storeFailedMessage(
390 _srcChainId,
391 _srcAddress,
392 _nonce,
393 _payload,
394 returnData
395 );
396 }
397 }
398
399 function _nonblockingLzReceive(
400 uint16 _srcChainId,
401 bytes memory _srcAddress,
402 uint64 _nonce,
403 bytes memory _payload
404 ) internal virtual override {
405 uint256 packetType = _payload.toUint256(0);
406
407 if (packetType == PT_YB_SEND_SGL_LEND_OR_REPAY) {
408 _executeOnDestination(
409 Module.Market,
410 abi.encodeWithSelector(
411 USDOMarketModule.lend.selector,
412 marketModule,
413 _srcChainId,
414 _srcAddress,
415 _nonce,
416 _payload
417 ),
418 _srcChainId,
419 _srcAddress,
420 _nonce,
421 _payload
422 );
423 } else if (packetType == PT_LEVERAGE_MARKET_UP) {
424 _executeOnDestination(
425 Module.Leverage,
426 abi.encodeWithSelector(
427 USDOLeverageModule.leverageUp.selector,
428 leverageModule,
429 _srcChainId,
430 _srcAddress,
431 _nonce,
432 _payload
433 ),
434 _srcChainId,
435 _srcAddress,
436 _nonce,
437 _payload
438 );
439 } else if (packetType == PT_MARKET_REMOVE_ASSET) {
440 _executeOnDestination(
441 Module.Market,
442 abi.encodeWithSelector(
443 USDOMarketModule.remove.selector,
444 _payload
445 ),
446 _srcChainId,
447 _srcAddress,
448 _nonce,
449 _payload
450 );
451 } else if (packetType == PT_MARKET_MULTIHOP_BUY) {
452 _executeOnDestination(
453 Module.Leverage,
454 abi.encodeWithSelector(
455 USDOLeverageModule.multiHop.selector,
456 _payload
457 ),
458 _srcChainId,
459 _srcAddress,
460 _nonce,
461 _payload
462 );
463 } else if (packetType == PT_TAP_EXERCISE) {
464 _executeOnDestination(
465 Module.Options,
466 abi.encodeWithSelector(
467 USDOOptionsModule.exercise.selector,
468 optionsModule,
469 _srcChainId,
470 _srcAddress,
471 _nonce,
472 _payload
473 ),
474 _srcChainId,
475 _srcAddress,
476 _nonce,
477 _payload
478 );
479 } else if (packetType == PT_SEND_FROM) {
480 _executeOnDestination(
481 Module.Options,
482 abi.encodeWithSelector(
483 USDOOptionsModule.sendFromDestination.selector,
484 _payload
485 ),
486 _srcChainId,
487 _srcAddress,
488 _nonce,
489 _payload
490 );
491 } else {
492 packetType = _payload.toUint8(0);
493 if (packetType == PT_SEND) {
494 _sendAck(_srcChainId, _srcAddress, _nonce, _payload);
495 } else if (packetType == PT_SEND_AND_CALL) {
496 _sendAndCallAck(_srcChainId, _srcAddress, _nonce, _payload);
497 } else {
498 revert("OFTCoreV2: unknown packet type");
499 }
500 }
501 }
502: }
File: contracts/Balancer.sol
34 contract Balancer is Owned {
35 // ************ //
36 // *** VARS *** //
37 // ************ //
38 /// @notice current OFT => chain => destination OFT
39 /// @dev chain ids (https://stargateprotocol.gitbook.io/stargate/developers/chain-ids):
40 /// - Ethereum: 101
41 /// - BNB: 102
42 /// - Avalanche: 106
43 /// - Polygon: 109
44 /// - Arbitrum: 110
45 /// - Optimism: 111
46 /// - Fantom: 112
47 /// - Metis: 151
48 /// pool ids https://stargateprotocol.gitbook.io/stargate/developers/pool-ids
49 mapping(address => mapping(uint16 => OFTData)) public connectedOFTs;
50
51 struct OFTData {
52 uint256 srcPoolId;
53 uint256 dstPoolId;
54 address dstOft;
55 uint256 rebalanceable;
56 }
57
58 /// @notice StargetETH router address
59 IStargateRouter public immutable routerETH;
60 /// @notice Stargate router address
61 IStargateRouter public immutable router;
62
63 uint256 private constant SLIPPAGE_PRECISION = 1e5;
64
65 // ************************ //
66 // *** EVENTS FUNCTIONS *** //
67 // ************************ //
68 /// @notice event emitted when mTapiocaOFT is initialized
69 event ConnectedChainUpdated(
70 address indexed _srcOft,
71 uint16 _dstChainId,
72 address indexed _dstOft
73 );
74 /// @notice event emitted when a rebalance operation is performed
75 /// @dev rebalancing means sending an amount of the underlying token to one of the connected chains
76 event Rebalanced(
77 address indexed _srcOft,
78 uint16 _dstChainId,
79 uint256 _slippage,
80 uint256 _amount,
81 bool _isNative
82 );
83 /// @notice event emitted when max rebalanceable amount is updated
84 event RebalanceAmountUpdated(
85 address _srcOft,
86 uint16 _dstChainId,
87 uint256 _amount,
88 uint256 _totalAmount
89 );
90
91 // ************************ //
92 // *** ERRORS FUNCTIONS *** //
93 // ************************ //
94 /// @notice error thrown when IStargetRouter address is not valid
95 error RouterNotValid();
96 /// @notice error thrown when value exceeds balance
97 error ExceedsBalance();
98 /// @notice error thrown when chain destination is not valid
99 error DestinationNotValid();
100 /// @notice error thrown when dex slippage is not valid
101 error SlippageNotValid();
102 /// @notice error thrown when fee amount is not set
103 error FeeAmountNotSet();
104 error PoolInfoRequired();
105 error RebalanceAmountNotSet();
106 error DestinationOftNotValid();
107
108 // *************************** //
109 // *** MODIFIERS FUNCTIONS *** //
110 // *************************** //
111 modifier onlyValidDestination(address _srcOft, uint16 _dstChainId) {
112 if (connectedOFTs[_srcOft][_dstChainId].dstOft == address(0))
113 revert DestinationNotValid();
114 _;
115 }
116
117 modifier onlyValidSlippage(uint256 _slippage) {
118 if (_slippage >= 1e5) revert SlippageNotValid();
119 _;
120 }
121
122 constructor(
123 address _routerETH,
124 address _router,
125 address _owner
126 ) Owned(_owner) {
127 if (_router == address(0)) revert RouterNotValid();
128 if (_routerETH == address(0)) revert RouterNotValid();
129 routerETH = IStargateRouter(_routerETH);
130 router = IStargateRouter(_router);
131 }
132
133 // ************************ //
134 // *** PUBLIC FUNCTIONS *** //
135 // ************************ //
136
137 function checker(
138 address payable _srcOft,
139 uint16 _dstChainId
140 ) external view returns (bool canExec, bytes memory execPayload) {
141 bytes memory ercData;
142 if (ITapiocaOFT(_srcOft).erc20() == address(0)) {
143 ercData = abi.encode(
144 connectedOFTs[_srcOft][_dstChainId].srcPoolId,
145 connectedOFTs[_srcOft][_dstChainId].dstPoolId
146 );
147 }
148
149 canExec = connectedOFTs[_srcOft][_dstChainId].rebalanceable > 0;
150 execPayload = abi.encodeCall(
151 Balancer.rebalance,
152 (
153 _srcOft,
154 _dstChainId,
155 1e3, //1% slippage
156 connectedOFTs[_srcOft][_dstChainId].rebalanceable,
157 ercData
158 )
159 );
160 }
161
162 // *********************** //
163 // *** OWNER FUNCTIONS *** //
164 // *********************** //
165 /// @notice performs a rebalance operation
166 /// @dev callable only by the owner
167 /// @param _srcOft the source TOFT address
168 /// @param _dstChainId the destination LayerZero id
169 /// @param _slippage the destination LayerZero id
170 /// @param _amount the rebalanced amount
171 /// @param _ercData custom send data
172 function rebalance(
173 address payable _srcOft,
174 uint16 _dstChainId,
175 uint256 _slippage,
176 uint256 _amount,
177 bytes memory _ercData
178 )
179 external
180 payable
181 onlyOwner
182 onlyValidDestination(_srcOft, _dstChainId)
183 onlyValidSlippage(_slippage)
184 {
185 if (connectedOFTs[_srcOft][_dstChainId].rebalanceable < _amount)
186 revert RebalanceAmountNotSet();
187
188 //check if OFT is still valid
189 if (
190 !_isValidOft(
191 _srcOft,
192 connectedOFTs[_srcOft][_dstChainId].dstOft,
193 _dstChainId
194 )
195 ) revert DestinationOftNotValid();
196
197 //extract
198 ITapiocaOFT(_srcOft).extractUnderlying(_amount);
199
200 //send
201 bool _isNative = ITapiocaOFT(_srcOft).erc20() == address(0);
202 if (_isNative) {
203 if (msg.value <= _amount) revert FeeAmountNotSet();
204 _sendNative(_srcOft, _amount, _dstChainId, _slippage);
205 } else {
206 if (msg.value == 0) revert FeeAmountNotSet();
207 _sendToken(_srcOft, _amount, _dstChainId, _slippage, _ercData);
208 }
209
210 connectedOFTs[_srcOft][_dstChainId].rebalanceable -= _amount;
211 emit Rebalanced(_srcOft, _dstChainId, _slippage, _amount, _isNative);
212 }
213
214 /// @notice registeres mTapiocaOFT for rebalancing
215 /// @param _srcOft the source TOFT address
216 /// @param _dstChainId the destination LayerZero id
217 /// @param _dstOft the destination TOFT address
218 /// @param _ercData custom send data
219 function initConnectedOFT(
220 address _srcOft,
221 uint16 _dstChainId,
222 address _dstOft,
223 bytes memory _ercData
224 ) external onlyOwner {
225 bool isNative = ITapiocaOFT(_srcOft).erc20() == address(0);
226 if (!isNative && _ercData.length == 0) revert PoolInfoRequired();
227 if (!_isValidOft(_srcOft, _dstOft, _dstChainId))
228 revert DestinationOftNotValid();
229
230 (uint256 _srcPoolId, uint256 _dstPoolId) = abi.decode(
231 _ercData,
232 (uint256, uint256)
233 );
234
235 OFTData memory oftData = OFTData({
236 srcPoolId: _srcPoolId,
237 dstPoolId: _dstPoolId,
238 dstOft: _dstOft,
239 rebalanceable: 0
240 });
241
242 connectedOFTs[_srcOft][_dstChainId] = oftData;
243 emit ConnectedChainUpdated(_srcOft, _dstChainId, _dstOft);
244 }
245
246 /// @notice assings more rebalanceable amount for TOFT
247 /// @param _srcOft the source TOFT address
248 /// @param _dstChainId the destination LayerZero id
249 /// @param _amount the rebalanced amount
250 function addRebalanceAmount(
251 address _srcOft,
252 uint16 _dstChainId,
253 uint256 _amount
254 ) external onlyValidDestination(_srcOft, _dstChainId) onlyOwner {
255 connectedOFTs[_srcOft][_dstChainId].rebalanceable += _amount;
256 emit RebalanceAmountUpdated(
257 _srcOft,
258 _dstChainId,
259 _amount,
260 connectedOFTs[_srcOft][_dstChainId].rebalanceable
261 );
262 }
263
264 // ************************* //
265 // *** PRIVATE FUNCTIONS *** //
266 // ************************* //
267 function _isValidOft(
268 address _srcOft,
269 address _dstOft,
270 uint16 _dstChainId
271 ) private view returns (bool) {
272 bytes memory trustedRemotePath = abi.encodePacked(_dstOft, _srcOft);
273 return
274 ITapiocaOFT(_srcOft).isTrustedRemote(
275 _dstChainId,
276 trustedRemotePath
277 );
278 }
279
280 function _sendNative(
281 address payable _oft,
282 uint256 _amount,
283 uint16 _dstChainId,
284 uint256 _slippage
285 ) private {
286 if (address(this).balance < _amount) revert ExceedsBalance();
287
288 routerETH.swapETH(
289 _dstChainId,
290 _oft, //refund
291 abi.encodePacked(connectedOFTs[_oft][_dstChainId].dstOft),
292 _amount,
293 _computeMinAmount(_amount, _slippage)
294 );
295 }
296
297 function _sendToken(
298 address payable _oft,
299 uint256 _amount,
300 uint16 _dstChainId,
301 uint256 _slippage,
302 bytes memory _data
303 ) private {
304 IERC20Metadata erc20 = IERC20Metadata(ITapiocaOFT(_oft).erc20());
305 if (erc20.balanceOf(address(this)) < _amount) revert ExceedsBalance();
306
307 (uint256 _srcPoolId, uint256 _dstPoolId) = abi.decode(
308 _data,
309 (uint256, uint256)
310 );
311
312 IStargateRouter.lzTxObj memory _lzTxParams = IStargateRouterBase
313 .lzTxObj({
314 dstGasForCall: 0,
315 dstNativeAmount: msg.value,
316 dstNativeAddr: abi.encode(
317 connectedOFTs[_oft][_dstChainId].dstOft
318 )
319 });
320
321 erc20.approve(address(router), _amount);
322 router.swap(
323 _dstChainId,
324 _srcPoolId,
325 _dstPoolId,
326 _oft, //refund,
327 _amount,
328 _computeMinAmount(_amount, _slippage),
329 _lzTxParams,
330 _lzTxParams.dstNativeAddr,
331 "0x"
332 );
333 }
334
335 function _computeMinAmount(
336 uint256 _amount,
337 uint256 _slippage
338 ) private pure returns (uint256) {
339 return _amount - ((_amount * _slippage) / SLIPPAGE_PRECISION);
340 }
341
342 receive() external payable {}
343: }
File: contracts/TapiocaWrapper.sol
26 contract TapiocaWrapper is Ownable {
27 struct ExecutionCall {
28 address toft;
29 bytes bytecode;
30 bool revertOnFailure;
31 }
32
33 // ************ //
34 // *** VARS *** //
35 // ************ //
36 /// @notice Array of deployed TOFT contracts.
37 ITapiocaOFT[] public tapiocaOFTs;
38 /// @notice Array of harvestable TOFT fees.
39 ITapiocaOFT[] private harvestableTapiocaOFTs;
40 /// @notice Map of deployed TOFT contracts by ERC20.
41 mapping(address => ITapiocaOFT) public tapiocaOFTsByErc20;
42
43 // ************** //
44 // *** EVENTS *** //
45 // ************** //
46 /// @notice Called when a new OFT is deployed.
47 event CreateOFT(ITapiocaOFT indexed _tapiocaOFT, address indexed _erc20);
48 /// @notice Called when fees are harvested.
49 event HarvestFees(address indexed _caller);
50 /// @notice Called when fees are changed.
51 event SetFees(uint256 _newFee);
52
53 // ************** //
54 // *** ERRORS *** //
55 // ************** //
56 /// @notice If the TOFT is already deployed.
57 error TapiocaWrapper__AlreadyDeployed(address _erc20);
58 /// @notice Failed to deploy the TapiocaWrapper contract.
59 error TapiocaWrapper__FailedDeploy();
60 /// @notice The management fee is too high. Currently set to a max of 50 BPS or 0.5%.
61 error TapiocaWrapper__MngmtFeeTooHigh();
62 /// @notice The TapiocaOFT execution failed.
63 error TapiocaWrapper__TOFTExecutionFailed(bytes message);
64 /// @notice No TOFT has been deployed yet.
65 error TapiocaWrapper__NoTOFTDeployed();
66
67 constructor(address _owner) {
68 _transferOwnership(_owner);
69 }
70
71 // ********************** //
72 // *** VIEW FUNCTIONS *** //
73 // ********************** //
74 /// @notice Return the number of TOFT contracts deployed on the current chain.
75 function tapiocaOFTLength() external view returns (uint256) {
76 return tapiocaOFTs.length;
77 }
78
79 /// @notice Return the number of harvestable TOFT contracts deployed on the current chain.
80 function harvestableTapiocaOFTsLength() external view returns (uint256) {
81 return harvestableTapiocaOFTs.length;
82 }
83
84 /// @notice Return the latest TOFT contract deployed on the current chain.
85 function lastTOFT() external view returns (ITapiocaOFT) {
86 if (tapiocaOFTs.length == 0) {
87 revert TapiocaWrapper__NoTOFTDeployed();
88 }
89 return tapiocaOFTs[tapiocaOFTs.length - 1];
90 }
91
92 // ************************ //
93 // *** PUBLIC FUNCTIONS *** //
94 // ************************ //
95
96 /// @notice Harvest fees from all the deployed TOFT contracts. Fees are transferred to the owner.
97 function harvestFees() external {
98 for (uint256 i = 0; i < harvestableTapiocaOFTs.length; i++) {
99 harvestableTapiocaOFTs[i].harvestFees();
100 }
101 emit HarvestFees(msg.sender);
102 }
103
104 // *********************** //
105 // *** OWNER FUNCTIONS *** //
106 // *********************** //
107
108 /// @notice Execute the `_bytecode` against the `_toft`. Callable only by the owner.
109 /// @dev Used to call derived OFT functions to a TOFT contract.
110 /// @param _toft The TOFT contract to execute against.
111 /// @param _bytecode The executable bytecode of the TOFT contract.
112 /// @param _revertOnFailure Whether to revert on failure.
113 /// @return success If the execution was successful.
114 /// @return result The error message if the execution failed.
115 function executeTOFT(
116 address _toft,
117 bytes calldata _bytecode,
118 bool _revertOnFailure
119 ) external payable onlyOwner returns (bool success, bytes memory result) {
120 (success, result) = payable(_toft).call{value: msg.value}(_bytecode);
121 if (_revertOnFailure && !success) {
122 revert TapiocaWrapper__TOFTExecutionFailed(result);
123 }
124 }
125
126 /// @notice Execute the `_bytecode` against the `_toft`. Callable only by the owner.
127 /// @dev Used to call derived OFT functions to a TOFT contract.
128 /// @param _call The array calls to do.
129 /// @return success If the execution was successful.
130 /// @return results The message of the execution, could be an error message.
131 function executeCalls(
132 ExecutionCall[] calldata _call
133 )
134 external
135 payable
136 onlyOwner
137 returns (bool success, bytes[] memory results)
138 {
139 results = new bytes[](_call.length);
140 for (uint256 i = 0; i < _call.length; i++) {
141 (success, results[i]) = payable(_call[i].toft).call{
142 value: msg.value
143 }(_call[i].bytecode);
144 if (_call[i].revertOnFailure && !success) {
145 revert TapiocaWrapper__TOFTExecutionFailed(results[i]);
146 }
147 }
148 }
149
150 /// @notice Deploy a new TOFT contract. Callable only by the owner.
151 /// @param _erc20 The ERC20 to wrap.
152 /// @param _bytecode The executable bytecode of the TOFT contract.
153 /// @param _salt Create2 salt.
154 function createTOFT(
155 address _erc20,
156 bytes calldata _bytecode,
157 bytes32 _salt,
158 bool _linked
159 ) external onlyOwner {
160 if (address(tapiocaOFTsByErc20[_erc20]) != address(0x0)) {
161 revert TapiocaWrapper__AlreadyDeployed(_erc20);
162 }
163
164 ITapiocaOFT iOFT = ITapiocaOFT(
165 _createTOFT(_erc20, _bytecode, _salt, _linked)
166 );
167 if (address(iOFT.erc20()) != _erc20) {
168 revert TapiocaWrapper__FailedDeploy();
169 }
170
171 tapiocaOFTs.push(iOFT);
172 tapiocaOFTsByErc20[_erc20] = iOFT;
173
174 if (iOFT.hostChainID() == block.chainid) {
175 harvestableTapiocaOFTs.push(iOFT);
176 }
177 emit CreateOFT(iOFT, _erc20);
178 }
179
180 // ************************* //
181 // *** PRIVATE FUNCTIONS *** //
182 // ************************* //
183 function _createTOFT(
184 address _erc20,
185 bytes calldata _bytecode,
186 bytes32 _salt,
187 bool _linked
188 ) private returns (address) {
189 address oft;
190 if (!_linked) {
191 TapiocaOFT toft = TapiocaOFT(
192 payable(
193 Create2.deploy(
194 0,
195 keccak256(
196 abi.encodePacked(
197 keccak256(_bytecode),
198 address(this),
199 _erc20,
200 _salt
201 )
202 ),
203 _bytecode
204 )
205 )
206 );
207 oft = address(toft);
208 } else {
209 mTapiocaOFT toft = mTapiocaOFT(
210 payable(
211 Create2.deploy(
212 0,
213 keccak256(
214 abi.encodePacked(
215 keccak256(_bytecode),
216 address(this),
217 _erc20,
218 _salt
219 )
220 ),
221 _bytecode
222 )
223 )
224 );
225 oft = address(toft);
226 }
227 return oft;
228 }
229: }
File: contracts/tOFT/mTapiocaOFT.sol
9 contract mTapiocaOFT is BaseTOFT {
10 using SafeERC20 for IERC20;
11
12 // ************ //
13 // *** VARS *** //
14 // ************ //
15
16 /// @notice allowed chains where you can unwrap your TOFT
17 mapping(uint256 => bool) public connectedChains;
18
19 /// @notice map of approved balancers
20 /// @dev a balancer can extract the underlying
21 mapping(address => bool) public balancers;
22
23 // ************** //
24 // *** EVENTS *** //
25 // ************** //
26 /// @notice event emitted when a connected chain is reigstered or unregistered
27 event ConnectedChainStatusUpdated(uint256 _chain, bool _old, bool _new);
28 /// @notice event emitted when balancer status is updated
29 event BalancerStatusUpdated(
30 address indexed _balancer,
31 bool _bool,
32 bool _new
33 );
34 /// @notice event emitted when rebalancing is performed
35 event Rebalancing(
36 address indexed _balancer,
37 uint256 _amount,
38 bool _isNative
39 );
40
41 /// @notice creates a new mTapiocaOFT
42 /// @param _lzEndpoint LayerZero endpoint address
43 /// @param _erc20 true the underlying ERC20 address
44 /// @param _yieldBox the YieldBox address
45 /// @param _name the TOFT name
46 /// @param _symbol the TOFT symbol
47 /// @param _decimal the TOFT decimal
48 /// @param _hostChainID the TOFT host chain LayerZero id
49 constructor(
50 address _lzEndpoint,
51 address _erc20,
52 IYieldBoxBase _yieldBox,
53 string memory _name,
54 string memory _symbol,
55 uint8 _decimal,
56 uint256 _hostChainID,
57 address payable _leverageModule,
58 address payable _strategyModule,
59 address payable _marketModule,
60 address payable _optionsModule
61 )
62 BaseTOFT(
63 _lzEndpoint,
64 _erc20,
65 _yieldBox,
66 _name,
67 _symbol,
68 _decimal,
69 _hostChainID,
70 _leverageModule,
71 _strategyModule,
72 _marketModule,
73 _optionsModule
74 )
75 {
76 if (block.chainid == _hostChainID) {
77 connectedChains[_hostChainID] = true;
78 }
79 }
80
81 // ************************ //
82 // *** PUBLIC FUNCTIONS *** //
83 // ************************ //
84 /// @notice Wrap an ERC20 with a 1:1 ratio with a fee if existing.
85 /// @dev Since it can be executed only on the main chain, if an address exists on the OP chain it will not allowed to wrap.
86 /// @param _toAddress The address to wrap the ERC20 to.
87 /// @param _amount The amount of ERC20 to wrap.
88 function wrap(
89 address _fromAddress,
90 address _toAddress,
91 uint256 _amount
92 ) external payable onlyHostChain {
93 require(!balancers[msg.sender], "TOFT_auth");
94 if (erc20 == address(0)) {
95 _wrapNative(_toAddress);
96 } else {
97 _wrap(_fromAddress, _toAddress, _amount);
98 }
99 }
100
101 /// @notice Unwrap an ERC20/Native with a 1:1 ratio. Called only on host chain.
102 /// @param _toAddress The address to unwrap the tokens to.
103 /// @param _amount The amount of tokens to unwrap.
104 function unwrap(address _toAddress, uint256 _amount) external {
105 require(connectedChains[block.chainid], "TOFT_host");
106 require(!balancers[msg.sender], "TOFT_auth");
107 _unwrap(_toAddress, _amount);
108 }
109
110 // *********************** //
111 // *** OWNER FUNCTIONS *** //
112 // *********************** //
113 /// @notice updates a connected chain whitelist status
114 /// @param _chain the block.chainid of that specific chain
115 /// @param _status the new whitelist status
116 function updateConnectedChain(
117 uint256 _chain,
118 bool _status
119 ) external onlyOwner {
120 emit ConnectedChainStatusUpdated(
121 _chain,
122 connectedChains[_chain],
123 _status
124 );
125 connectedChains[_chain] = _status;
126 }
127
128 /// @notice updates a Balancer whitelist status
129 /// @param _balancer the operator address
130 /// @param _status the new whitelist status
131 function updateBalancerState(
132 address _balancer,
133 bool _status
134 ) external onlyOwner {
135 emit BalancerStatusUpdated(_balancer, balancers[_balancer], _status);
136 balancers[_balancer] = _status;
137 }
138
139 /// @notice extracts the underlying token/native for rebalancing
140 /// @param _amount the amount used for rebalancing
141 function extractUnderlying(uint256 _amount) external {
142 require(balancers[msg.sender], "TOFT_auth");
143
144 bool _isNative = erc20 == address(0);
145 if (_isNative) {
146 _safeTransferETH(msg.sender, _amount);
147 } else {
148 IERC20(erc20).safeTransfer(msg.sender, _amount);
149 }
150
151 emit Rebalancing(msg.sender, _amount, _isNative);
152 }
153: }
File: contracts/Vesting.sol
10 contract Vesting is BoringOwnable, ReentrancyGuard {
11 using SafeERC20 for IERC20;
12
13 // ************ //
14 // *** VARS *** //
15 // ************ //
16 /// @notice the vested token
17 IERC20 public token;
18
19 /// @notice returns the start time for vesting
20 uint256 public start;
21
22 /// @notice returns the cliff period
23 uint256 public cliff;
24
25 /// @notice returns total vesting duration
26 uint256 public duration;
27
28 /// @notice returns total available tokens
29 uint256 public seeded = 0;
30
31 /// @notice user vesting data
32 struct UserData {
33 uint256 amount;
34 uint256 claimed;
35 uint256 latestClaimTimestamp;
36 bool revoked;
37 }
38 mapping(address => UserData) public users;
39
40 uint256 private _totalAmount;
41 uint256 private _totalClaimed;
42
43 // ************** //
44 // *** ERRORS *** //
45 // ************** //
46 error NotStarted();
47 error NothingToClaim();
48 error Initialized();
49 error AddressNotValid();
50 error AmountNotValid();
51 error AlreadyRegistered();
52 error NoTokens();
53 error NotEnough();
54 error BalanceTooLow();
55
56 // *************** //
57 // *** EVENTS *** //
58 // ************** //
59 /// @notice event emitted when a new user is registered
60 event UserRegistered(address indexed user, uint256 amount);
61 /// @notice event emitted when someone claims available tokens
62 event Claimed(address indexed user, uint256 amount);
63
64 /// @notice creates a new Vesting contract
65 /// @param _cliff cliff period
66 /// @param _duration vesting period
67 constructor(uint256 _cliff, uint256 _duration, address _owner) {
68 require(_duration > 0, "Vesting: no vesting");
69
70 cliff = _cliff;
71 duration = _duration;
72 owner = _owner;
73 }
74
75 // ********************** //
76 // *** VIEW FUNCTIONS *** //
77 // ********************** //
78 /// @notice returns total claimable
79 function claimable() external view returns (uint256) {
80 return _vested(seeded) - _totalClaimed;
81 }
82
83 /// @notice returns total claimable for user
84 /// @param _user the user address
85 function claimable(address _user) public view returns (uint256) {
86 return _vested(users[_user].amount) - users[_user].claimed;
87 }
88
89 /// @notice returns total vested amount
90 function vested() external view returns (uint256) {
91 return _vested(seeded);
92 }
93
94 /// @notice returns total vested amount for user
95 /// @param _user the user address
96 function vested(address _user) external view returns (uint256) {
97 return _vested(users[_user].amount);
98 }
99
100 /// @notice returns total claimed
101 function totalClaimed() external view returns (uint256) {
102 return _totalClaimed;
103 }
104
105 // ************************ //
106 // *** PUBLIC FUNCTIONS *** //
107 // ************************ //
108 /// @notice claim available tokens
109 /// @dev claim works for msg.sender
110 function claim() external nonReentrant {
111 if (start == 0 || seeded == 0) revert NotStarted();
112 uint256 _claimable = claimable(msg.sender);
113 if (_claimable == 0) revert NothingToClaim();
114
115 _totalClaimed += _claimable;
116 users[msg.sender].claimed += _claimable;
117 users[msg.sender].latestClaimTimestamp = block.timestamp;
118
119 token.safeTransfer(msg.sender, _claimable);
120 emit Claimed(msg.sender, _claimable);
121 }
122
123 // *********************** //
124 // *** OWNER FUNCTIONS *** //
125 // *********************** //
126 /// @notice adds a new user
127 /// @dev should be called before init
128 /// @param _user the user address
129 /// @param _amount user weight
130 function registerUser(address _user, uint256 _amount) external onlyOwner {
131 if (start > 0) revert Initialized();
132 if (_user == address(0)) revert AddressNotValid();
133 if (_amount == 0) revert AmountNotValid();
134 if (users[_user].amount > 0) revert AlreadyRegistered();
135
136 UserData memory data;
137 data.amount = _amount;
138 data.claimed = 0;
139 data.revoked = false;
140 data.latestClaimTimestamp = 0;
141 users[_user] = data;
142
143 _totalAmount += _amount;
144
145 emit UserRegistered(_user, _amount);
146 }
147
148 /// @notice inits the contract with total amount
149 /// @dev sets the start time to block.timestamp
150 /// @param _seededAmount total vested amount
151 function init(IERC20 _token, uint256 _seededAmount) external onlyOwner {
152 if (start > 0) revert Initialized();
153 if (_seededAmount == 0) revert NoTokens();
154 if (_totalAmount > _seededAmount) revert NotEnough();
155
156 token = _token;
157 uint256 availableToken = _token.balanceOf(address(this));
158 if (availableToken < _seededAmount) revert BalanceTooLow();
159
160 seeded = _seededAmount;
161 start = block.timestamp;
162 }
163
164 // ************************* //
165 // *** PRIVATE FUNCTIONS *** //
166 // ************************* //
167 function _vested(uint256 _total) private view returns (uint256) {
168 if (start == 0) return 0;
169 uint256 total = _total;
170 if (block.timestamp < start + cliff) return 0;
171 if (block.timestamp >= start + duration) return total;
172 return (total * (block.timestamp - start)) / duration;
173 }
174: }
File: contracts/governance/twTAP.sol
71 contract TwTAP is TWAML, ONFT721, ERC721Permit {
72 using SafeERC20 for IERC20;
73
74 TapOFT public immutable tapOFT;
75
76 /// ===== TWAML ======
77 TWAMLPool public twAML; // sglAssetId => twAMLPool
78
79 mapping(uint256 => Participation) public participants; // tokenId => part.
80
81 uint256 constant MIN_WEIGHT_FACTOR = 10; // In BPS, 0.1%
82 uint256 constant dMAX = 100 * 1e4; // 10% - 100% voting power multiplier
83 uint256 constant dMIN = 10 * 1e4;
84 uint256 public constant EPOCH_DURATION = 7 days;
85
86 // If we assume 128 bit balances for the reward token -- which fit 1e40
87 // "tokens" at the most commonly used 1e18 precision -- then we can use the
88 // other 128 bits to store the tokens allotted to a single vote more
89 // accurately. Votes in turn are proportional to the amount of TAP locked,
90 // weighted by a multiplier. This number is at most 107 bits long (see
91 // definition of `Participation` struct).
92 // the weight ranges from 10-100% where 1% = 1e4, so 1 million (20 bits).
93 // the multiplier is at most 100% = 1M (20 bits), so votes is at most a
94 // 107-bit number.
95 uint256 constant DIST_PRECISION = 2 ** 128;
96
97 IERC20[] public rewardTokens;
98 mapping(IERC20 => uint256) public rewardTokenIndex;
99 // tokenId -> rewardTokens index -> amount
100 mapping(uint256 => mapping(uint256 => uint256)) public claimed;
101
102 // The current week is determined by creation, but there are values that
103 // need to be updated weekly. If, for any reason whatsoever, this cannot
104 // be done in time, the `lastProcessedWeek` will be behind until this is
105 // done.
106 uint256 public mintedTWTap;
107 uint256 public creation; // Week 0 starts here
108 uint256 public lastProcessedWeek;
109 mapping(uint256 => WeekTotals) public weekTotals;
110
111 uint256 public immutable HOST_CHAIN_ID;
112 string private baseURI;
113
114 /// =====-------======
115 constructor(
116 address payable _tapOFT,
117 address _owner,
118 address _layerZeroEndpoint,
119 uint256 _hostChainID,
120 uint256 _minGas
121 )
122 ONFT721("Time Weighted TAP", "twTAP", _minGas, _layerZeroEndpoint)
123 ERC721Permit("Time Weighted TAP")
124 {
125 tapOFT = TapOFT(_tapOFT);
126 transferOwnership(_owner);
127 creation = block.timestamp;
128 HOST_CHAIN_ID = _hostChainID;
129 }
130
131 // ==========
132 // EVENTS
133 // ==========
134 event Participate(
135 address indexed participant,
136 uint256 tapAmount,
137 uint256 multiplier
138 );
139 event AMLDivergence(
140 uint256 cumulative,
141 uint256 averageMagnitude,
142 uint256 totalParticipants
143 );
144 event ExitPosition(uint256 tokenId, uint256 amount);
145
146 // ==========
147 // READ
148 // ==========
149
150 function currentWeek() public view returns (uint256) {
151 return (block.timestamp - creation) / EPOCH_DURATION;
152 }
153
154 /// @notice Return the participation of a token. Returns 0 votes for expired tokens.
155 function getParticipation(
156 uint _tokenId
157 ) public view returns (Participation memory participant) {
158 participant = participants[_tokenId];
159 if (participant.expiry < block.timestamp) {
160 participant.multiplier = 0;
161 }
162 return participant;
163 }
164
165 /// @notice Amount currently claimable for each reward token
166 function claimable(
167 uint256 _tokenId
168 ) public view returns (uint256[] memory) {
169 uint256 len = rewardTokens.length;
170 uint256[] memory result = new uint256[](len);
171
172 Participation memory position = participants[_tokenId];
173 uint256 votes;
174 unchecked {
175 // Math is safe: Types fit
176 votes = uint256(position.tapAmount) * uint256(position.multiplier);
177 }
178
179 if (votes == 0) {
180 return result;
181 }
182
183 // If the "last processed week" is behind the actual week, rewards
184 // get processed as if it were earlier.
185 uint256 week = lastProcessedWeek;
186 if (week <= position.lastInactive) {
187 return result;
188 }
189 if (position.lastActive < week) {
190 week = position.lastActive;
191 }
192
193 WeekTotals storage cur = weekTotals[week];
194 WeekTotals storage prev = weekTotals[position.lastInactive];
195
196 for (uint256 i = 0; i < len; ) {
197 // Math is safe (but we do the checks anyway):
198 //
199 // -- The `totalDistPerVote[i]` values are increasing as a
200 // function of weeks (see `advanceWeek()`), and if `week`
201 // were not greater than `position.lastInactive`, this bit
202 // of code would not be reached (see above). Therefore the
203 // subtraction in the calculation of `net` cannot underflow.
204 //
205 // -- `votes * net` is at most the entire reward amount given
206 // out, ever, in units of
207 //
208 // (reward tokens) * DIST_PRECISION.
209 //
210 // If this number were to exceed 256 bits, then
211 // `distributeReward` would revert.
212 //
213 // -- `claimed[_tokenId][i]` is the sum of all (the i-th values
214 // of) previous calls to the current function that were made
215 // by `_claimRewards()`. Let there be n such calls, and let
216 // r_j be `result[i]`, c_j be `claimed[_tokenId][i]`, and
217 // net_j be `net` during that j-th call. Then, up to a
218 // multiplication by votes / DIST_PRECISION:
219 //
220 // c_1 = 0 <= net_1,
221 //
222 // and, for n > 1:
223 //
224 // c_n = r_(n-1) + r_(n-2) + ... + r_1
225 // = r_(n-1) + c_(n-1)
226 // = (net_(n-1) - c_(n-1) + c_(n-1)
227 // = net_(n-1)
228 // <= net_n,
229 //
230 // so that the subtraction net_n - c_n does not underflow.
231 // (The rounding the calculation favors the greater first
232 // term).
233 // (TODO: Word better?)
234 //
235 uint256 net = cur.totalDistPerVote[i] - prev.totalDistPerVote[i];
236 result[i] = ((votes * net) / DIST_PRECISION) - claimed[_tokenId][i];
237 unchecked {
238 ++i;
239 }
240 }
241 return result;
242 }
243
244 // ===========
245 // WRITE
246 // ===========
247
248 /// @notice Participate in twAMl voting and mint an oTAP position
249 /// @param _participant The address of the participant
250 /// @param _amount The amount of TAP to participate with
251 /// @param _duration The duration of the lock
252 function participate(
253 address _participant,
254 uint256 _amount,
255 uint256 _duration
256 ) external returns (uint256 tokenId) {
257 require(_duration >= EPOCH_DURATION, "twTAP: Lock not a week");
258
259 // Transfer TAP to this contract
260 tapOFT.transferFrom(msg.sender, address(this), _amount);
261
262 // Copy to memory
263 TWAMLPool memory pool = twAML;
264
265 uint256 magnitude = computeMagnitude(_duration, pool.cumulative);
266 bool divergenceForce;
267 uint256 multiplier = computeTarget(
268 dMIN,
269 dMAX,
270 magnitude,
271 pool.cumulative
272 );
273
274 // Calculate twAML voting weight
275 bool hasVotingPower = _amount >=
276 computeMinWeight(pool.totalDeposited, MIN_WEIGHT_FACTOR);
277 if (hasVotingPower) {
278 pool.totalParticipants++; // Save participation
279 pool.averageMagnitude =
280 (pool.averageMagnitude + magnitude) /
281 pool.totalParticipants; // compute new average magnitude
282
283 // Compute and save new cumulative
284 divergenceForce = _duration > pool.cumulative;
285
286 if (divergenceForce) {
287 pool.cumulative += pool.averageMagnitude;
288 } else {
289 // TODO: Strongly suspect this is never less. Prove it.
290 if (pool.cumulative > pool.averageMagnitude) {
291 pool.cumulative -= pool.averageMagnitude;
292 } else {
293 pool.cumulative = 0;
294 }
295 }
296
297 // Save new weight
298 pool.totalDeposited += _amount;
299
300 twAML = pool; // Save twAML participation
301 emit AMLDivergence(
302 pool.cumulative,
303 pool.averageMagnitude,
304 pool.totalParticipants
305 );
306 }
307
308 // Mint twTAP position
309 tokenId = ++mintedTWTap;
310 _safeMint(_participant, tokenId);
311
312 uint256 expiry = block.timestamp + _duration;
313 require(expiry < type(uint56).max, "twTAP: too long");
314 // Eligibility starts NEXT week, and lasts until the week that the lock
315 // expires. This is guaranteed to be at least one week later by the
316 // check on `_duration`.
317 // If a user locks right before the current week ends, and have a
318 // duration slightly over one week, straddling the two starting points,
319 // then that user is eligible for the rewards during both weeks; the
320 // price for this maneuver is a lower multiplier, and loss of voting
321 // power in the DAO after the lock expires.
322 uint256 w0 = currentWeek();
323 uint256 w1 = (expiry - creation) / EPOCH_DURATION;
324
325 // Save twAML participation
326 // Casts are safe: see struct definition
327 uint256 votes = _amount * multiplier;
328 participants[tokenId] = Participation({
329 averageMagnitude: pool.averageMagnitude,
330 hasVotingPower: hasVotingPower,
331 divergenceForce: divergenceForce,
332 tapReleased: false,
333 expiry: uint56(expiry),
334 tapAmount: uint88(_amount),
335 multiplier: uint24(multiplier),
336 lastInactive: uint40(w0),
337 lastActive: uint40(w1)
338 });
339
340 // w0 + 1 = lastInactive + 1 = first active
341 // w1 + 1 = lastActive + 1 = first inactive
342 // Cast is safe: `votes` is the product of a uint88 and a uint24
343 weekTotals[w0 + 1].netActiveVotes += int256(votes);
344 weekTotals[w1 + 1].netActiveVotes -= int256(votes);
345
346 emit Participate(_participant, _amount, multiplier);
347 // TODO: Mint event?
348 }
349
350 /// @notice claims all rewards distributed since token mint or last claim.
351 /// @param _tokenId tokenId whose rewards to claim
352 /// @param _to address to receive the rewards
353 function claimRewards(uint256 _tokenId, address _to) external {
354 _requireClaimPermission(_to, _tokenId);
355 _claimRewards(_tokenId, _to);
356 }
357
358 /// @notice claims all rewards distributed since token mint or last claim, and send them to another chain.
359 /// @param _tokenId The tokenId of the twTAP position
360 /// @param _rewardTokens The address of the reward token
361 function claimAndSendRewards(
362 uint256 _tokenId,
363 IERC20[] memory _rewardTokens
364 ) external {
365 require(msg.sender == address(tapOFT), "twTAP: only tapOFT");
366 _claimRewardsOn(_tokenId, address(tapOFT), _rewardTokens);
367 }
368
369 /// @notice claims the TAP locked in a position whose votes have expired,
370 /// @notice and undoes the effect on the twAML calculations.
371 /// @param _tokenId tokenId whose locked TAP to claim
372 /// @param _to address to receive the TAP
373 function releaseTap(uint256 _tokenId, address _to) external {
374 _requireClaimPermission(_to, _tokenId);
375 _releaseTap(_tokenId, _to);
376 }
377
378 /// @notice Exit a twAML participation and delete the voting power if existing
379 /// @param _tokenId The tokenId of the twTAP position
380 function exitPosition(uint256 _tokenId) external {
381 address to = ownerOf(_tokenId);
382 _releaseTap(_tokenId, to);
383 }
384
385 /// @notice Exit a twAML participation and send the withdrawn TAP to tapOFT to send it to another chain.
386 /// @param _tokenId The tokenId of the twTAP position
387 function exitPositionAndSendTap(
388 uint256 _tokenId
389 ) external returns (uint256) {
390 require(msg.sender == address(tapOFT), "twTAP: only tapOFT");
391 return _releaseTap(_tokenId, address(tapOFT));
392 }
393
394 /// @notice Indicate that (a) week(s) have passed and update running totals
395 /// @notice Reverts if called in week 0. Let it.
396 /// @param _limit Maximum number of weeks to process in one call
397 function advanceWeek(uint256 _limit) public {
398 // TODO: Make whole function unchecked
399 uint256 cur = currentWeek();
400 uint256 week = lastProcessedWeek;
401 uint256 goal = cur;
402 unchecked {
403 if (goal - week > _limit) {
404 goal = week + _limit;
405 }
406 }
407 uint256 len = rewardTokens.length;
408 while (week < goal) {
409 WeekTotals storage prev = weekTotals[week];
410 WeekTotals storage next = weekTotals[++week];
411 // TODO: Prove that math is safe
412 next.netActiveVotes += prev.netActiveVotes;
413 for (uint256 i = 0; i < len; ) {
414 next.totalDistPerVote[i] += prev.totalDistPerVote[i];
415 unchecked {
416 ++i;
417 }
418 }
419 }
420 lastProcessedWeek = goal;
421 }
422
423 /// @notice distributes a reward among all tokens, weighted by voting power
424 /// @notice The reward gets allocated to all positions that have locked in
425 /// @notice the current week. Fails, intentionally, if this number is zero.
426 /// @notice Total rewards cannot exceed 2^128 tokens.
427 /// @param _rewardTokenId index of the reward in `rewardTokens`
428 /// @param _amount amount of reward token to distribute.
429 function distributeReward(
430 uint256 _rewardTokenId,
431 uint256 _amount
432 ) external {
433 require(
434 lastProcessedWeek == currentWeek(),
435 "twTAP: Advance week first"
436 );
437 WeekTotals storage totals = weekTotals[lastProcessedWeek];
438 IERC20 rewardToken = rewardTokens[_rewardTokenId];
439 // If this is a DBZ then there are no positions to give the reward to.
440 // Since reward eligibility starts in the week after locking, there is
441 // no way to give out rewards THIS week.
442 // Cast is safe: `netActiveVotes` is at most zero by construction of
443 // weekly totals and the requirement that they are up to date.
444 // TODO: Word this better
445 totals.totalDistPerVote[_rewardTokenId] +=
446 (_amount * DIST_PRECISION) /
447 uint256(totals.netActiveVotes);
448 rewardToken.safeTransferFrom(msg.sender, address(this), _amount);
449 }
450
451 // =========
452 // OWNER
453 // =========
454
455 function addRewardToken(IERC20 token) external onlyOwner returns (uint256) {
456 uint256 i = rewardTokens.length;
457 rewardTokens.push(token);
458 rewardTokenIndex[token] = i;
459 return i;
460 }
461
462 // ============
463 // INTERNAL
464 // ============
465
466 /// @dev Mirrors the implementation of _isApprovedOrOwner, with the modification
467 /// that it is allowed if `_to` is the owner:
468 function _requireClaimPermission(
469 address _to,
470 uint256 _tokenId
471 ) internal view {
472 address tokenOwner = ownerOf(_tokenId);
473 require(
474 msg.sender == tokenOwner ||
475 _to == tokenOwner ||
476 isApprovedForAll(tokenOwner, msg.sender) ||
477 getApproved(_tokenId) == msg.sender,
478 "twTAP: cannot claim"
479 );
480 }
481
482 /// @dev Claim all rewards on a position and send them to `_to`.
483 function _claimRewards(uint256 _tokenId, address _to) internal {
484 uint256[] memory amounts = claimable(_tokenId);
485 uint256 len = amounts.length;
486 unchecked {
487 for (uint256 i = 0; i < len; ++i) {
488 uint256 amount = amounts[i];
489 if (amount > 0) {
490 // Math is safe: `amount` calculated safely in `claimable()`
491 claimed[_tokenId][i] += amount;
492 rewardTokens[i].safeTransfer(_to, amount);
493 }
494 }
495 }
496 }
497
498 /// @dev Claim rewards of a specific token on a position and send them to `_to`.
499 function _claimRewardsOn(
500 uint256 _tokenId,
501 address _to,
502 IERC20[] memory _rewardTokens
503 ) internal {
504 uint256[] memory amounts = claimable(_tokenId);
505 unchecked {
506 uint256 len = _rewardTokens.length;
507 for (uint256 i = 0; i < len; ) {
508 uint256 claimableIndex = rewardTokenIndex[_rewardTokens[i]];
509 uint256 amount = amounts[i];
510
511 if (amount > 0) {
512 // Math is safe: `amount` calculated safely in `claimable()`
513 claimed[_tokenId][claimableIndex] += amount;
514 rewardTokens[claimableIndex].safeTransfer(_to, amount);
515 }
516 ++i;
517 }
518 }
519 }
520
521 /// @dev Release the tap of a position and send it to `_to`. Remove the user from twAML.
522 function _releaseTap(
523 uint256 _tokenId,
524 address _to
525 ) internal returns (uint256 releasedAmount) {
526 Participation memory position = participants[_tokenId];
527 if (position.tapReleased) {
528 return 0;
529 }
530 require(position.expiry <= block.timestamp, "twTAP: Lock not expired");
531
532 releasedAmount = position.tapAmount;
533
534 // Remove participation
535 if (position.hasVotingPower) {
536 TWAMLPool memory pool = twAML;
537 pool.totalParticipants--;
538
539 // Inverse of the participation. The participation entry tracks
540 // the average magnitude as it was at the time the participant
541 // entered. When going the other way around, this value matches the
542 // one in the pool, but here it does not.
543 if (position.divergenceForce) {
544 if (pool.cumulative > position.averageMagnitude) {
545 pool.cumulative -= position.averageMagnitude;
546 } else {
547 pool.cumulative = 0;
548 }
549 } else {
550 pool.cumulative += position.averageMagnitude;
551 }
552
553 // Save new weight
554 pool.totalDeposited -= position.tapAmount;
555
556 twAML = pool; // Save twAML exit
557 emit AMLDivergence(
558 pool.cumulative,
559 pool.averageMagnitude,
560 pool.totalParticipants
561 ); // Register new voting power event
562 }
563
564 participants[_tokenId].tapReleased = true;
565 tapOFT.transfer(_to, releasedAmount);
566
567 emit ExitPosition(_tokenId, releasedAmount);
568 }
569
570 /// @dev Returns the chain ID of the current network
571 function _getChainId() internal view virtual returns (uint256) {
572 uint256 chainId;
573 assembly {
574 chainId := chainid()
575 }
576 return chainId;
577 }
578
579 /**
580 * @dev See {IERC165-supportsInterface}.
581 */
582 function supportsInterface(
583 bytes4 interfaceId
584 ) public view virtual override(ONFT721, ERC721) returns (bool) {
585 return super.supportsInterface(interfaceId);
586 }
587: }
File: contracts/option-airdrop/AirdropBroker.sol
43 contract AirdropBroker is Pausable, BoringOwnable, FullMath {
44 bytes public tapOracleData;
45 TapOFT public immutable tapOFT;
46 AOTAP public immutable aoTAP;
47 IOracle public tapOracle;
48 IERC721 public immutable PCNFT;
49
50 uint128 public epochTAPValuation; // TAP price for the current epoch
51 uint64 public lastEpochUpdate; // timestamp of the last epoch update
52 uint64 public epoch; // Represents the number of weeks since the start of the contract
53
54 mapping(ERC20 => PaymentTokenOracle) public paymentTokens; // Token address => PaymentTokenOracle
55 address public paymentTokenBeneficiary; // Where to collect the payment tokens
56
57 mapping(uint256 => mapping(uint256 => uint256)) public aoTAPCalls; // oTAPTokenID => epoch => amountExercised
58
59 /// @notice Record of participation in phase 2 airdrop
60 /// Only applicable for phase 2. To get subphases on phase 2 we do userParticipation[_user][20+roles]
61 mapping(address => mapping(uint256 => bool)) public userParticipation; // user address => phase => participated
62
63 /// =====-------======
64 /// Phase 1
65 /// =====-------======
66
67 /// @notice user address => eligible TAP amount, 0 means no eligibility
68 mapping(address => uint256) public phase1Users;
69 uint256 public constant PHASE_1_DISCOUNT = 50 * 1e4; // 50%
70
71 /// =====-------======
72 /// Phase 2
73 /// =====-------======
74
75 // [OG Pearls, Sushi Frens, Tapiocans, Oysters, Cassava]
76 bytes32[4] public phase2MerkleRoots; // merkle root of phase 2 airdrop
77 uint8[4] public PHASE_2_AMOUNT_PER_USER = [200, 190, 200, 190];
78 uint8[4] public PHASE_2_DISCOUNT_PER_USER = [50, 40, 40, 33];
79
80 /// =====-------======
81 /// Phase 3
82 /// =====-------======
83
84 uint256 public constant PHASE_3_AMOUNT_PER_USER = 714;
85 uint256 public constant PHASE_3_DISCOUNT = 50 * 1e4;
86
87 /// =====-------======
88 /// Phase 4
89 /// =====-------======
90
91 /// @notice user address => eligible TAP amount, 0 means no eligibility
92 mapping(address => uint256) public phase4Users;
93 uint256 public constant PHASE_4_DISCOUNT = 33 * 1e4;
94
95 uint256 public constant EPOCH_DURATION = 2 days;
96
97 /// =====-------======
98 constructor(
99 address _aoTAP,
100 address payable _tapOFT,
101 address _pcnft,
102 address _paymentTokenBeneficiary,
103 address _owner
104 ) {
105 paymentTokenBeneficiary = _paymentTokenBeneficiary;
106 tapOFT = TapOFT(_tapOFT);
107 aoTAP = AOTAP(_aoTAP);
108 PCNFT = IERC721(_pcnft);
109 owner = _owner;
110 }
111
112 // ==========
113 // EVENTS
114 // ==========
115 event Participate(uint256 indexed epoch, uint256 aoTAPTokenID);
116 event ExerciseOption(
117 uint256 indexed epoch,
118 address indexed to,
119 ERC20 indexed paymentToken,
120 uint256 aoTapTokenID,
121 uint256 amount
122 );
123 event NewEpoch(uint256 indexed epoch, uint256 epochTAPValuation);
124
125 event SetPaymentToken(ERC20 paymentToken, IOracle oracle, bytes oracleData);
126 event SetTapOracle(IOracle oracle, bytes oracleData);
127
128 // ==========
129 // READ
130 // ==========
131
132 /// @notice Returns the details of an OTC deal for a given oTAP token ID and a payment token.
133 /// The oracle uses the last peeked value, and not the latest one, so the payment amount may be different.
134 /// @param _aoTAPTokenID The aoTAP token ID
135 /// @param _paymentToken The payment token
136 /// @param _tapAmount The amount of TAP to be exchanged. If 0 it will use the full amount of TAP eligible for the deal
137 /// @return eligibleTapAmount The amount of TAP eligible for the deal
138 /// @return paymentTokenAmount The amount of payment tokens required for the deal
139 /// @return tapAmount The amount of TAP to be exchanged
140
141 function getOTCDealDetails(
142 uint256 _aoTAPTokenID,
143 ERC20 _paymentToken,
144 uint256 _tapAmount
145 )
146 external
147 view
148 returns (
149 uint256 eligibleTapAmount,
150 uint256 paymentTokenAmount,
151 uint256 tapAmount
152 )
153 {
154 // Load data
155 (, AirdropTapOption memory aoTapOption) = aoTAP.attributes(
156 _aoTAPTokenID
157 );
158 require(aoTapOption.expiry > block.timestamp, "adb: Option expired");
159
160 uint256 cachedEpoch = epoch;
161
162 PaymentTokenOracle memory paymentTokenOracle = paymentTokens[
163 _paymentToken
164 ];
165
166 // Check requirements
167 require(
168 paymentTokenOracle.oracle != IOracle(address(0)),
169 "adb: Payment token not supported"
170 );
171
172 eligibleTapAmount = aoTapOption.amount;
173 eligibleTapAmount -= aoTAPCalls[_aoTAPTokenID][cachedEpoch]; // Subtract already exercised amount
174 require(eligibleTapAmount >= _tapAmount, "adb: Too high");
175
176 tapAmount = _tapAmount == 0 ? eligibleTapAmount : _tapAmount;
177 require(tapAmount >= 1e18, "adb: Too low");
178 // Get TAP valuation
179 uint256 otcAmountInUSD = tapAmount * epochTAPValuation; // Divided by TAP decimals
180 // Get payment token valuation
181 (, uint256 paymentTokenValuation) = paymentTokenOracle.oracle.peek(
182 paymentTokenOracle.oracleData
183 );
184 // Get payment token amount
185 paymentTokenAmount = _getDiscountedPaymentAmount(
186 otcAmountInUSD,
187 paymentTokenValuation,
188 aoTapOption.discount,
189 _paymentToken.decimals()
190 );
191 }
192
193 // ===========
194 // WRITE
195 // ===========
196
197 /// @notice Participate in the airdrop
198 /// @param _data The data to be used for the participation, varies by phases
199 function participate(
200 bytes calldata _data
201 ) external returns (uint256 aoTAPTokenID) {
202 uint256 cachedEpoch = epoch;
203 require(cachedEpoch > 0, "adb: Airdrop not started");
204 require(cachedEpoch <= 4, "adb: Airdrop ended");
205
206 // Phase 1
207 if (cachedEpoch == 1) {
208 aoTAPTokenID = _participatePhase1();
209 } else if (cachedEpoch == 2) {
210 aoTAPTokenID = _participatePhase2(_data); // _data = (uint256 role, bytes32[] _merkleProof)
211 } else if (cachedEpoch == 3) {
212 aoTAPTokenID = _participatePhase3(_data); // _data = (uint256 _tokenID)
213 } else if (cachedEpoch == 4) {
214 aoTAPTokenID = _participatePhase4();
215 }
216
217 emit Participate(cachedEpoch, aoTAPTokenID);
218 }
219
220 /// @notice Exercise an aoTAP position
221 /// @param _aoTAPTokenID tokenId of the aoTAP position, position must be active
222 /// @param _paymentToken Address of the payment token to use, must be whitelisted
223 /// @param _tapAmount Amount of TAP to exercise. If 0, the full amount is exercised
224 function exerciseOption(
225 uint256 _aoTAPTokenID,
226 ERC20 _paymentToken,
227 uint256 _tapAmount
228 ) external {
229 // Load data
230 (, AirdropTapOption memory aoTapOption) = aoTAP.attributes(
231 _aoTAPTokenID
232 );
233 require(aoTapOption.expiry > block.timestamp, "adb: Option expired");
234
235 uint256 cachedEpoch = epoch;
236
237 PaymentTokenOracle memory paymentTokenOracle = paymentTokens[
238 _paymentToken
239 ];
240
241 // Check requirements
242 require(
243 paymentTokenOracle.oracle != IOracle(address(0)),
244 "adb: Payment token not supported"
245 );
246 require(
247 aoTAP.isApprovedOrOwner(msg.sender, _aoTAPTokenID),
248 "adb: Not approved or owner"
249 );
250
251 // Get eligible OTC amount
252
253 uint256 eligibleTapAmount = aoTapOption.amount;
254 eligibleTapAmount -= aoTAPCalls[_aoTAPTokenID][cachedEpoch]; // Subtract already exercised amount
255 require(eligibleTapAmount >= _tapAmount, "adb: Too high");
256
257 uint256 chosenAmount = _tapAmount == 0 ? eligibleTapAmount : _tapAmount;
258 require(chosenAmount >= 1e18, "adb: Too low");
259 aoTAPCalls[_aoTAPTokenID][cachedEpoch] += chosenAmount; // Adds up exercised amount to current epoch
260
261 // Finalize the deal
262 _processOTCDeal(
263 _paymentToken,
264 paymentTokenOracle,
265 chosenAmount,
266 aoTapOption.discount
267 );
268
269 emit ExerciseOption(
270 cachedEpoch,
271 msg.sender,
272 _paymentToken,
273 _aoTAPTokenID,
274 chosenAmount
275 );
276 }
277
278 /// @notice Start a new epoch, extract TAP from the TapOFT contract,
279 /// emit it to the active singularities and get the price of TAP for the epoch.
280 function newEpoch() external {
281 require(
282 block.timestamp >= lastEpochUpdate + EPOCH_DURATION,
283 "adb: too soon"
284 );
285
286 // Update epoch info
287 lastEpochUpdate = uint64(block.timestamp);
288 epoch++;
289
290 // Get epoch TAP valuation
291 (, uint256 _epochTAPValuation) = tapOracle.get(tapOracleData);
292 epochTAPValuation = uint128(_epochTAPValuation);
293 emit NewEpoch(epoch, epochTAPValuation);
294 }
295
296 /// @notice Claim the Broker role of the aoTAP contract
297 function aoTAPBrokerClaim() external {
298 aoTAP.brokerClaim();
299 }
300
301 // =========
302 // OWNER
303 // =========
304
305 /// @notice Set the TapOFT Oracle address and data
306 /// @param _tapOracle The new TapOFT Oracle address
307 /// @param _tapOracleData The new TapOFT Oracle data
308 function setTapOracle(
309 IOracle _tapOracle,
310 bytes calldata _tapOracleData
311 ) external onlyOwner {
312 tapOracle = _tapOracle;
313 tapOracleData = _tapOracleData;
314
315 emit SetTapOracle(_tapOracle, _tapOracleData);
316 }
317
318 function setPhase2MerkleRoots(
319 bytes32[4] calldata _merkleRoots
320 ) external onlyOwner {
321 phase2MerkleRoots = _merkleRoots;
322 }
323
324 function registerUserForPhase(
325 uint256 _phase,
326 address[] calldata _users,
327 uint256[] calldata _amounts
328 ) external onlyOwner {
329 require(_users.length == _amounts.length, "adb: invalid input");
330
331 if (_phase == 1) {
332 for (uint256 i = 0; i < _users.length; i++) {
333 phase1Users[_users[i]] = _amounts[i];
334 }
335 } else if (_phase == 4) {
336 for (uint256 i = 0; i < _users.length; i++) {
337 phase4Users[_users[i]] = _amounts[i];
338 }
339 }
340 }
341
342 /// @notice Activate or deactivate a payment token
343 /// @dev set the oracle to address(0) to deactivate, expect the same decimal precision as TAP oracle
344 function setPaymentToken(
345 ERC20 _paymentToken,
346 IOracle _oracle,
347 bytes calldata _oracleData
348 ) external onlyOwner {
349 paymentTokens[_paymentToken].oracle = _oracle;
350 paymentTokens[_paymentToken].oracleData = _oracleData;
351
352 emit SetPaymentToken(_paymentToken, _oracle, _oracleData);
353 }
354
355 /// @notice Set the payment token beneficiary
356 /// @param _paymentTokenBeneficiary The new payment token beneficiary
357 function setPaymentTokenBeneficiary(
358 address _paymentTokenBeneficiary
359 ) external onlyOwner {
360 paymentTokenBeneficiary = _paymentTokenBeneficiary;
361 }
362
363 /// @notice Collect the payment tokens from the OTC deals
364 /// @param _paymentTokens The payment tokens to collect
365 function collectPaymentTokens(
366 address[] calldata _paymentTokens
367 ) external onlyOwner {
368 require(
369 paymentTokenBeneficiary != address(0),
370 "adb: Payment token beneficiary not set"
371 );
372 uint256 len = _paymentTokens.length;
373
374 unchecked {
375 for (uint256 i = 0; i < len; ++i) {
376 ERC20 paymentToken = ERC20(_paymentTokens[i]);
377 paymentToken.transfer(
378 paymentTokenBeneficiary,
379 paymentToken.balanceOf(address(this))
380 );
381 }
382 }
383 }
384
385 // ============
386 // INTERNAL
387 // ============
388
389 /// @notice Participate in phase 1 of the Airdrop. LBP users are given aoTAP pro-rata.
390 function _participatePhase1() internal returns (uint256 oTAPTokenID) {
391 uint256 _eligibleAmount = phase1Users[msg.sender];
392 require(_eligibleAmount > 0, "adb: Not eligible");
393
394 // Close eligibility
395 phase1Users[msg.sender] = 0;
396
397 // Mint aoTAP
398 uint128 expiry = uint128(lastEpochUpdate + EPOCH_DURATION); // Set expiry to the end of the epoch
399 oTAPTokenID = aoTAP.mint(
400 msg.sender,
401 expiry,
402 uint128(PHASE_1_DISCOUNT),
403 _eligibleAmount
404 );
405 }
406
407 /// @notice Participate in phase 2 of the Airdrop. Guild members will receive pre-defined discounts and TAP, based on role.
408 /// @param _data The calldata. Needs to be the address of the user.
409 /// _data = (uint256 role, bytes32[] _merkleProof). Refer to {phase2MerkleRoots} for role.
410 function _participatePhase2(
411 bytes calldata _data
412 ) internal returns (uint256 oTAPTokenID) {
413 (uint256 _role, bytes32[] memory _merkleProof) = abi.decode(
414 _data,
415 (uint256, bytes32[])
416 );
417
418 bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
419 require(
420 MerkleProof.verify(_merkleProof, phase2MerkleRoots[_role], leaf),
421 "adb: Not eligible"
422 );
423
424 uint256 subPhase = 20 + _role;
425 require(
426 userParticipation[msg.sender][subPhase] == false,
427 "adb: Already participated"
428 );
429 // Close eligibility
430 userParticipation[msg.sender][subPhase] = true;
431
432 // Mint aoTAP
433 uint128 expiry = uint128(lastEpochUpdate + EPOCH_DURATION); // Set expiry to the end of the epoch
434 uint256 eligibleAmount = uint256(PHASE_2_AMOUNT_PER_USER[_role]) * 1e18;
435 uint128 discount = uint128(PHASE_2_DISCOUNT_PER_USER[_role]) * 1e4;
436 oTAPTokenID = aoTAP.mint(msg.sender, expiry, discount, eligibleAmount);
437 }
438
439 /// @notice Participate in phase 1 of the Airdrop. PCNFT holder will receive pre-defined discount and TAP.
440 /// @param _data The calldata. Needs to be the address of the user.
441 /// _data = (uint256 _tokenID)
442 function _participatePhase3(
443 bytes calldata _data
444 ) internal returns (uint256 oTAPTokenID) {
445 uint256 _tokenID = abi.decode(_data, (uint256));
446
447 require(PCNFT.ownerOf(_tokenID) == msg.sender, "adb: Not eligible");
448 address tokenIDToAddress = address(uint160(_tokenID));
449 require(
450 userParticipation[tokenIDToAddress][3] == false,
451 "adb: Already participated"
452 );
453 // Close eligibility
454 // To avoid a potential attack vector, we cast token ID to an address instead of using _to,
455 // no conflict possible, tokenID goes from 0 ... 714.
456 userParticipation[tokenIDToAddress][3] = true;
457
458 uint128 expiry = uint128(lastEpochUpdate + EPOCH_DURATION); // Set expiry to the end of the epoch
459 uint256 eligibleAmount = PHASE_3_AMOUNT_PER_USER;
460 uint128 discount = uint128(PHASE_3_DISCOUNT);
461 oTAPTokenID = aoTAP.mint(msg.sender, expiry, discount, eligibleAmount);
462 }
463
464 /// @notice Participate in phase 4 of the Airdrop. twTAP and Cassava guild's role are given TAP pro-rata.
465 function _participatePhase4() internal returns (uint256 oTAPTokenID) {
466 uint256 _eligibleAmount = phase4Users[msg.sender];
467 require(_eligibleAmount > 0, "adb: Not eligible");
468
469 // Close eligibility
470 phase4Users[msg.sender] = 0;
471
472 // Mint aoTAP
473 uint128 expiry = uint128(lastEpochUpdate + EPOCH_DURATION); // Set expiry to the end of the epoch
474 oTAPTokenID = aoTAP.mint(
475 msg.sender,
476 expiry,
477 uint128(PHASE_4_DISCOUNT),
478 _eligibleAmount
479 );
480 }
481
482 /// @notice Process the OTC deal, transfer the payment token to the broker and the TAP amount to the user
483 /// @param _paymentToken The payment token
484 /// @param _paymentTokenOracle The oracle of the payment token
485 /// @param tapAmount The amount of TAP that the user has to receive
486 /// @param discount The discount that the user has to apply to the OTC deal
487 function _processOTCDeal(
488 ERC20 _paymentToken,
489 PaymentTokenOracle memory _paymentTokenOracle,
490 uint256 tapAmount,
491 uint256 discount
492 ) internal {
493 // Get TAP valuation
494 uint256 otcAmountInUSD = tapAmount * epochTAPValuation;
495
496 // Get payment token valuation
497 (, uint256 paymentTokenValuation) = _paymentTokenOracle.oracle.get(
498 _paymentTokenOracle.oracleData
499 );
500
501 // Calculate payment amount and initiate the transfers
502 uint256 discountedPaymentAmount = _getDiscountedPaymentAmount(
503 otcAmountInUSD,
504 paymentTokenValuation,
505 discount,
506 _paymentToken.decimals()
507 );
508
509 _paymentToken.transferFrom(
510 msg.sender,
511 address(this),
512 discountedPaymentAmount
513 );
514 tapOFT.transfer(msg.sender, tapAmount);
515 }
516
517 /// @notice Computes the discounted payment amount for a given OTC amount in USD
518 /// @param _otcAmountInUSD The OTC amount in USD, 18 decimals
519 /// @param _paymentTokenValuation The payment token valuation in USD, 18 decimals
520 /// @param _discount The discount in BPS
521 /// @param _paymentTokenDecimals The payment token decimals
522 /// @return paymentAmount The discounted payment amount
523 function _getDiscountedPaymentAmount(
524 uint256 _otcAmountInUSD,
525 uint256 _paymentTokenValuation,
526 uint256 _discount,
527 uint256 _paymentTokenDecimals
528 ) internal pure returns (uint256 paymentAmount) {
529 // Calculate payment amount
530 uint256 rawPaymentAmount = _otcAmountInUSD / _paymentTokenValuation;
531 paymentAmount =
532 rawPaymentAmount -
533 muldiv(rawPaymentAmount, _discount, 100e4); // 1e4 is discount decimals, 100 is discount percentage
534
535 paymentAmount = paymentAmount / (10 ** (18 - _paymentTokenDecimals));
536 }
537: }
File: contracts/options/TapiocaOptionBroker.sol
53 contract TapiocaOptionBroker is Pausable, BoringOwnable, TWAML {
54 TapiocaOptionLiquidityProvision public immutable tOLP;
55 bytes public tapOracleData;
56 TapOFT public immutable tapOFT;
57 OTAP public immutable oTAP;
58 IOracle public tapOracle;
59
60 uint256 public lastEpochUpdate; // timestamp of the last epoch update
61 uint256 public epochTAPValuation; // TAP price for the current epoch
62 uint256 public epoch; // Represents the number of weeks since the start of the contract
63
64 mapping(uint256 => Participation) public participants; // tOLPTokenID => Participation
65 mapping(uint256 => mapping(uint256 => uint256)) public oTAPCalls; // oTAPTokenID => epoch => amountExercised
66
67 mapping(uint256 => mapping(uint256 => uint256)) public singularityGauges; // epoch => sglAssetId => availableTAP
68
69 mapping(ERC20 => PaymentTokenOracle) public paymentTokens; // Token address => PaymentTokenOracle
70 address public paymentTokenBeneficiary; // Where to collect the payment tokens
71
72 /// ===== TWAML ======
73 mapping(uint256 => TWAMLPool) public twAML; // sglAssetId => twAMLPool
74
75 uint256 constant MIN_WEIGHT_FACTOR = 10; // In BPS, 0.1%
76 uint256 constant dMAX = 50 * 1e4; // 5% - 50% discount
77 uint256 constant dMIN = 5 * 1e4;
78 uint256 public immutable EPOCH_DURATION; // 7 days = 604800
79
80 /// =====-------======
81 constructor(
82 address _tOLP,
83 address _oTAP,
84 address payable _tapOFT,
85 address _paymentTokenBeneficiary,
86 uint256 _epochDuration,
87 address _owner
88 ) {
89 paymentTokenBeneficiary = _paymentTokenBeneficiary;
90 tOLP = TapiocaOptionLiquidityProvision(_tOLP);
91 tapOFT = TapOFT(_tapOFT);
92 oTAP = OTAP(_oTAP);
93 EPOCH_DURATION = _epochDuration;
94 owner = _owner;
95 }
96
97 // ==========
98 // EVENTS
99 // ==========
100 event Participate(
101 uint256 indexed epoch,
102 uint256 indexed sglAssetID,
103 uint256 totalDeposited,
104 LockPosition lock,
105 uint256 discount
106 );
107 event AMLDivergence(
108 uint256 indexed epoch,
109 uint256 cumulative,
110 uint256 averageMagnitude,
111 uint256 totalParticipants
112 );
113 event ExerciseOption(
114 uint256 indexed epoch,
115 address indexed to,
116 ERC20 indexed paymentToken,
117 uint256 oTapTokenID,
118 uint256 amount
119 );
120 event NewEpoch(
121 uint256 indexed epoch,
122 uint256 extractedTAP,
123 uint256 epochTAPValuation
124 );
125 event ExitPosition(
126 uint256 indexed epoch,
127 uint256 indexed tokenId,
128 uint256 amount
129 );
130 event SetPaymentToken(ERC20 paymentToken, IOracle oracle, bytes oracleData);
131 event SetTapOracle(IOracle oracle, bytes oracleData);
132
133 // ==========
134 // READ
135 // ==========
136
137 /// @notice Returns the details of an OTC deal for a given oTAP token ID and a payment token.
138 /// The oracle uses the last peeked value, and not the latest one, so the payment amount may be different.
139 /// @param _oTAPTokenID The oTAP token ID
140 /// @param _paymentToken The payment token
141 /// @param _tapAmount The amount of TAP to be exchanged. If 0 it will use the full amount of TAP eligible for the deal
142 /// @return eligibleTapAmount The amount of TAP eligible for the deal
143 /// @return paymentTokenAmount The amount of payment tokens required for the deal
144 /// @return tapAmount The amount of TAP to be exchanged
145 function getOTCDealDetails(
146 uint256 _oTAPTokenID,
147 ERC20 _paymentToken,
148 uint256 _tapAmount
149 )
150 external
151 view
152 returns (
153 uint256 eligibleTapAmount,
154 uint256 paymentTokenAmount,
155 uint256 tapAmount
156 )
157 {
158 // Load data
159 (, TapOption memory oTAPPosition) = oTAP.attributes(_oTAPTokenID);
160 (bool isPositionActive, LockPosition memory tOLPLockPosition) = tOLP
161 .getLock(oTAPPosition.tOLP);
162
163 uint256 cachedEpoch = epoch;
164
165 PaymentTokenOracle memory paymentTokenOracle = paymentTokens[
166 _paymentToken
167 ];
168
169 // Check requirements
170 require(
171 paymentTokenOracle.oracle != IOracle(address(0)),
172 "tOB: Payment token not supported"
173 );
174
175 require(isPositionActive, "tOB: Option expired");
176
177 // Get eligible OTC amount
178 uint256 gaugeTotalForEpoch = singularityGauges[cachedEpoch][
179 tOLPLockPosition.sglAssetID
180 ];
181 eligibleTapAmount = muldiv(
182 tOLPLockPosition.amount,
183 gaugeTotalForEpoch,
184 tOLP.getTotalPoolDeposited(tOLPLockPosition.sglAssetID)
185 );
186 eligibleTapAmount -= oTAPCalls[_oTAPTokenID][cachedEpoch]; // Subtract already exercised amount
187 require(eligibleTapAmount >= _tapAmount, "tOB: Too high");
188
189 tapAmount = _tapAmount == 0 ? eligibleTapAmount : _tapAmount;
190 require(tapAmount >= 1e18, "tOB: Too low");
191 // Get TAP valuation
192 uint256 otcAmountInUSD = tapAmount * epochTAPValuation; // Divided by TAP decimals
193 // Get payment token valuation
194 (, uint256 paymentTokenValuation) = paymentTokenOracle.oracle.peek(
195 paymentTokenOracle.oracleData
196 );
197 // Get payment token amount
198 paymentTokenAmount = _getDiscountedPaymentAmount(
199 otcAmountInUSD,
200 paymentTokenValuation,
201 oTAPPosition.discount,
202 _paymentToken.decimals()
203 );
204 }
205
206 // ===========
207 // WRITE
208 // ===========
209
210 /// @notice Participate in twAMl voting and mint an oTAP position
211 /// @param _tOLPTokenID The tokenId of the tOLP position
212 function participate(
213 uint256 _tOLPTokenID
214 ) external returns (uint256 oTAPTokenID) {
215 // Compute option parameters
216 (bool isPositionActive, LockPosition memory lock) = tOLP.getLock(
217 _tOLPTokenID
218 );
219 require(isPositionActive, "tOB: Position is not active");
220 require(lock.lockDuration >= EPOCH_DURATION, "tOB: Duration too short");
221
222 TWAMLPool memory pool = twAML[lock.sglAssetID];
223
224 require(
225 tOLP.isApprovedOrOwner(msg.sender, _tOLPTokenID),
226 "tOB: Not approved or owner"
227 );
228
229 // Transfer tOLP position to this contract
230 tOLP.transferFrom(msg.sender, address(this), _tOLPTokenID);
231
232 uint256 magnitude = computeMagnitude(
233 uint256(lock.lockDuration),
234 pool.cumulative
235 );
236 bool divergenceForce;
237 uint256 target = computeTarget(dMIN, dMAX, magnitude, pool.cumulative);
238
239 // Participate in twAMl voting
240 bool hasVotingPower = lock.amount >=
241 computeMinWeight(pool.totalDeposited, MIN_WEIGHT_FACTOR);
242 if (hasVotingPower) {
243 pool.totalParticipants++; // Save participation
244 pool.averageMagnitude =
245 (pool.averageMagnitude + magnitude) /
246 pool.totalParticipants; // compute new average magnitude
247
248 // Compute and save new cumulative
249 divergenceForce = lock.lockDuration > pool.cumulative;
250 if (divergenceForce) {
251 pool.cumulative += pool.averageMagnitude;
252 } else {
253 if (pool.cumulative > pool.averageMagnitude) {
254 pool.cumulative -= pool.averageMagnitude;
255 } else {
256 pool.cumulative = 0;
257 }
258 }
259
260 // Save new weight
261 pool.totalDeposited += lock.amount;
262
263 twAML[lock.sglAssetID] = pool; // Save twAML participation
264 emit AMLDivergence(
265 epoch,
266 pool.cumulative,
267 pool.averageMagnitude,
268 pool.totalParticipants
269 ); // Register new voting power event
270 }
271 // Save twAML participation
272 participants[_tOLPTokenID] = Participation(
273 hasVotingPower,
274 divergenceForce,
275 pool.averageMagnitude
276 );
277
278 // Mint oTAP position
279 oTAPTokenID = oTAP.mint(
280 msg.sender,
281 lock.lockTime + lock.lockDuration,
282 uint128(target),
283 _tOLPTokenID
284 );
285 emit Participate(
286 epoch,
287 lock.sglAssetID,
288 pool.totalDeposited,
289 lock,
290 target
291 );
292 }
293
294 /// @notice Exit a twAML participation and delete the voting power if existing
295 /// @param _oTAPTokenID The tokenId of the oTAP position
296 function exitPosition(uint256 _oTAPTokenID) external {
297 require(oTAP.exists(_oTAPTokenID), "tOB: oTAP position does not exist");
298
299 // Load data
300 (, TapOption memory oTAPPosition) = oTAP.attributes(_oTAPTokenID);
301 (, LockPosition memory lock) = tOLP.getLock(oTAPPosition.tOLP);
302
303 require(
304 block.timestamp >= lock.lockTime + lock.lockDuration,
305 "tOB: Lock not expired"
306 );
307
308 Participation memory participation = participants[oTAPPosition.tOLP];
309
310 // Remove participation
311 if (participation.hasVotingPower) {
312 TWAMLPool memory pool = twAML[lock.sglAssetID];
313
314 if (participation.divergenceForce) {
315 if (pool.cumulative > pool.averageMagnitude) {
316 pool.cumulative -= pool.averageMagnitude;
317 } else {
318 pool.cumulative = 0;
319 }
320 } else {
321 pool.cumulative += pool.averageMagnitude;
322 }
323
324 pool.totalDeposited -= lock.amount;
325 pool.totalParticipants--;
326
327 twAML[lock.sglAssetID] = pool; // Save twAML exit
328 emit AMLDivergence(
329 epoch,
330 pool.cumulative,
331 pool.averageMagnitude,
332 pool.totalParticipants
333 ); // Register new voting power event
334 }
335
336 // Delete participation and burn oTAP position
337 address otapOwner = oTAP.ownerOf(_oTAPTokenID);
338 delete participants[oTAPPosition.tOLP];
339 oTAP.burn(_oTAPTokenID);
340
341 // Transfer position back to oTAP owner
342 tOLP.transferFrom(address(this), otapOwner, oTAPPosition.tOLP);
343
344 emit ExitPosition(epoch, oTAPPosition.tOLP, lock.amount);
345 }
346
347 /// @notice Exercise an oTAP position
348 /// @param _oTAPTokenID tokenId of the oTAP position, position must be active
349 /// @param _paymentToken Address of the payment token to use, must be whitelisted
350 /// @param _tapAmount Amount of TAP to exercise. If 0, the full amount is exercised
351 function exerciseOption(
352 uint256 _oTAPTokenID,
353 ERC20 _paymentToken,
354 uint256 _tapAmount
355 ) external {
356 // Load data
357 (, TapOption memory oTAPPosition) = oTAP.attributes(_oTAPTokenID);
358 (bool isPositionActive, LockPosition memory tOLPLockPosition) = tOLP
359 .getLock(oTAPPosition.tOLP);
360
361 uint256 cachedEpoch = epoch;
362
363 PaymentTokenOracle memory paymentTokenOracle = paymentTokens[
364 _paymentToken
365 ];
366
367 // Check requirements
368 require(
369 paymentTokenOracle.oracle != IOracle(address(0)),
370 "tOB: Payment token not supported"
371 );
372 require(
373 oTAP.isApprovedOrOwner(msg.sender, _oTAPTokenID),
374 "tOB: Not approved or owner"
375 );
376 require(isPositionActive, "tOB: Option expired");
377
378 // Get eligible OTC amount
379 uint256 gaugeTotalForEpoch = singularityGauges[cachedEpoch][
380 tOLPLockPosition.sglAssetID
381 ];
382 uint256 eligibleTapAmount = muldiv(
383 tOLPLockPosition.amount,
384 gaugeTotalForEpoch,
385 tOLP.getTotalPoolDeposited(tOLPLockPosition.sglAssetID)
386 );
387 eligibleTapAmount -= oTAPCalls[_oTAPTokenID][cachedEpoch]; // Subtract already exercised amount
388 require(eligibleTapAmount >= _tapAmount, "tOB: Too high");
389
390 uint256 chosenAmount = _tapAmount == 0 ? eligibleTapAmount : _tapAmount;
391 require(chosenAmount >= 1e18, "tOB: Too low");
392 oTAPCalls[_oTAPTokenID][cachedEpoch] += chosenAmount; // Adds up exercised amount to current epoch
393
394 // Finalize the deal
395 _processOTCDeal(
396 _paymentToken,
397 paymentTokenOracle,
398 chosenAmount,
399 oTAPPosition.discount
400 );
401
402 emit ExerciseOption(
403 cachedEpoch,
404 msg.sender,
405 _paymentToken,
406 _oTAPTokenID,
407 chosenAmount
408 );
409 }
410
411 /// @notice Start a new epoch, extract TAP from the TapOFT contract,
412 /// emit it to the active singularities and get the price of TAP for the epoch.
413 function newEpoch() external {
414 require(
415 block.timestamp >= lastEpochUpdate + EPOCH_DURATION,
416 "tOB: too soon"
417 );
418 uint256[] memory singularities = tOLP.getSingularities();
419 require(singularities.length > 0, "tOB: No active singularities");
420
421 // Update epoch info
422 lastEpochUpdate = block.timestamp;
423 epoch++;
424
425 // Extract TAP
426 uint256 epochTAP = tapOFT.emitForWeek();
427 _emitToGauges(epochTAP);
428
429 // Get epoch TAP valuation
430 (, epochTAPValuation) = tapOracle.get(tapOracleData);
431 emit NewEpoch(epoch, epochTAP, epochTAPValuation);
432 }
433
434 /// @notice Claim the Broker role of the oTAP contract
435 function oTAPBrokerClaim() external {
436 oTAP.brokerClaim();
437 }
438
439 // =========
440 // OWNER
441 // =========
442
443 /// @notice Set the TapOFT Oracle address and data
444 /// @param _tapOracle The new TapOFT Oracle address
445 /// @param _tapOracleData The new TapOFT Oracle data
446 function setTapOracle(
447 IOracle _tapOracle,
448 bytes calldata _tapOracleData
449 ) external onlyOwner {
450 tapOracle = _tapOracle;
451 tapOracleData = _tapOracleData;
452
453 emit SetTapOracle(_tapOracle, _tapOracleData);
454 }
455
456 /// @notice Activate or deactivate a payment token
457 /// @dev set the oracle to address(0) to deactivate, expect the same decimal precision as TAP oracle
458 function setPaymentToken(
459 ERC20 _paymentToken,
460 IOracle _oracle,
461 bytes calldata _oracleData
462 ) external onlyOwner {
463 paymentTokens[_paymentToken].oracle = _oracle;
464 paymentTokens[_paymentToken].oracleData = _oracleData;
465
466 emit SetPaymentToken(_paymentToken, _oracle, _oracleData);
467 }
468
469 /// @notice Set the payment token beneficiary
470 /// @param _paymentTokenBeneficiary The new payment token beneficiary
471 function setPaymentTokenBeneficiary(
472 address _paymentTokenBeneficiary
473 ) external onlyOwner {
474 paymentTokenBeneficiary = _paymentTokenBeneficiary;
475 }
476
477 /// @notice Collect the payment tokens from the OTC deals
478 /// @param _paymentTokens The payment tokens to collect
479 function collectPaymentTokens(
480 address[] calldata _paymentTokens
481 ) external onlyOwner {
482 require(
483 paymentTokenBeneficiary != address(0),
484 "tOB: Payment token beneficiary not set"
485 );
486 uint256 len = _paymentTokens.length;
487
488 unchecked {
489 for (uint256 i = 0; i < len; ++i) {
490 ERC20 paymentToken = ERC20(_paymentTokens[i]);
491 paymentToken.transfer(
492 paymentTokenBeneficiary,
493 paymentToken.balanceOf(address(this))
494 );
495 }
496 }
497 }
498
499 // ============
500 // INTERNAL
501 // ============
502
503 /// @notice Process the OTC deal, transfer the payment token to the broker and the TAP amount to the user
504 /// @param _paymentToken The payment token
505 /// @param _paymentTokenOracle The oracle of the payment token
506 /// @param tapAmount The amount of TAP that the user has to receive
507 /// @param discount The discount that the user has to apply to the OTC deal
508 function _processOTCDeal(
509 ERC20 _paymentToken,
510 PaymentTokenOracle memory _paymentTokenOracle,
511 uint256 tapAmount,
512 uint256 discount
513 ) internal {
514 // Get TAP valuation
515 uint256 otcAmountInUSD = tapAmount * epochTAPValuation;
516
517 // Get payment token valuation
518 (, uint256 paymentTokenValuation) = _paymentTokenOracle.oracle.get(
519 _paymentTokenOracle.oracleData
520 );
521
522 // Calculate payment amount and initiate the transfers
523 uint256 discountedPaymentAmount = _getDiscountedPaymentAmount(
524 otcAmountInUSD,
525 paymentTokenValuation,
526 discount,
527 _paymentToken.decimals()
528 );
529
530 _paymentToken.transferFrom(
531 msg.sender,
532 address(this),
533 discountedPaymentAmount
534 );
535 tapOFT.extractTAP(msg.sender, tapAmount);
536 }
537
538 /// @notice Computes the discounted payment amount for a given OTC amount in USD
539 /// @param _otcAmountInUSD The OTC amount in USD, 18 decimals
540 /// @param _paymentTokenValuation The payment token valuation in USD, 18 decimals
541 /// @param _discount The discount in BPS
542 /// @param _paymentTokenDecimals The payment token decimals
543 /// @return paymentAmount The discounted payment amount
544 function _getDiscountedPaymentAmount(
545 uint256 _otcAmountInUSD,
546 uint256 _paymentTokenValuation,
547 uint256 _discount,
548 uint256 _paymentTokenDecimals
549 ) internal pure returns (uint256 paymentAmount) {
550 // Calculate payment amount
551 uint256 rawPaymentAmount = _otcAmountInUSD / _paymentTokenValuation;
552 paymentAmount =
553 rawPaymentAmount -
554 muldiv(rawPaymentAmount, _discount, 100e4); // 1e4 is discount decimals, 100 is discount percentage
555 paymentAmount = paymentAmount / (10 ** (18 - _paymentTokenDecimals));
556 }
557
558 /// @notice Emit TAP to the gauges equitably
559 function _emitToGauges(uint256 _epochTAP) internal {
560 SingularityPool[] memory sglPools = tOLP.getSingularityPools();
561 uint256 totalWeights = tOLP.totalSingularityPoolWeights();
562
563 uint256 len = sglPools.length;
564 unchecked {
565 for (uint256 i = 0; i < len; ++i) {
566 uint256 currentPoolWeight = sglPools[i].poolWeight;
567 uint256 quotaPerSingularity = muldiv(
568 currentPoolWeight,
569 _epochTAP,
570 totalWeights
571 );
572 singularityGauges[epoch][
573 sglPools[i].sglAssetID
574 ] = quotaPerSingularity;
575 }
576 }
577 }
578: }
File: contracts/options/TapiocaOptionLiquidityProvision.sol
48 contract TapiocaOptionLiquidityProvision is
49 ERC721,
50 ERC721Permit,
51 BaseBoringBatchable,
52 Pausable,
53 BoringOwnable
54 {
55 uint256 public tokenCounter; // Counter for token IDs
56 mapping(uint256 => LockPosition) public lockPositions; // TokenID => LockPosition
57
58 IYieldBox public immutable yieldBox;
59
60 // Singularity market address => SingularityPool (YieldBox Asset ID is 0 if not active)
61 mapping(IERC20 => SingularityPool) public activeSingularities;
62 mapping(uint256 => IERC20) public sglAssetIDToAddress; // Singularity market YieldBox asset ID => Singularity market address
63 uint256[] public singularities; // Array of active singularity asset IDs
64
65 uint256 public totalSingularityPoolWeights; // Total weight of all active singularity pools
66
67 constructor(
68 address _yieldBox,
69 address _owner
70 )
71 ERC721("TapiocaOptionLiquidityProvision", "tOLP")
72 ERC721Permit("TapiocaOptionLiquidityProvision")
73 {
74 yieldBox = IYieldBox(_yieldBox);
75 owner = _owner;
76 }
77
78 // ==========
79 // EVENTS
80 // ==========
81 event Mint(
82 address indexed to,
83 uint128 indexed sglAssetID,
84 LockPosition lockPosition
85 );
86 event Burn(
87 address indexed to,
88 uint128 indexed sglAssetID,
89 LockPosition lockPosition
90 );
91 event UpdateTotalSingularityPoolWeights(
92 uint256 totalSingularityPoolWeights
93 );
94 event SetSGLPoolWeight(address sgl, uint256 poolWeight);
95 event RegisterSingularity(address sgl, uint256 assetID);
96 event UnregisterSingularity(address sgl, uint256 assetID);
97
98 // ===============
99 // MODIFIERS
100 // ===============
101 modifier updateTotalSGLPoolWeights() {
102 _;
103 totalSingularityPoolWeights = _computeSGLPoolWeights();
104 emit UpdateTotalSingularityPoolWeights(totalSingularityPoolWeights);
105 }
106
107 // =========
108 // READ
109 // =========
110 /// @notice Returns the lock position of a given tOLP NFT and if it's active
111 /// @param _tokenId tOLP NFT ID
112 function getLock(
113 uint256 _tokenId
114 ) external view returns (bool, LockPosition memory) {
115 LockPosition memory lockPosition = lockPositions[_tokenId];
116
117 return (_isPositionActive(_tokenId), lockPosition);
118 }
119
120 /// @notice Returns the active singularity YieldBox ID markets
121 function getSingularities() external view returns (uint256[] memory) {
122 return singularities;
123 }
124
125 /// @notice Returns the active singularity pool data
126 function getSingularityPools()
127 external
128 view
129 returns (SingularityPool[] memory)
130 {
131 uint256[] memory _singularities = singularities;
132 uint256 len = _singularities.length;
133
134 SingularityPool[] memory pools = new SingularityPool[](len);
135 unchecked {
136 for (uint256 i = 0; i < len; ++i) {
137 pools[i] = activeSingularities[
138 sglAssetIDToAddress[_singularities[i]]
139 ];
140 }
141 }
142 return pools;
143 }
144
145 /// @notice Returns the total amount of locked tokens for a given singularity market
146 function getTotalPoolDeposited(
147 uint256 _sglAssetId
148 ) external view returns (uint256) {
149 return
150 activeSingularities[sglAssetIDToAddress[_sglAssetId]]
151 .totalDeposited;
152 }
153
154 function isApprovedOrOwner(
155 address _spender,
156 uint256 _tokenId
157 ) external view returns (bool) {
158 return _isApprovedOrOwner(_spender, _tokenId);
159 }
160
161 // ==========
162 // WRITE
163 // ==========
164
165 /// @notice Locks tOLR tokens for a given duration
166 /// @param _to Address to mint the tOLP NFT to
167 /// @param _singularity Singularity market address
168 /// @param _lockDuration Duration of the lock
169 /// @param _amount Amount of tOLR tokens to lock
170 /// @return tokenId The ID of the minted NFT
171 function lock(
172 address _to,
173 IERC20 _singularity,
174 uint128 _lockDuration,
175 uint128 _amount
176 ) external returns (uint256 tokenId) {
177 require(_lockDuration > 0, "tOLP: lock duration must be > 0");
178 require(_amount > 0, "tOLP: amount must be > 0");
179
180 uint256 sglAssetID = activeSingularities[_singularity].sglAssetID;
181 require(sglAssetID > 0, "tOLP: singularity not active");
182
183 // Transfer the Singularity position to this contract
184 uint256 sharesIn = yieldBox.toShare(sglAssetID, _amount, false);
185
186 yieldBox.transfer(msg.sender, address(this), sglAssetID, sharesIn);
187 activeSingularities[_singularity].totalDeposited += _amount;
188
189 // Mint the tOLP NFT position
190 tokenId = ++tokenCounter;
191 _safeMint(_to, tokenId);
192
193 // Create the lock position
194 LockPosition storage lockPosition = lockPositions[tokenId];
195 lockPosition.lockTime = uint128(block.timestamp);
196 lockPosition.sglAssetID = uint128(sglAssetID);
197 lockPosition.lockDuration = _lockDuration;
198 lockPosition.amount = _amount;
199
200 emit Mint(_to, uint128(sglAssetID), lockPosition);
201 }
202
203 /// @notice Unlocks tOLP tokens
204 /// @param _tokenId ID of the position to unlock
205 /// @param _singularity Singularity market address
206 /// @param _to Address to send the tokens to
207 function unlock(
208 uint256 _tokenId,
209 IERC20 _singularity,
210 address _to
211 ) external returns (uint256 sharesOut) {
212 require(_exists(_tokenId), "tOLP: Expired position");
213
214 LockPosition memory lockPosition = lockPositions[_tokenId];
215 require(
216 block.timestamp >=
217 lockPosition.lockTime + lockPosition.lockDuration,
218 "tOLP: Lock not expired"
219 );
220 require(
221 activeSingularities[_singularity].sglAssetID ==
222 lockPosition.sglAssetID,
223 "tOLP: Invalid singularity"
224 );
225
226 require(
227 _isApprovedOrOwner(msg.sender, _tokenId),
228 "tOLP: not owner nor approved"
229 );
230
231 _burn(_tokenId);
232 delete lockPositions[_tokenId];
233
234 // Transfer the tOLR tokens back to the owner
235 sharesOut = yieldBox.toShare(
236 lockPosition.sglAssetID,
237 lockPosition.amount,
238 false
239 );
240
241 yieldBox.transfer(
242 address(this),
243 _to,
244 lockPosition.sglAssetID,
245 sharesOut
246 );
247 activeSingularities[_singularity].totalDeposited -= lockPosition.amount;
248
249 emit Burn(_to, lockPosition.sglAssetID, lockPosition);
250 }
251
252 // =========
253 // OWNER
254 // =========
255
256 /// @notice Sets the pool weight of a given singularity market
257 /// @param singularity Singularity market address
258 /// @param weight Weight of the pool
259 function setSGLPoolWEight(
260 IERC20 singularity,
261 uint256 weight
262 ) external onlyOwner updateTotalSGLPoolWeights {
263 require(
264 activeSingularities[singularity].sglAssetID > 0,
265 "tOLP: not registered"
266 );
267 activeSingularities[singularity].poolWeight = weight;
268
269 emit SetSGLPoolWeight(address(singularity), weight);
270 }
271
272 /// @notice Registers a new singularity market
273 /// @param singularity Singularity market address
274 /// @param assetID YieldBox asset ID of the singularity market
275 /// @param weight Weight of the pool
276 function registerSingularity(
277 IERC20 singularity,
278 uint256 assetID,
279 uint256 weight
280 ) external onlyOwner updateTotalSGLPoolWeights {
281 require(assetID > 0, "tOLP: invalid asset ID");
282 require(
283 activeSingularities[singularity].sglAssetID == 0,
284 "tOLP: already registered"
285 );
286
287 activeSingularities[singularity].sglAssetID = assetID;
288 activeSingularities[singularity].poolWeight = weight > 0 ? weight : 1;
289 sglAssetIDToAddress[assetID] = singularity;
290 singularities.push(assetID);
291
292 emit RegisterSingularity(address(singularity), assetID);
293 }
294
295 /// @notice Un-registers a singularity market
296 /// @param singularity Singularity market address
297 function unregisterSingularity(
298 IERC20 singularity
299 ) external onlyOwner updateTotalSGLPoolWeights {
300 uint256 sglAssetID = activeSingularities[singularity].sglAssetID;
301 require(sglAssetID > 0, "tOLP: not registered");
302
303 unchecked {
304 uint256[] memory _singularities = singularities;
305 uint256 sglLength = _singularities.length;
306 uint256 sglLastIndex = sglLength - 1;
307
308 for (uint256 i = 0; i < sglLength; i++) {
309 // If last element, just pop
310 if (i == sglLastIndex) {
311 delete activeSingularities[singularity];
312 delete sglAssetIDToAddress[sglAssetID];
313 singularities.pop();
314 } else if (
315 _singularities[i] == sglAssetID && i < sglLastIndex
316 ) {
317 // If in the middle, copy last element on deleted element, then pop
318 delete activeSingularities[singularity];
319 delete sglAssetIDToAddress[sglAssetID];
320
321 singularities[i] = _singularities[sglLastIndex];
322 singularities.pop();
323 break;
324 }
325 }
326 }
327
328 emit UnregisterSingularity(address(singularity), sglAssetID);
329 }
330
331 // =========
332 // INTERNAL
333 // =========
334
335 /// @notice Compute the total pool weight of all active singularity markets
336 function _computeSGLPoolWeights() internal view returns (uint256) {
337 uint256 total;
338 uint256 len = singularities.length;
339 for (uint256 i = 0; i < len; i++) {
340 total += activeSingularities[sglAssetIDToAddress[singularities[i]]]
341 .poolWeight;
342 }
343
344 return total;
345 }
346
347 /// @notice Checks if the lock position is still active
348 function _isPositionActive(uint256 tokenId) internal view returns (bool) {
349 LockPosition memory lockPosition = lockPositions[tokenId];
350
351 return
352 (lockPosition.lockTime + lockPosition.lockDuration) >=
353 block.timestamp;
354 }
355
356 /// @notice ERC1155 compliance
357 function onERC1155Received(
358 address,
359 address,
360 uint256,
361 uint256,
362 bytes calldata
363 ) external pure returns (bytes4) {
364 return
365 bytes4(
366 keccak256(
367 "onERC1155Received(address,address,uint256,uint256,bytes)"
368 )
369 );
370 }
371: }
File: contracts/tokens/BaseTapOFT.sol
31 abstract contract BaseTapOFT is OFTV2 {
32 using ExcessivelySafeCall for address;
33 using BytesLib for bytes;
34
35 TwTAP public twTap;
36
37 uint16 internal constant PT_LOCK_TWTAP = 870;
38 uint16 internal constant PT_UNLOCK_TWTAP = 871;
39 uint16 internal constant PT_CLAIM_REWARDS = 872;
40
41 event CallFailedStr(uint16 _srcChainId, bytes _payload, string _reason);
42 event CallFailedBytes(uint16 _srcChainId, bytes _payload, bytes _reason);
43
44 constructor(
45 string memory _name,
46 string memory _symbol,
47 uint8 _sharedDec,
48 address _lzEndpoint
49 ) OFTV2(_name, _symbol, _sharedDec, _lzEndpoint) {}
50
51 //---LZ---
52 function _nonblockingLzReceive(
53 uint16 _srcChainId,
54 bytes memory _srcAddress,
55 uint64 _nonce,
56 bytes memory _payload
57 ) internal virtual override {
58 uint256 packetType = _payload.toUint256(0);
59
60 if (packetType == PT_LOCK_TWTAP) {
61 _lockTwTapPosition(_srcChainId, _payload);
62 } else if (packetType == PT_UNLOCK_TWTAP) {
63 _unlockTwTapPosition(_srcChainId, _payload);
64 } else if (packetType == PT_CLAIM_REWARDS) {
65 _claimRewards(_srcChainId, _payload);
66 } else {
67 packetType = _payload.toUint8(0);
68 if (packetType == PT_SEND) {
69 _sendAck(_srcChainId, _srcAddress, _nonce, _payload);
70 } else if (packetType == PT_SEND_AND_CALL) {
71 _sendAndCallAck(_srcChainId, _srcAddress, _nonce, _payload);
72 } else {
73 revert("TOFT_packet");
74 }
75 }
76 }
77
78 /// --------------------------
79 /// ------- LOCK TWTAP -------
80 /// --------------------------
81
82 /// @notice Opens a twTAP by participating in twAML.
83 /// @param to The address to add the twTAP position to.
84 /// @param amount The amount to add.
85 /// @param lzDstChainId The destination chain id.
86 /// @param zroPaymentAddress The address to send the ZRO payment to.
87 /// @param adapterParams The adapter params.
88 function lockTwTapPosition(
89 address to,
90 uint256 amount, // Amount to add
91 uint256 duration, // Duration of the position.
92 uint16 lzDstChainId,
93 address zroPaymentAddress,
94 bytes calldata adapterParams
95 ) external payable {
96 bytes memory lzPayload = abi.encode(
97 PT_LOCK_TWTAP, // packet type
98 msg.sender,
99 to,
100 amount,
101 duration
102 );
103
104 require(duration > 0, "TapOFT: Small duration");
105 bytes32 senderBytes = LzLib.addressToBytes32(msg.sender);
106 _debitFrom(msg.sender, lzEndpoint.getChainId(), senderBytes, amount);
107
108 _lzSend(
109 lzDstChainId,
110 lzPayload,
111 payable(msg.sender),
112 zroPaymentAddress,
113 adapterParams,
114 msg.value
115 );
116
117 emit SendToChain(
118 lzDstChainId,
119 msg.sender,
120 LzLib.addressToBytes32(to),
121 0
122 );
123 }
124
125 function _lockTwTapPosition(
126 uint16 _srcChainId,
127 bytes memory _payload
128 ) internal virtual {
129 (, , address to, uint256 amount, uint duration) = abi.decode(
130 _payload,
131 (uint16, address, address, uint256, uint256)
132 );
133
134 _creditTo(_srcChainId, address(this), amount);
135 approve(address(twTap), amount);
136
137 // We participate and mint with TapOFT as a receiver
138 try twTap.participate(to, amount, duration) {} catch Error(
139 string memory _reason
140 ) {
141 // If the process fails, we send back the funds to the user
142 // We send back the funds to the user
143 emit CallFailedStr(_srcChainId, _payload, _reason);
144 _transferFrom(address(this), to, amount);
145 } catch (bytes memory _reason) {
146 emit CallFailedBytes(_srcChainId, _payload, _reason);
147 _transferFrom(address(this), to, amount);
148 }
149 }
150
151 /// ------------------------------
152 /// ------- CLAIM REWARDS --------
153 /// ------------------------------
154
155 /// @notice Claim rewards from a twTAP position.
156 /// @param to The address to add the twTAP position to.
157 /// @param tokenID Token ID of the twTAP position.
158 /// @param rewardTokens The address of the reward tokens.
159 /// @param lzDstChainId The destination chain id.
160 /// @param zroPaymentAddress The address to send the ZRO payment to.
161 /// @param adapterParams The adapter params.
162 /// @param rewardClaimSendParams The adapter params to send back the TAP token.
163 function claimRewards(
164 address to,
165 uint256 tokenID,
166 address[] memory rewardTokens,
167 uint16 lzDstChainId,
168 address zroPaymentAddress,
169 bytes calldata adapterParams,
170 IRewardClaimSendFromParams[] calldata rewardClaimSendParams
171 ) external payable {
172 bytes memory lzPayload = abi.encode(
173 PT_CLAIM_REWARDS, // packet type
174 msg.sender,
175 to,
176 tokenID,
177 rewardTokens,
178 rewardClaimSendParams
179 );
180
181 _lzSend(
182 lzDstChainId,
183 lzPayload,
184 payable(msg.sender),
185 zroPaymentAddress,
186 adapterParams,
187 msg.value
188 );
189
190 emit SendToChain(
191 lzDstChainId,
192 msg.sender,
193 LzLib.addressToBytes32(to),
194 0
195 );
196 }
197
198 function _claimRewards(
199 uint16 _srcChainId,
200 bytes memory _payload
201 ) internal virtual {
202 (
203 ,
204 ,
205 address to,
206 uint256 tokenID,
207 IERC20[] memory rewardTokens,
208 IRewardClaimSendFromParams[] memory rewardClaimSendParams
209 ) = abi.decode(
210 _payload,
211 (
212 uint16,
213 address,
214 address,
215 uint256,
216 IERC20[],
217 IRewardClaimSendFromParams[]
218 )
219 );
220
221 // Only the owner can unlock
222 require(twTap.ownerOf(tokenID) == to, "TapOFT: Not owner");
223
224 // Exit and receive tokens to this contract
225 try twTap.claimAndSendRewards(tokenID, rewardTokens) {
226 // Transfer them to the user
227 uint256 len = rewardTokens.length;
228 for (uint i = 0; i < len; ) {
229 ISendFrom(address(rewardTokens[i])).sendFrom{
230 value: rewardClaimSendParams[i].ethValue
231 }(
232 address(this),
233 _srcChainId,
234 LzLib.addressToBytes32(to),
235 IERC20(rewardTokens[i]).balanceOf(address(this)),
236 rewardClaimSendParams[i].callParams
237 );
238 ++i;
239 }
240 } catch Error(string memory _reason) {
241 emit CallFailedStr(_srcChainId, _payload, _reason);
242 } catch (bytes memory _reason) {
243 emit CallFailedBytes(_srcChainId, _payload, _reason);
244 }
245 }
246
247 /// --------------------------
248 /// ------- UNLOCK TWTAP -------
249 /// --------------------------
250
251 /// @notice Exit a twTAP by participating in twAML.
252 /// @param to The address to add the twTAP position to.
253 /// @param tokenID Token ID of the twTAP position.
254 /// @param lzDstChainId The destination chain id.
255 /// @param zroPaymentAddress The address to send the ZRO payment to.
256 /// @param adapterParams The adapter params.
257 /// @param twTapSendBackAdapterParams The adapter params to send back the TAP token.
258 function unlockTwTapPosition(
259 address to,
260 uint256 tokenID,
261 uint16 lzDstChainId,
262 address zroPaymentAddress,
263 bytes calldata adapterParams,
264 LzCallParams calldata twTapSendBackAdapterParams
265 ) external payable {
266 bytes memory lzPayload = abi.encode(
267 PT_UNLOCK_TWTAP, // packet type
268 msg.sender,
269 to,
270 tokenID,
271 twTapSendBackAdapterParams
272 );
273
274 _lzSend(
275 lzDstChainId,
276 lzPayload,
277 payable(msg.sender),
278 zroPaymentAddress,
279 adapterParams,
280 msg.value
281 );
282
283 emit SendToChain(
284 lzDstChainId,
285 msg.sender,
286 LzLib.addressToBytes32(to),
287 0
288 );
289 }
290
291 function _unlockTwTapPosition(
292 uint16 _srcChainId,
293 bytes memory _payload
294 ) internal virtual {
295 (
296 ,
297 ,
298 address to,
299 uint256 tokenID,
300 LzCallParams memory twTapSendBackAdapterParams
301 ) = abi.decode(
302 _payload,
303 (uint16, address, address, uint256, LzCallParams)
304 );
305
306 // Only the owner can unlock
307 require(twTap.ownerOf(tokenID) == to, "TapOFT: Not owner");
308
309 // Exit and receive tokens to this contract
310 try twTap.exitPositionAndSendTap(tokenID) returns (uint256 _amount) {
311 // Transfer them to the user
312 this.sendFrom{value: address(this).balance}(
313 address(this),
314 _srcChainId,
315 LzLib.addressToBytes32(to),
316 _amount,
317 twTapSendBackAdapterParams
318 );
319 } catch Error(string memory _reason) {
320 emit CallFailedStr(_srcChainId, _payload, _reason);
321 } catch (bytes memory _reason) {
322 emit CallFailedBytes(_srcChainId, _payload, _reason);
323 }
324 }
325
326 function setTwTap(address _twTap) external onlyOwner {
327 twTap = TwTAP(_twTap);
328 }
329
330 receive() external payable virtual {}
331
332 function _callApproval(ICommonData.IApproval[] memory approvals) private {
333 for (uint256 i = 0; i < approvals.length; ) {
334 try
335 IERC20Permit(approvals[i].target).permit(
336 approvals[i].owner,
337 approvals[i].spender,
338 approvals[i].value,
339 approvals[i].deadline,
340 approvals[i].v,
341 approvals[i].r,
342 approvals[i].s
343 )
344 {} catch Error(string memory reason) {
345 if (!approvals[i].allowFailure) {
346 revert(reason);
347 }
348 }
349
350 unchecked {
351 ++i;
352 }
353 }
354 }
355: }
File: contracts/tokens/LTap.sol
23 contract LTap is BoringOwnable, ERC20Permit {
24 IERC20 tapToken;
25 uint256 public lockedUntil;
26 uint256 public maxLockedUntil;
27
28 /// @notice Creates a new LTAP token
29 /// @dev LTAP tokens are minted by depositing TAP
30 /// @param _tapToken Address of the TAP token
31 /// @param _maxLockedUntil Latest possible end of locking period
32 constructor(
33 IERC20 _tapToken,
34 uint256 _maxLockedUntil
35 ) ERC20("LTAP", "LTAP") ERC20Permit("LTAP") {
36 tapToken = _tapToken;
37 lockedUntil = _maxLockedUntil;
38 maxLockedUntil = _maxLockedUntil;
39 }
40
41 function deposit(uint256 amount) external {
42 tapToken.transferFrom(msg.sender, address(this), amount);
43 _mint(msg.sender, amount);
44 }
45
46 function redeem() external {
47 require(block.timestamp > lockedUntil, "Still locked");
48 uint256 amount = balanceOf(msg.sender);
49 _burn(msg.sender, amount);
50 tapToken.transfer(msg.sender, amount);
51 }
52
53 function setLockedUntil(uint256 _lockedUntil) external onlyOwner {
54 require(_lockedUntil <= maxLockedUntil, "Too late");
55 lockedUntil = _lockedUntil;
56 }
57: }
File: contracts/tokens/TapOFT.sol
26 contract TapOFT is BaseTapOFT, ERC20Permit {
27 // ==========
28 // *DATA*
29 // ==========
30
31 // Allocation:
32 // =========
33 // * DSO: 53,313,405
34 // * DAO: 8m
35 // * Contributors: 15m
36 // * Early supporters: 3,686,595
37 // * Supporters: 12.5m
38 // * LBP: 5m
39 // * Airdrop: 2.5m
40 // == 100M ==
41 uint256 public constant INITIAL_SUPPLY = 46_686_595 * 1e18; // Everything minus DSO
42 uint256 public dso_supply = 53_313_405 * 1e18;
43
44 /// @notice the a parameter used in the emission function;
45 uint256 constant decay_rate = 8800000000000000; // 0.88%
46 uint256 constant DECAY_RATE_DECIMAL = 1e18;
47
48 /// @notice seconds in a week
49 uint256 public constant WEEK = 604800;
50
51 /// @notice starts time for emissions
52 /// @dev initialized in the constructor with block.timestamp
53 uint256 public immutable emissionsStartTime;
54
55 /// @notice returns the amount of emitted TAP for a specific week
56 /// @dev week is computed using (timestamp - emissionStartTime) / WEEK
57 mapping(uint256 => uint256) public emissionForWeek;
58
59 /// @notice returns the amount minted for a specific week
60 /// @dev week is computed using (timestamp - emissionStartTime) / WEEK
61 mapping(uint256 => uint256) public mintedInWeek;
62
63 /// @notice returns the minter address
64 address public minter;
65
66 /// @notice LayerZero governance chain identifier
67 uint256 public governanceChainIdentifier;
68
69 /// @notice returns the pause state of the contract
70 bool public paused;
71
72 // ==========
73 // *EVENTS*
74 // ==========
75 /// @notice event emitted when a new minter is set
76 event MinterUpdated(address indexed _old, address indexed _new);
77 /// @notice event emitted when a new emission is called
78 event Emitted(uint256 week, uint256 amount);
79 /// @notice event emitted when new TAP is minted
80 event Minted(address indexed _by, address indexed _to, uint256 _amount);
81 /// @notice event emitted when new TAP is burned
82 event Burned(address indexed _from, uint256 _amount);
83 /// @notice event emitted when the governance chain identifier is updated
84 event GovernanceChainIdentifierUpdated(uint256 _old, uint256 _new);
85 /// @notice event emitted when pause state is changed
86 event PausedUpdated(bool oldState, bool newState);
87
88 modifier notPaused() {
89 require(!paused, "TAP: paused");
90 _;
91 }
92
93 // ==========
94 // * METHODS *
95 // ==========
96 /// @notice Creates a new TAP OFT type token
97 /// @dev The initial supply of 100M is not minted here as we have the wrap method
98 /// @param _lzEndpoint the layer zero address endpoint deployed on the current chain
99 /// @param _contributors address of the contributors. 15m
100 /// @param _earlySupporters address of early supporters. 3,686,595
101 /// @param _supporters address of supporters. 12.5m
102 /// @param _lbp address of the LBP. 5m
103 /// @param _dao address of the DAO. 8m
104 /// @param _airdrop address of the airdrop contract. 2.5m
105 /// @param _governanceChainId LayerZero governance chain identifier
106 /// @param _conservator address of the conservator/owner
107 constructor(
108 address _lzEndpoint,
109 address _contributors,
110 address _earlySupporters,
111 address _supporters,
112 address _lbp,
113 address _dao,
114 address _airdrop,
115 uint256 _governanceChainId,
116 address _conservator
117 ) BaseTapOFT("TapOFT", "TAP", 8, _lzEndpoint) ERC20Permit("TapOFT") {
118 require(_lzEndpoint != address(0), "LZ endpoint not valid");
119 governanceChainIdentifier = _governanceChainId;
120 if (_getChainId() == governanceChainIdentifier) {
121 _mint(_contributors, 1e18 * 15_000_000);
122 _mint(_earlySupporters, 1e18 * 3_686_595);
123 _mint(_supporters, 1e18 * 12_500_000);
124 _mint(_lbp, 1e18 * 5_000_000);
125 _mint(_dao, 1e18 * 8_000_000);
126 _mint(_airdrop, 1e18 * 2_500_000);
127 require(
128 totalSupply() == INITIAL_SUPPLY,
129 "initial supply not valid"
130 );
131 }
132 emissionsStartTime = block.timestamp;
133
134 transferOwnership(_conservator);
135 }
136
137 ///-- Owner methods --
138 /// @notice sets the governance chain identifier
139 /// @param _identifier LayerZero chain identifier
140 function setGovernanceChainIdentifier(
141 uint256 _identifier
142 ) external onlyOwner {
143 emit GovernanceChainIdentifierUpdated(
144 governanceChainIdentifier,
145 _identifier
146 );
147 governanceChainIdentifier = _identifier;
148 }
149
150 /// @notice updates the pause state of the contract
151 /// @param val the new value
152 function updatePause(bool val) external onlyOwner {
153 require(val != paused, "TAP: same state");
154 emit PausedUpdated(paused, val);
155 paused = val;
156 }
157
158 /// @notice sets a new minter address
159 /// @param _minter the new address
160 function setMinter(address _minter) external onlyOwner {
161 require(_minter != address(0), "address not valid");
162 emit MinterUpdated(minter, _minter);
163 minter = _minter;
164 }
165
166 //-- View methods --
167 /// @notice returns token's decimals
168 function decimals() public pure override returns (uint8) {
169 return 18;
170 }
171
172 /// @notice Returns the current week given a timestamp
173 function timestampToWeek(
174 uint256 timestamp
175 ) external view returns (uint256) {
176 if (timestamp == 0) {
177 timestamp = block.timestamp;
178 }
179 if (timestamp < emissionsStartTime) return 0;
180
181 return _timestampToWeek(timestamp);
182 }
183
184 /// @notice Returns the current week
185 function getCurrentWeek() external view returns (uint256) {
186 return _timestampToWeek(block.timestamp);
187 }
188
189 /// @notice Returns the current week emission
190 function getCurrentWeekEmission() external view returns (uint256) {
191 return emissionForWeek[_timestampToWeek(block.timestamp)];
192 }
193
194 ///-- Write methods --
195 /// @notice Emit the TAP for the current week
196 /// @return the emitted amount
197 function emitForWeek() external notPaused returns (uint256) {
198 require(_getChainId() == governanceChainIdentifier, "chain not valid");
199
200 uint256 week = _timestampToWeek(block.timestamp);
201 if (emissionForWeek[week] > 0) return 0;
202
203 // Update DSO supply from last minted emissions
204 dso_supply -= mintedInWeek[week - 1];
205
206 // Compute unclaimed emission from last week and add it to the current week emission
207 uint256 unclaimed = emissionForWeek[week - 1] - mintedInWeek[week - 1];
208 uint256 emission = uint256(_computeEmission());
209 emission += unclaimed;
210 emissionForWeek[week] = emission;
211
212 emit Emitted(week, emission);
213
214 return emission;
215 }
216
217 /// @notice extracts from the minted TAP
218 /// @param _to Address to send the minted TAP to
219 /// @param _amount TAP amount
220 function extractTAP(address _to, uint256 _amount) external notPaused {
221 require(msg.sender == minter, "unauthorized");
222 require(_amount > 0, "amount not valid");
223
224 uint256 week = _timestampToWeek(block.timestamp);
225 require(emissionForWeek[week] >= _amount, "exceeds allowable amount");
226 _mint(_to, _amount);
227 mintedInWeek[week] += _amount;
228 emit Minted(msg.sender, _to, _amount);
229 }
230
231 /// @notice burns TAP
232 /// @param _amount TAP amount
233 function removeTAP(uint256 _amount) external notPaused {
234 _burn(msg.sender, _amount);
235 emit Burned(msg.sender, _amount);
236 }
237
238 ///-- Internal methods --
239 function _timestampToWeek(
240 uint256 timestamp
241 ) internal view returns (uint256) {
242 return ((timestamp - emissionsStartTime) / WEEK) + 1; // Starts at week 1
243 }
244
245 ///-- Private methods --
246 /// @notice Return the current chain ID.
247 /// @dev Useful for testing.
248 function _getChainId() private view returns (uint256) {
249 return block.chainid;
250 }
251
252 /// @notice returns the available emissions for a given supply
253 function _computeEmission() internal view returns (uint256 result) {
254 result = (dso_supply * decay_rate) / DECAY_RATE_DECIMAL;
255 }
256: }
File: contracts/Swapper/UniswapV3Swapper.sol
28 contract UniswapV3Swapper is BaseSwapper {
29 using SafeERC20 for IERC20;
30
31 // ************ //
32 // *** VARS *** //
33 // ************ //
34 IYieldBox private immutable yieldBox;
35 ISwapRouter public immutable swapRouter;
36 IUniswapV3Factory public immutable factory;
37
38 uint24 public poolFee = 3000;
39
40 // ************** //
41 // *** EVENTS *** //
42 // ************** //
43 event PoolFee(uint256 _old, uint256 _new);
44
45 constructor(
46 IYieldBox _yieldBox,
47 ISwapRouter _swapRouter,
48 IUniswapV3Factory _factory
49 )
50 validAddress(address(_yieldBox))
51 validAddress(address(_swapRouter))
52 validAddress(address(_factory))
53 {
54 yieldBox = _yieldBox;
55 swapRouter = _swapRouter;
56 factory = _factory;
57 }
58
59 /// *** OWNER METHODS ***
60 /// *** ***
61 function setPoolFee(uint24 _newFee) external onlyOwner {
62 emit PoolFee(poolFee, _newFee);
63 poolFee = _newFee;
64 }
65
66 /// *** VIEW METHODS ***
67 /// *** ***
68 /// @notice returns default bytes swap data
69 function getDefaultDexOptions()
70 public
71 view
72 override
73 returns (bytes memory)
74 {
75 return abi.encode(block.timestamp + 1 hours);
76 }
77
78 /// @notice Computes amount out for amount in
79 /// @param swapData operation data
80 function getOutputAmount(
81 SwapData calldata swapData,
82 bytes calldata
83 ) external view override returns (uint256 amountOut) {
84 (address tokenIn, address tokenOut) = _getTokens(
85 swapData.tokensData,
86 yieldBox
87 );
88
89 (uint256 amountIn, ) = _getAmounts(
90 swapData.amountData,
91 swapData.tokensData.tokenInId,
92 swapData.tokensData.tokenOutId,
93 yieldBox
94 );
95
96 address pool = factory.getPool(tokenIn, tokenOut, poolFee);
97 (int24 tick, ) = OracleLibrary.consult(pool, 60);
98
99 amountOut = OracleLibrary.getQuoteAtTick(
100 tick,
101 uint128(amountIn),
102 tokenIn,
103 tokenOut
104 );
105 }
106
107 /// @notice Comutes amount in for amount out
108 function getInputAmount(
109 SwapData calldata swapData,
110 bytes calldata
111 ) external view override returns (uint256 amountIn) {
112 (address tokenIn, address tokenOut) = _getTokens(
113 swapData.tokensData,
114 yieldBox
115 );
116
117 (, uint256 amountOut) = _getAmounts(
118 swapData.amountData,
119 swapData.tokensData.tokenInId,
120 swapData.tokensData.tokenOutId,
121 yieldBox
122 );
123
124 address pool = factory.getPool(tokenIn, tokenOut, poolFee);
125
126 (int24 tick, ) = OracleLibrary.consult(pool, 60);
127 amountIn = OracleLibrary.getQuoteAtTick(
128 tick,
129 uint128(amountOut),
130 tokenOut,
131 tokenIn
132 );
133 }
134
135 /// *** PUBLIC METHODS ***
136 /// *** ***
137 /// @notice swaps amount in
138 /// @param swapData operation data
139 /// @param amountOutMin min amount out to receive
140 /// @param to receiver address
141 /// @param data AMM data
142 function swap(
143 SwapData calldata swapData,
144 uint256 amountOutMin,
145 address to,
146 bytes memory data
147 ) external override returns (uint256 amountOut, uint256 shareOut) {
148 // Get tokens' addresses
149 (address tokenIn, address tokenOut) = _getTokens(
150 swapData.tokensData,
151 yieldBox
152 );
153
154 // Get tokens' amounts
155 (uint256 amountIn, ) = _getAmounts(
156 swapData.amountData,
157 swapData.tokensData.tokenInId,
158 swapData.tokensData.tokenOutId,
159 yieldBox
160 );
161
162 // Retrieve tokens from sender or from YieldBox
163 amountIn = _extractTokens(
164 swapData.yieldBoxData,
165 yieldBox,
166 tokenIn,
167 swapData.tokensData.tokenInId,
168 amountIn,
169 swapData.amountData.shareIn
170 );
171
172 TransferHelper.safeApprove(tokenIn, address(swapRouter), amountIn);
173
174 // Perform the swap operation
175 if (data.length == 0) {
176 data = getDefaultDexOptions();
177 }
178 uint256 deadline = abi.decode(data, (uint256));
179
180 ISwapRouter.ExactInputSingleParams memory params = ISwapRouter
181 .ExactInputSingleParams({
182 tokenIn: tokenIn,
183 tokenOut: tokenOut,
184 fee: poolFee,
185 recipient: swapData.yieldBoxData.depositToYb
186 ? address(this)
187 : to,
188 deadline: deadline,
189 amountIn: amountIn,
190 amountOutMinimum: amountOutMin,
191 sqrtPriceLimitX96: 0
192 });
193
194 // Compute outputs
195 amountOut = swapRouter.exactInputSingle(params);
196 if (swapData.yieldBoxData.depositToYb) {
197 _safeApprove(tokenOut, address(yieldBox), amountOut);
198 (, shareOut) = yieldBox.depositAsset(
199 swapData.tokensData.tokenOutId,
200 address(this),
201 to,
202 amountOut,
203 0
204 );
205 }
206 }
207: }
File: contracts/NativeTokenFactory.sol
21 contract NativeTokenFactory is AssetRegister {
22 using BoringMath for uint256;
23
24 mapping(uint256 => NativeToken) public nativeTokens;
25 mapping(uint256 => address) public owner;
26 mapping(uint256 => address) public pendingOwner;
27
28 event TokenCreated(address indexed creator, string name, string symbol, uint8 decimals, uint256 tokenId);
29 event OwnershipTransferred(uint256 indexed tokenId, address indexed previousOwner, address indexed newOwner);
30
31 // ***************** //
32 // *** MODIFIERS *** //
33 // ***************** //
34
35 /// Modifier to check if the msg.sender is allowed to use funds belonging to the 'from' address.
36 /// If 'from' is msg.sender, it's allowed.
37 /// If 'msg.sender' is an address (an operator) that is approved by 'from', it's allowed.
38 modifier allowed(address _from, uint256 _id) {
39 _requireTransferAllowed(_from, isApprovedForAsset[_from][msg.sender][_id]);
40 _;
41 }
42
43 /// @notice Only allows the `owner` to execute the function.
44 /// @param tokenId The `tokenId` that the sender has to be owner of.
45 modifier onlyOwner(uint256 tokenId) {
46 require(msg.sender == owner[tokenId], "NTF: caller is not the owner");
47 _;
48 }
49
50 /// @notice Transfers ownership to `newOwner`. Either directly or claimable by the new pending owner.
51 /// Can only be invoked by the current `owner`.
52 /// @param tokenId The `tokenId` of the token that ownership whose ownership will be transferred/renounced.
53 /// @param newOwner Address of the new owner.
54 /// @param direct True if `newOwner` should be set immediately. False if `newOwner` needs to use `claimOwnership`.
55 /// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect otherwise.
56 function transferOwnership(uint256 tokenId, address newOwner, bool direct, bool renounce) public onlyOwner(tokenId) {
57 if (direct) {
58 // Checks
59 require(newOwner != address(0) || renounce, "NTF: zero address");
60
61 // Effects
62 emit OwnershipTransferred(tokenId, owner[tokenId], newOwner);
63 owner[tokenId] = newOwner;
64 pendingOwner[tokenId] = address(0);
65 } else {
66 // Effects
67 pendingOwner[tokenId] = newOwner;
68 }
69 }
70
71 /// @notice Needs to be called by `pendingOwner` to claim ownership.
72 /// @param tokenId The `tokenId` of the token that ownership is claimed for.
73 function claimOwnership(uint256 tokenId) public {
74 address _pendingOwner = pendingOwner[tokenId];
75
76 // Checks
77 require(msg.sender == _pendingOwner, "NTF: caller != pending owner");
78
79 // Effects
80 emit OwnershipTransferred(tokenId, owner[tokenId], _pendingOwner);
81 owner[tokenId] = _pendingOwner;
82 pendingOwner[tokenId] = address(0);
83 }
84
85 /// @notice Create a new native token. This will be an ERC1155 token. If later it's needed as an ERC20 token it can
86 /// be wrapped into an ERC20 token. Native support for ERC1155 tokens is growing though.
87 /// @param name The name of the token.
88 /// @param symbol The symbol of the token.
89 /// @param decimals The number of decimals of the token (this is just for display purposes). Should be set to 18 in normal cases.
90 function createToken(string calldata name, string calldata symbol, uint8 decimals, string calldata uri) public returns (uint32 tokenId) {
91 // To keep each Token unique in the AssetRegister, we use the assetId as the tokenId. So for native assets, the tokenId is always equal to the assetId.
92 tokenId = assets.length.to32();
93 _registerAsset(TokenType.Native, address(0), NO_STRATEGY, tokenId);
94 // Initial supply is 0, use owner can mint. For a fixed supply the owner can mint and revoke ownership.
95 // The msg.sender is the initial owner, can be changed after.
96 nativeTokens[tokenId] = NativeToken(name, symbol, decimals, uri);
97 owner[tokenId] = msg.sender;
98
99 emit TokenCreated(msg.sender, name, symbol, decimals, tokenId);
100 emit TransferSingle(msg.sender, address(0), address(0), tokenId, 0);
101 emit OwnershipTransferred(tokenId, address(0), msg.sender);
102 }
103
104 /// @notice The `owner` can mint tokens. If a fixed supply is needed, the `owner` should mint the totalSupply and renounce ownership.
105 /// @param tokenId The token to be minted.
106 /// @param to The account to transfer the minted tokens to.
107 /// @param amount The amount of tokens to mint.
108 /// @dev For security reasons, operators are not allowed to mint. Only the actual owner can do this. Of course the owner can be a contract.
109 function mint(uint256 tokenId, address to, uint256 amount) public onlyOwner(tokenId) {
110 _mint(to, tokenId, amount);
111 }
112
113 /// @notice Burns tokens. Only the holder of tokens can burn them or an approved operator.
114 /// @param tokenId The token to be burned.
115 /// @param amount The amount of tokens to burn.
116 function burn(uint256 tokenId, address from, uint256 amount) public allowed(from, tokenId) {
117 require(assets[tokenId].tokenType == TokenType.Native, "NTF: Not native");
118 _burn(from, tokenId, amount);
119 }
120
121 /// @notice The `owner` can mint tokens. If a fixed supply is needed, the `owner` should mint the totalSupply and renounce ownership.
122 /// @param tokenId The token to be minted.
123 /// @param tos The accounts to transfer the minted tokens to.
124 /// @param amounts The amounts of tokens to mint.
125 /// @dev If the tos array is longer than the amounts array there will be an out of bounds error. If the amounts array is longer, the extra amounts are simply ignored.
126 /// @dev For security reasons, operators are not allowed to mint. Only the actual owner can do this. Of course the owner can be a contract.
127 function batchMint(uint256 tokenId, address[] calldata tos, uint256[] calldata amounts) public onlyOwner(tokenId) {
128 uint256 len = tos.length;
129 for (uint256 i = 0; i < len; i++) {
130 _mint(tos[i], tokenId, amounts[i]);
131 }
132 }
133
134 /// @notice Burns tokens. This is only useful to be used by an operator.
135 /// @param tokenId The token to be burned.
136 /// @param froms The accounts to burn tokens from.
137 /// @param amounts The amounts of tokens to burn.
138 function batchBurn(uint256 tokenId, address[] calldata froms, uint256[] calldata amounts) public {
139 require(assets[tokenId].tokenType == TokenType.Native, "NTF: Not native");
140 uint256 len = froms.length;
141 for (uint256 i = 0; i < len; i++) {
142 _requireTransferAllowed(froms[i], isApprovedForAsset[froms[i]][msg.sender][tokenId]);
143 _burn(froms[i], tokenId, amounts[i]);
144 }
145 }
146: }
Ensure that events follow the best practice of check-effects-interaction, and are emitted before external calls
There are 23 instances of this issue:
see instances
File: contracts/markets/bigBang/BigBang.sol
/// @audit swappers() prior to emission of Liquidated()
629 emit Liquidated(
630 msg.sender,
631 _users,
632 callerShare,
633 feeShare,
634 borrowAmount,
635 collateralShare
636: );
File: contracts/markets/singularity/SGLLiquidation.sol
/// @audit swappers() prior to emission of Liquidated()
360 emit Liquidated(
361 msg.sender,
362 _users,
363 callerShare,
364 feeShare,
365 borrowAmount,
366 collateralShare
367: );
File: contracts/usd0/modules/USDOLeverageModule.sol
/// @audit safeTransfer() prior to emission of ReceiveFromChain()
187: emit ReceiveFromChain(_srcChainId, leverageFor, amount);
File: contracts/usd0/modules/USDOMarketModule.sol
/// @audit safeTransfer() prior to emission of ReceiveFromChain()
188: emit ReceiveFromChain(_srcChainId, to, lendParams.depositAmount);
File: contracts/usd0/modules/USDOOptionsModule.sol
/// @audit safeTransfer() prior to emission of ReceiveFromChain()
199 emit ReceiveFromChain(
200 _srcChainId,
201 optionsData.from,
202 optionsData.paymentTokenAmount
203: );
File: contracts/TapiocaWrapper.sol
/// @audit push() prior to emission of CreateOFT()
177: emit CreateOFT(iOFT, _erc20);
File: contracts/tOFT/mTapiocaOFT.sol
/// @audit safeTransfer() prior to emission of Rebalancing()
151: emit Rebalancing(msg.sender, _amount, _isNative);
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
/// @audit safeTransfer() prior to emission of ReceiveFromChain()
202: emit ReceiveFromChain(_srcChainId, leverageFor, amount);
File: contracts/tOFT/modules/BaseTOFTMarketModule.sol
/// @audit safeTransfer() prior to emission of ReceiveFromChain()
177: emit ReceiveFromChain(_srcChainId, _from, borrowParams.amount);
File: contracts/tOFT/modules/BaseTOFTOptionsModule.sol
/// @audit safeTransfer() prior to emission of ReceiveFromChain()
214 emit ReceiveFromChain(
215 _srcChainId,
216 optionsData.from,
217 optionsData.paymentTokenAmount
218: );
File: contracts/tOFT/modules/BaseTOFTStrategyModule.sol
/// @audit safeTransfer() prior to emission of ReceiveFromChain()
170: emit ReceiveFromChain(_srcChainId, onBehalfOf, amount);
File: contracts/Vesting.sol
/// @audit safeTransfer() prior to emission of Claimed()
120: emit Claimed(msg.sender, _claimable);
File: contracts/aave/AaveStrategy.sol
/// @audit safeTransfer() prior to emission of AmountWithdrawn()
274: emit AmountWithdrawn(to, amount);
File: contracts/balancer/BalancerStrategy.sol
/// @audit safeTransfer() prior to emission of AmountWithdrawn()
215: emit AmountWithdrawn(to, amount);
File: contracts/compound/CompoundStrategy.sol
/// @audit safeTransfer() prior to emission of AmountWithdrawn()
161: emit AmountWithdrawn(to, amount);
File: contracts/convex/ConvexTricryptoStrategy.sol
/// @audit safeTransfer() prior to emission of AmountWithdrawn()
351: emit AmountWithdrawn(to, amount);
File: contracts/curve/TricryptoLPStrategy.sol
/// @audit safeTransfer() prior to emission of AmountWithdrawn()
253: emit AmountWithdrawn(to, amount);
File: contracts/curve/TricryptoNativeStrategy.sol
/// @audit safeTransfer() prior to emission of AmountWithdrawn()
244: emit AmountWithdrawn(to, amount);
File: contracts/lido/LidoEthStrategy.sol
/// @audit safeTransfer() prior to emission of AmountWithdrawn()
166: emit AmountWithdrawn(to, amount);
File: contracts/stargate/StargateStrategy.sol
/// @audit safeTransfer() prior to emission of AmountWithdrawn()
268: emit AmountWithdrawn(to, amount);
File: contracts/yearn/YearnStrategy.sol
/// @audit safeTransfer() prior to emission of AmountWithdrawn()
149: emit AmountWithdrawn(to, amount);
File: contracts/YieldBox.sol
/// @audit safeTransferFrom() prior to emission of Deposited()
157: emit Deposited(msg.sender, from, to, assetId, amount, share, amountOut, shareOut, false);
/// @audit safeTransfer() prior to emission of Deposited()
212: emit Deposited(msg.sender, msg.sender, to, assetId, amount, share, amountOut, shareOut, false);
According to the Solidity style guide function names should be in mixedCase
(lowerCamelCase)
There are 17 instances of this issue:
File: contracts/markets/Market.sol
305 function computeTVLInfo(
306 address user,
307 uint256 _exchangeRate
308 )
309 public
310 view
311 returns (uint256 amountToSolvency, uint256 minTVL, uint256 maxTVL)
312: {
428 function _computeMaxAndMinLTVInAsset(
429 uint256 collateralShare,
430 uint256 _exchangeRate
431: ) internal view returns (uint256 min, uint256 max) {
File: contracts/TapiocaWrapper.sol
75: function tapiocaOFTLength() external view returns (uint256) {
85: function lastTOFT() external view returns (ITapiocaOFT) {
115 function executeTOFT(
116 address _toft,
117 bytes calldata _bytecode,
118 bool _revertOnFailure
119: ) external payable onlyOwner returns (bool success, bytes memory result) {
154 function createTOFT(
155 address _erc20,
156 bytes calldata _bytecode,
157 bytes32 _salt,
158 bool _linked
159: ) external onlyOwner {
183 function _createTOFT(
184 address _erc20,
185 bytes calldata _bytecode,
186 bytes32 _salt,
187 bool _linked
188: ) private returns (address) {
File: contracts/option-airdrop/AirdropBroker.sol
141 function getOTCDealDetails(
142 uint256 _aoTAPTokenID,
143 ERC20 _paymentToken,
144 uint256 _tapAmount
145 )
146 external
147 view
148 returns (
149 uint256 eligibleTapAmount,
150 uint256 paymentTokenAmount,
151 uint256 tapAmount
152 )
153: {
297: function aoTAPBrokerClaim() external {
487 function _processOTCDeal(
488 ERC20 _paymentToken,
489 PaymentTokenOracle memory _paymentTokenOracle,
490 uint256 tapAmount,
491 uint256 discount
492: ) internal {
File: contracts/options/TapiocaOptionBroker.sol
145 function getOTCDealDetails(
146 uint256 _oTAPTokenID,
147 ERC20 _paymentToken,
148 uint256 _tapAmount
149 )
150 external
151 view
152 returns (
153 uint256 eligibleTapAmount,
154 uint256 paymentTokenAmount,
155 uint256 tapAmount
156 )
157: {
435: function oTAPBrokerClaim() external {
508 function _processOTCDeal(
509 ERC20 _paymentToken,
510 PaymentTokenOracle memory _paymentTokenOracle,
511 uint256 tapAmount,
512 uint256 discount
513: ) internal {
File: contracts/options/TapiocaOptionLiquidityProvision.sol
259 function setSGLPoolWEight(
260 IERC20 singularity,
261 uint256 weight
262: ) external onlyOwner updateTotalSGLPoolWeights {
336: function _computeSGLPoolWeights() internal view returns (uint256) {
File: contracts/YieldBox.sol
168 function depositNFTAsset(
169 uint256 assetId,
170 address from,
171 address to
172: ) public allowed(from, assetId) returns (uint256 amountOut, uint256 shareOut) {
196: function depositETHAsset(uint256 assetId, address to, uint256 amount) public payable returns (uint256 amountOut, uint256 shareOut) {
The functions below take in an unbounded array, and make function calls for entries in the array. While the function will revert if it eventually runs out of gas, it may be a nicer user experience to require()
that the length of the array is below some reasonable maximum, so that the user doesn't have to use up a full transaction's gas only to see that the transaction reverts.
There are 29 instances of this issue:
see instances
File: contracts/Penrose.sol
437 for (uint256 i = 0; i < len; ) {
438 require(
439 isSingularityMasterContractRegistered[
440 masterContractOf[mc[i]]
441 ] || isBigBangMasterContractRegistered[masterContractOf[mc[i]]],
442 "Penrose: MC not registered"
443 );
444 (success[i], result[i]) = mc[i].call(data[i]);
445 if (forceSuccess) {
446 require(success[i], _getRevertMsg(result[i]));
447 }
448 ++i;
449: }
492 for (uint256 i = 0; i < length; ) {
493 _depositFeesToYieldBox(markets_[i], swappers_[i], swapData_[i]);
494 ++i;
495: }
550 for (uint256 i = 0; i < _masterContractLength; ) {
551 marketsLength += clonesOfCount(array[i].location);
552
553 ++i;
554: }
564 for (uint256 i = 0; i < _masterContractLength; ) {
565 address mcLocation = array[i].location;
566 clonesOfLength = clonesOfCount(mcLocation);
567
568 // Loop through clones of the current MC.
569 for (uint256 j = 0; j < clonesOfLength; ) {
570 markets[marketIndex] = clonesOf[mcLocation][j];
571 ++marketIndex;
572 ++j;
573 }
574 ++i;
575: }
File: contracts/markets/bigBang/BigBang.sol
215 for (uint256 i = 0; i < calls.length; i++) {
216 (bool success, bytes memory result) = address(this).delegatecall(
217 calls[i]
218 );
219 require(success || !revertOnFail, _getRevertMsg(result));
220 successes[i] = success;
221 results[i] = _getRevertMsg(result);
222: }
666 for (uint256 i = 0; i < users.length; i++) {
667 address user = users[i];
668 if (!_isSolvent(user, _exchangeRate)) {
669 liquidatedCount++;
670 _liquidateUser(
671 user,
672 maxBorrowParts[i],
673 swapper,
674 _exchangeRate,
675 swapData
676 );
677 }
678: }
File: contracts/markets/singularity/SGLLiquidation.sol
107 for (uint256 i = 0; i < users.length; i++) {
108 address user = users[i];
109 if (!_isSolvent(user, _exchangeRate)) {
110 uint256 borrowAmount = _computeAssetAmountToSolvency(
111 user,
112 _exchangeRate
113 );
114
115 if (borrowAmount == 0) {
116 continue;
117 }
118
119 uint256 borrowPart;
120 {
121 uint256 availableBorrowPart = userBorrowPart[user];
122 borrowPart = _totalBorrow.toBase(borrowAmount, false);
123 userBorrowPart[user] = availableBorrowPart - borrowPart;
124 }
125 uint256 amountWithBonus = borrowAmount +
126 (borrowAmount * liquidationMultiplier) /
127 FEE_PRECISION;
128 uint256 collateralShare = yieldBox.toShare(
129 collateralId,
130 (amountWithBonus * _exchangeRate) / EXCHANGE_RATE_PRECISION,
131 false
132 );
133 userCollateralShare[user] -= collateralShare;
134 emit LogRemoveCollateral(
135 user,
136 address(liquidationQueue),
137 collateralShare
138 );
139 emit LogRepay(
140 address(liquidationQueue),
141 user,
142 borrowAmount,
143 borrowPart
144 );
145
146 // Keep totals
147 allCollateralShare += collateralShare;
148 allBorrowAmount += borrowAmount;
149 allBorrowPart += borrowPart;
150 }
151: }
384 for (uint256 i = 0; i < users.length; i++) {
385 address user = users[i];
386 if (!_isSolvent(user, _exchangeRate)) {
387 liquidatedCount++;
388 _liquidateUser(
389 user,
390 maxBorrowParts[i],
391 swapper,
392 _exchangeRate,
393 swapData
394 );
395 }
396: }
File: contracts/markets/singularity/Singularity.sol
187 for (uint256 i = 0; i < calls.length; i++) {
188 (bool success, bytes memory result) = address(this).delegatecall(
189 calls[i]
190 );
191 require(success || !revertOnFail, _getRevertMsg(result));
192 successes[i] = success;
193 results[i] = _getRevertMsg(result);
194: }
File: contracts/usd0/modules/USDOLeverageModule.sol
255 for (uint256 i = 0; i < approvals.length; ) {
256 if (approvals[i].permitBorrow) {
257 try
258 IPermitBorrow(approvals[i].target).permitBorrow(
259 approvals[i].owner,
260 approvals[i].spender,
261 approvals[i].value,
262 approvals[i].deadline,
263 approvals[i].v,
264 approvals[i].r,
265 approvals[i].s
266 )
267 {} catch Error(string memory reason) {
268 if (!approvals[i].allowFailure) {
269 revert(reason);
270 }
271 }
272 } else if (approvals[i].permitAll) {
273 try
274 IPermitAll(approvals[i].target).permitAll(
275 approvals[i].owner,
276 approvals[i].spender,
277 approvals[i].deadline,
278 approvals[i].v,
279 approvals[i].r,
280 approvals[i].s
281 )
282 {} catch Error(string memory reason) {
283 if (!approvals[i].allowFailure) {
284 revert(reason);
285 }
286 }
287 } else {
288 try
289 IERC20Permit(approvals[i].target).permit(
290 approvals[i].owner,
291 approvals[i].spender,
292 approvals[i].value,
293 approvals[i].deadline,
294 approvals[i].v,
295 approvals[i].r,
296 approvals[i].s
297 )
298 {} catch Error(string memory reason) {
299 if (!approvals[i].allowFailure) {
300 revert(reason);
301 }
302 }
303 }
304
305 unchecked {
306 ++i;
307 }
308: }
File: contracts/usd0/modules/USDOMarketModule.sol
244 for (uint256 i = 0; i < approvals.length; ) {
245 if (approvals[i].permitBorrow) {
246 try
247 IPermitBorrow(approvals[i].target).permitBorrow(
248 approvals[i].owner,
249 approvals[i].spender,
250 approvals[i].value,
251 approvals[i].deadline,
252 approvals[i].v,
253 approvals[i].r,
254 approvals[i].s
255 )
256 {} catch Error(string memory reason) {
257 if (!approvals[i].allowFailure) {
258 revert(reason);
259 }
260 }
261 } else if (approvals[i].permitAll) {
262 try
263 IPermitAll(approvals[i].target).permitAll(
264 approvals[i].owner,
265 approvals[i].spender,
266 approvals[i].deadline,
267 approvals[i].v,
268 approvals[i].r,
269 approvals[i].s
270 )
271 {} catch Error(string memory reason) {
272 if (!approvals[i].allowFailure) {
273 revert(reason);
274 }
275 }
276 } else {
277 try
278 IERC20Permit(approvals[i].target).permit(
279 approvals[i].owner,
280 approvals[i].spender,
281 approvals[i].value,
282 approvals[i].deadline,
283 approvals[i].v,
284 approvals[i].r,
285 approvals[i].s
286 )
287 {} catch Error(string memory reason) {
288 if (!approvals[i].allowFailure) {
289 revert(reason);
290 }
291 }
292 }
293
294 unchecked {
295 ++i;
296 }
297: }
File: contracts/usd0/modules/USDOOptionsModule.sol
245 for (uint256 i = 0; i < approvals.length; ) {
246 if (approvals[i].permitBorrow) {
247 try
248 IPermitBorrow(approvals[i].target).permitBorrow(
249 approvals[i].owner,
250 approvals[i].spender,
251 approvals[i].value,
252 approvals[i].deadline,
253 approvals[i].v,
254 approvals[i].r,
255 approvals[i].s
256 )
257 {} catch Error(string memory reason) {
258 if (!approvals[i].allowFailure) {
259 revert(reason);
260 }
261 }
262 } else if (approvals[i].permitAll) {
263 try
264 IPermitAll(approvals[i].target).permitAll(
265 approvals[i].owner,
266 approvals[i].spender,
267 approvals[i].deadline,
268 approvals[i].v,
269 approvals[i].r,
270 approvals[i].s
271 )
272 {} catch Error(string memory reason) {
273 if (!approvals[i].allowFailure) {
274 revert(reason);
275 }
276 }
277 } else {
278 try
279 IERC20Permit(approvals[i].target).permit(
280 approvals[i].owner,
281 approvals[i].spender,
282 approvals[i].value,
283 approvals[i].deadline,
284 approvals[i].v,
285 approvals[i].r,
286 approvals[i].s
287 )
288 {} catch Error(string memory reason) {
289 if (!approvals[i].allowFailure) {
290 revert(reason);
291 }
292 }
293 }
294
295 unchecked {
296 ++i;
297 }
298: }
File: contracts/TapiocaWrapper.sol
140 for (uint256 i = 0; i < _call.length; i++) {
141 (success, results[i]) = payable(_call[i].toft).call{
142 value: msg.value
143 }(_call[i].bytecode);
144 if (_call[i].revertOnFailure && !success) {
145 revert TapiocaWrapper__TOFTExecutionFailed(results[i]);
146 }
147: }
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
285 for (uint256 i = 0; i < approvals.length; ) {
286 if (approvals[i].permitBorrow) {
287 try
288 IPermitBorrow(approvals[i].target).permitBorrow(
289 approvals[i].owner,
290 approvals[i].spender,
291 approvals[i].value,
292 approvals[i].deadline,
293 approvals[i].v,
294 approvals[i].r,
295 approvals[i].s
296 )
297 {} catch Error(string memory reason) {
298 if (!approvals[i].allowFailure) {
299 revert(reason);
300 }
301 }
302 } else if (approvals[i].permitAll) {
303 try
304 IPermitAll(approvals[i].target).permitAll(
305 approvals[i].owner,
306 approvals[i].spender,
307 approvals[i].deadline,
308 approvals[i].v,
309 approvals[i].r,
310 approvals[i].s
311 )
312 {} catch Error(string memory reason) {
313 if (!approvals[i].allowFailure) {
314 revert(reason);
315 }
316 }
317 } else {
318 try
319 IERC20Permit(approvals[i].target).permit(
320 approvals[i].owner,
321 approvals[i].spender,
322 approvals[i].value,
323 approvals[i].deadline,
324 approvals[i].v,
325 approvals[i].r,
326 approvals[i].s
327 )
328 {} catch Error(string memory reason) {
329 if (!approvals[i].allowFailure) {
330 revert(reason);
331 }
332 }
333 }
334
335 unchecked {
336 ++i;
337 }
338: }
File: contracts/tOFT/modules/BaseTOFTMarketModule.sol
261 for (uint256 i = 0; i < approvals.length; ) {
262 if (approvals[i].permitBorrow) {
263 try
264 IPermitBorrow(approvals[i].target).permitBorrow(
265 approvals[i].owner,
266 approvals[i].spender,
267 approvals[i].value,
268 approvals[i].deadline,
269 approvals[i].v,
270 approvals[i].r,
271 approvals[i].s
272 )
273 {} catch Error(string memory reason) {
274 if (!approvals[i].allowFailure) {
275 revert(reason);
276 }
277 }
278 } else if (approvals[i].permitAll) {
279 try
280 IPermitAll(approvals[i].target).permitAll(
281 approvals[i].owner,
282 approvals[i].spender,
283 approvals[i].deadline,
284 approvals[i].v,
285 approvals[i].r,
286 approvals[i].s
287 )
288 {} catch Error(string memory reason) {
289 if (!approvals[i].allowFailure) {
290 revert(reason);
291 }
292 }
293 } else {
294 try
295 IERC20Permit(approvals[i].target).permit(
296 approvals[i].owner,
297 approvals[i].spender,
298 approvals[i].value,
299 approvals[i].deadline,
300 approvals[i].v,
301 approvals[i].r,
302 approvals[i].s
303 )
304 {} catch Error(string memory reason) {
305 if (!approvals[i].allowFailure) {
306 revert(reason);
307 }
308 }
309 }
310
311 unchecked {
312 ++i;
313 }
314: }
File: contracts/tOFT/modules/BaseTOFTOptionsModule.sol
260 for (uint256 i = 0; i < approvals.length; ) {
261 if (approvals[i].permitBorrow) {
262 try
263 IPermitBorrow(approvals[i].target).permitBorrow(
264 approvals[i].owner,
265 approvals[i].spender,
266 approvals[i].value,
267 approvals[i].deadline,
268 approvals[i].v,
269 approvals[i].r,
270 approvals[i].s
271 )
272 {} catch Error(string memory reason) {
273 if (!approvals[i].allowFailure) {
274 revert(reason);
275 }
276 }
277 } else if (approvals[i].permitAll) {
278 try
279 IPermitAll(approvals[i].target).permitAll(
280 approvals[i].owner,
281 approvals[i].spender,
282 approvals[i].deadline,
283 approvals[i].v,
284 approvals[i].r,
285 approvals[i].s
286 )
287 {} catch Error(string memory reason) {
288 if (!approvals[i].allowFailure) {
289 revert(reason);
290 }
291 }
292 } else {
293 try
294 IERC20Permit(approvals[i].target).permit(
295 approvals[i].owner,
296 approvals[i].spender,
297 approvals[i].value,
298 approvals[i].deadline,
299 approvals[i].v,
300 approvals[i].r,
301 approvals[i].s
302 )
303 {} catch Error(string memory reason) {
304 if (!approvals[i].allowFailure) {
305 revert(reason);
306 }
307 }
308 }
309
310 unchecked {
311 ++i;
312 }
313: }
File: contracts/governance/twTAP.sol
507 for (uint256 i = 0; i < len; ) {
508 uint256 claimableIndex = rewardTokenIndex[_rewardTokens[i]];
509 uint256 amount = amounts[i];
510
511 if (amount > 0) {
512 // Math is safe: `amount` calculated safely in `claimable()`
513 claimed[_tokenId][claimableIndex] += amount;
514 rewardTokens[claimableIndex].safeTransfer(_to, amount);
515 }
516 ++i;
517: }
File: contracts/option-airdrop/AirdropBroker.sol
375 for (uint256 i = 0; i < len; ++i) {
376 ERC20 paymentToken = ERC20(_paymentTokens[i]);
377 paymentToken.transfer(
378 paymentTokenBeneficiary,
379 paymentToken.balanceOf(address(this))
380 );
381: }
File: contracts/options/TapiocaOptionBroker.sol
489 for (uint256 i = 0; i < len; ++i) {
490 ERC20 paymentToken = ERC20(_paymentTokens[i]);
491 paymentToken.transfer(
492 paymentTokenBeneficiary,
493 paymentToken.balanceOf(address(this))
494 );
495: }
File: contracts/tokens/BaseTapOFT.sol
333 for (uint256 i = 0; i < approvals.length; ) {
334 try
335 IERC20Permit(approvals[i].target).permit(
336 approvals[i].owner,
337 approvals[i].spender,
338 approvals[i].value,
339 approvals[i].deadline,
340 approvals[i].v,
341 approvals[i].r,
342 approvals[i].s
343 )
344 {} catch Error(string memory reason) {
345 if (!approvals[i].allowFailure) {
346 revert(reason);
347 }
348 }
349
350 unchecked {
351 ++i;
352 }
353: }
File: contracts/Magnetar/MagnetarV2.sol
202 for (uint256 i = 0; i < length; i++) {
203 Call calldata _action = calls[i];
204 if (!_action.allowFailure) {
205 require(
206 _action.call.length > 0,
207 string.concat(
208 "MagnetarV2: Missing call for action with index",
209 string(abi.encode(i))
210 )
211 );
212 }
213
214 unchecked {
215 valAccumulator += _action.value;
216 }
217
218 if (_action.id == PERMIT_ALL) {
219 _permit(
220 _action.target,
221 _action.call,
222 true,
223 _action.allowFailure
224 );
225 } else if (_action.id == PERMIT) {
226 _permit(
227 _action.target,
228 _action.call,
229 false,
230 _action.allowFailure
231 );
232 } else if (_action.id == TOFT_WRAP) {
233 WrapData memory data = abi.decode(_action.call[4:], (WrapData));
234 _checkSender(data.from);
235 if (_action.value > 0) {
236 unchecked {
237 valAccumulator += _action.value;
238 }
239 ITapiocaOFT(_action.target).wrapNative{
240 value: _action.value
241 }(data.to);
242 } else {
243 ITapiocaOFT(_action.target).wrap(
244 msg.sender,
245 data.to,
246 data.amount
247 );
248 }
249 } else if (_action.id == TOFT_SEND_FROM) {
250 (
251 address from,
252 uint16 dstChainId,
253 bytes32 to,
254 uint256 amount,
255 ISendFrom.LzCallParams memory lzCallParams
256 ) = abi.decode(
257 _action.call[4:],
258 (
259 address,
260 uint16,
261 bytes32,
262 uint256,
263 (ISendFrom.LzCallParams)
264 )
265 );
266 _checkSender(from);
267
268 ISendFrom(_action.target).sendFrom{value: _action.value}(
269 msg.sender,
270 dstChainId,
271 to,
272 amount,
273 lzCallParams
274 );
275 } else if (_action.id == YB_DEPOSIT_ASSET) {
276 YieldBoxDepositData memory data = abi.decode(
277 _action.call[4:],
278 (YieldBoxDepositData)
279 );
280 _checkSender(data.from);
281
282 (uint256 amountOut, uint256 shareOut) = IYieldBoxBase(
283 _action.target
284 ).depositAsset(
285 data.assetId,
286 msg.sender,
287 data.to,
288 data.amount,
289 data.share
290 );
291 returnData[i] = Result({
292 success: true,
293 returnData: abi.encode(amountOut, shareOut)
294 });
295 } else if (_action.id == MARKET_ADD_COLLATERAL) {
296 SGLAddCollateralData memory data = abi.decode(
297 _action.call[4:],
298 (SGLAddCollateralData)
299 );
300 _checkSender(data.from);
301
302 IMarket(_action.target).addCollateral(
303 msg.sender,
304 data.to,
305 data.skim,
306 data.amount,
307 data.share
308 );
309 } else if (_action.id == MARKET_BORROW) {
310 SGLBorrowData memory data = abi.decode(
311 _action.call[4:],
312 (SGLBorrowData)
313 );
314 _checkSender(data.from);
315
316 (uint256 part, uint256 share) = IMarket(_action.target).borrow(
317 msg.sender,
318 data.to,
319 data.amount
320 );
321 returnData[i] = Result({
322 success: true,
323 returnData: abi.encode(part, share)
324 });
325 } else if (_action.id == YB_WITHDRAW_TO) {
326 (
327 address yieldBox,
328 address from,
329 uint256 assetId,
330 uint16 dstChainId,
331 bytes32 receiver,
332 uint256 amount,
333 uint256 share,
334 bytes memory adapterParams,
335 address payable refundAddress
336 ) = abi.decode(
337 _action.call[4:],
338 (
339 address,
340 address,
341 uint256,
342 uint16,
343 bytes32,
344 uint256,
345 uint256,
346 bytes,
347 address
348 )
349 );
350
351 _executeModule(
352 Module.Market,
353 abi.encodeWithSelector(
354 MagnetarMarketModule.withdrawToChain.selector,
355 yieldBox,
356 from,
357 assetId,
358 dstChainId,
359 receiver,
360 amount,
361 share,
362 adapterParams,
363 refundAddress,
364 _action.value
365 )
366 );
367 } else if (_action.id == MARKET_LEND) {
368 SGLLendData memory data = abi.decode(
369 _action.call[4:],
370 (SGLLendData)
371 );
372 _checkSender(data.from);
373
374 uint256 fraction = IMarket(_action.target).addAsset(
375 msg.sender,
376 data.to,
377 data.skim,
378 data.share
379 );
380 returnData[i] = Result({
381 success: true,
382 returnData: abi.encode(fraction)
383 });
384 } else if (_action.id == MARKET_REPAY) {
385 SGLRepayData memory data = abi.decode(
386 _action.call[4:],
387 (SGLRepayData)
388 );
389 _checkSender(data.from);
390
391 uint256 amount = IMarket(_action.target).repay(
392 msg.sender,
393 data.to,
394 data.skim,
395 data.part
396 );
397 returnData[i] = Result({
398 success: true,
399 returnData: abi.encode(amount)
400 });
401 } else if (_action.id == TOFT_SEND_AND_BORROW) {
402 (
403 address from,
404 address to,
405 uint16 lzDstChainId,
406 bytes memory airdropAdapterParams,
407 ITapiocaOFT.IBorrowParams memory borrowParams,
408 ICommonData.IWithdrawParams memory withdrawParams,
409 ICommonData.ISendOptions memory options,
410 ICommonData.IApproval[] memory approvals
411 ) = abi.decode(
412 _action.call[4:],
413 (
414 address,
415 address,
416 uint16,
417 bytes,
418 ITapiocaOFT.IBorrowParams,
419 ICommonData.IWithdrawParams,
420 ICommonData.ISendOptions,
421 ICommonData.IApproval[]
422 )
423 );
424 _checkSender(from);
425
426 ITapiocaOFT(_action.target).sendToYBAndBorrow{
427 value: _action.value
428 }(
429 msg.sender,
430 to,
431 lzDstChainId,
432 airdropAdapterParams,
433 borrowParams,
434 withdrawParams,
435 options,
436 approvals
437 );
438 } else if (_action.id == TOFT_SEND_AND_LEND) {
439 (
440 address from,
441 address to,
442 uint16 dstChainId,
443 address zroPaymentAddress,
444 IUSDOBase.ILendOrRepayParams memory lendParams,
445 ICommonData.IApproval[] memory approvals,
446 ICommonData.IWithdrawParams memory withdrawParams,
447 bytes memory adapterParams
448 ) = abi.decode(
449 _action.call[4:],
450 (
451 address,
452 address,
453 uint16,
454 address,
455 (IUSDOBase.ILendOrRepayParams),
456 (ICommonData.IApproval[]),
457 (ICommonData.IWithdrawParams),
458 bytes
459 )
460 );
461 _checkSender(from);
462
463 IUSDOBase(_action.target).sendAndLendOrRepay{
464 value: _action.value
465 }(
466 msg.sender,
467 to,
468 dstChainId,
469 zroPaymentAddress,
470 lendParams,
471 approvals,
472 withdrawParams,
473 adapterParams
474 );
475 } else if (_action.id == TOFT_DEPOSIT_TO_STRATEGY) {
476 TOFTSendToStrategyData memory data = abi.decode(
477 _action.call[4:],
478 (TOFTSendToStrategyData)
479 );
480 _checkSender(data.from);
481
482 ITapiocaOFT(_action.target).sendToStrategy{
483 value: _action.value
484 }(
485 msg.sender,
486 data.to,
487 data.amount,
488 data.share,
489 data.assetId,
490 data.lzDstChainId,
491 data.options
492 );
493 } else if (_action.id == TOFT_RETRIEVE_FROM_STRATEGY) {
494 (
495 address from,
496 uint256 amount,
497 uint256 share,
498 uint256 assetId,
499 uint16 lzDstChainId,
500 address zroPaymentAddress,
501 bytes memory airdropAdapterParam
502 ) = abi.decode(
503 _action.call[4:],
504 (
505 address,
506 uint256,
507 uint256,
508 uint256,
509 uint16,
510 address,
511 bytes
512 )
513 );
514
515 _checkSender(from);
516
517 ITapiocaOFT(_action.target).retrieveFromStrategy{
518 value: _action.value
519 }(
520 msg.sender,
521 amount,
522 share,
523 assetId,
524 lzDstChainId,
525 zroPaymentAddress,
526 airdropAdapterParam
527 );
528 } else if (_action.id == MARKET_YBDEPOSIT_AND_LEND) {
529 HelperLendData memory data = abi.decode(
530 _action.call[4:],
531 (HelperLendData)
532 );
533
534 _executeModule(
535 Module.Market,
536 abi.encodeWithSelector(
537 MagnetarMarketModule.mintFromBBAndLendOnSGL.selector,
538 data.user,
539 data.lendAmount,
540 data.mintData,
541 data.depositData,
542 data.lockData,
543 data.participateData,
544 data.externalContracts
545 )
546 );
547 } else if (_action.id == MARKET_YBDEPOSIT_COLLATERAL_AND_BORROW) {
548 (
549 address market,
550 address user,
551 uint256 collateralAmount,
552 uint256 borrowAmount,
553 ,
554 bool deposit,
555 ICommonData.IWithdrawParams memory withdrawParams
556 ) = abi.decode(
557 _action.call[4:],
558 (
559 address,
560 address,
561 uint256,
562 uint256,
563 bool,
564 bool,
565 ICommonData.IWithdrawParams
566 )
567 );
568
569 _executeModule(
570 Module.Market,
571 abi.encodeWithSelector(
572 MagnetarMarketModule
573 .depositAddCollateralAndBorrowFromMarket
574 .selector,
575 market,
576 user,
577 collateralAmount,
578 borrowAmount,
579 false,
580 deposit,
581 withdrawParams
582 )
583 );
584 } else if (_action.id == MARKET_REMOVE_ASSET) {
585 HelperMarketRemoveAndRepayAsset memory data = abi.decode(
586 _action.call[4:],
587 (HelperMarketRemoveAndRepayAsset)
588 );
589
590 _executeModule(
591 Module.Market,
592 abi.encodeWithSelector(
593 MagnetarMarketModule
594 .exitPositionAndRemoveCollateral
595 .selector,
596 data.user,
597 data.externalData,
598 data.removeAndRepayData
599 )
600 );
601 } else if (_action.id == MARKET_DEPOSIT_REPAY_REMOVE_COLLATERAL) {
602 HelperDepositRepayRemoveCollateral memory data = abi.decode(
603 _action.call[4:],
604 (HelperDepositRepayRemoveCollateral)
605 );
606
607 _executeModule(
608 Module.Market,
609 abi.encodeWithSelector(
610 MagnetarMarketModule
611 .depositRepayAndRemoveCollateralFromMarket
612 .selector,
613 data.market,
614 data.user,
615 data.depositAmount,
616 data.repayAmount,
617 data.collateralAmount,
618 data.extractFromSender,
619 data.withdrawCollateralParams
620 )
621 );
622 } else if (_action.id == MARKET_BUY_COLLATERAL) {
623 HelperBuyCollateral memory data = abi.decode(
624 _action.call[4:],
625 (HelperBuyCollateral)
626 );
627
628 IMarket(data.market).buyCollateral(
629 data.from,
630 data.borrowAmount,
631 data.supplyAmount,
632 data.minAmountOut,
633 address(data.swapper),
634 data.dexData
635 );
636 } else if (_action.id == MARKET_SELL_COLLATERAL) {
637 HelperSellCollateral memory data = abi.decode(
638 _action.call[4:],
639 (HelperSellCollateral)
640 );
641
642 IMarket(data.market).sellCollateral(
643 data.from,
644 data.share,
645 data.minAmountOut,
646 address(data.swapper),
647 data.dexData
648 );
649 } else if (_action.id == TAP_EXERCISE_OPTION) {
650 HelperExerciseOption memory data = abi.decode(
651 _action.call[4:],
652 (HelperExerciseOption)
653 );
654
655 ITapiocaOptionsBrokerCrossChain(_action.target).exerciseOption(
656 data.optionsData,
657 data.lzData,
658 data.tapSendData,
659 data.approvals
660 );
661 } else if (_action.id == MARKET_MULTIHOP_BUY) {
662 HelperMultiHopBuy memory data = abi.decode(
663 _action.call[4:],
664 (HelperMultiHopBuy)
665 );
666
667 IUSDOBase(_action.target).initMultiHopBuy(
668 data.from,
669 data.collateralAmount,
670 data.borrowAmount,
671 data.swapData,
672 data.lzData,
673 data.externalData,
674 data.airdropAdapterParams,
675 data.approvals
676 );
677 } else if (_action.id == MARKET_MULTIHOP_BUY) {
678 HelperMultiHopBuy memory data = abi.decode(
679 _action.call[4:],
680 (HelperMultiHopBuy)
681 );
682
683 IUSDOBase(_action.target).initMultiHopBuy(
684 data.from,
685 data.collateralAmount,
686 data.borrowAmount,
687 data.swapData,
688 data.lzData,
689 data.externalData,
690 data.airdropAdapterParams,
691 data.approvals
692 );
693 } else if (_action.id == TOFT_REMOVE_AND_REPAY) {
694 HelperTOFTRemoveAndRepayAsset memory data = abi.decode(
695 _action.call[4:],
696 (HelperTOFTRemoveAndRepayAsset)
697 );
698
699 IUSDOBase(_action.target).removeAsset(
700 data.from,
701 data.to,
702 data.lzDstChainId,
703 data.zroPaymentAddress,
704 data.adapterParams,
705 data.externalData,
706 data.removeAndRepayData,
707 data.approvals
708 );
709 } else {
710 revert("MagnetarV2: action not valid");
711 }
712: }
973 for (uint256 i = 0; i < len; i++) {
974 ISingularity sgl = markets[i];
975
976 result[i].market = _commonInfo(who, IMarket(address(sgl)));
977
978 (uint128 totalAssetElastic, uint128 totalAssetBase) = sgl //
979 .totalAsset(); //
980 _totalAsset = Rebase(totalAssetElastic, totalAssetBase); //
981 result[i].totalAsset = _totalAsset; //
982 result[i].userAssetFraction = sgl.balanceOf(who); //
983
984 (
985 ISingularity.AccrueInfo memory _accrueInfo,
986 uint256 _utilization
987 ) = sgl.getInterestDetails();
988
989 result[i].accrueInfo = _accrueInfo;
990 result[i].utilization = _utilization;
991: }
1004 for (uint256 i = 0; i < len; i++) {
1005 IBigBang bigBang = markets[i];
1006 result[i].market = _commonInfo(who, IMarket(address(bigBang)));
1007
1008 (uint64 debtRate, uint64 lastAccrued) = bigBang.accrueInfo();
1009 _accrueInfo = IBigBang.AccrueInfo(debtRate, lastAccrued);
1010 result[i].accrueInfo = _accrueInfo;
1011 result[i].minDebtRate = bigBang.minDebtRate();
1012 result[i].maxDebtRate = bigBang.maxDebtRate();
1013 result[i].debtRateAgainstEthMarket = bigBang
1014 .debtRateAgainstEthMarket();
1015 result[i].currentDebtRate = bigBang.getDebtRate();
1016
1017 IPenrose penrose = IPenrose(bigBang.penrose());
1018 result[i].mainBBMarket = penrose.bigBangEthMarket();
1019 result[i].mainBBDebtRate = penrose.bigBangEthDebtRate();
1020: }
File: contracts/NativeTokenFactory.sol
129 for (uint256 i = 0; i < len; i++) {
130 _mint(tos[i], tokenId, amounts[i]);
131: }
141 for (uint256 i = 0; i < len; i++) {
142 _requireTransferAllowed(froms[i], isApprovedForAsset[froms[i]][msg.sender][tokenId]);
143 _burn(froms[i], tokenId, amounts[i]);
144: }
File: contracts/YieldBox.sol
309 for (uint256 i = 0; i < len; i++) {
310 _requireTransferAllowed(from, isApprovedForAsset[from][msg.sender][assetIds_[i]]);
311: }
320 for (uint256 i = 0; i < len; i++) {
321 uint256 id = ids[i];
322 _requireTransferAllowed(from, isApprovedForAsset[from][msg.sender][id]);
323 uint256 value = values[i];
324 balanceOf[from][id] -= value;
325 balanceOf[to][id] += value;
326: }
339 for (uint256 i = 0; i < len; i++) {
340 require(tos[i] != address(0), "YieldBox: to not set"); // To avoid a bad UI from burning funds
341: }
345 for (uint256 i = 0; i < len; i++) {
346 address to = tos[i];
347 uint256 share_ = shares[i];
348 balanceOf[to][assetId] += share_;
349 _totalShares += share_;
350 emit TransferSingle(msg.sender, from, to, assetId, share_);
351: }
There are 10 instances of this issue:
see instances
File: contracts/Penrose.sol
272: require(msg.sender == conservator, "Penrose: unauthorized");
File: contracts/markets/Market.sol
246: require(msg.sender == conservator, "Market: unauthorized");
File: contracts/usd0/BaseUSDO.sol
115: require(msg.sender == conservator, "USDO: unauthorized");
File: contracts/governance/twTAP.sol
365: require(msg.sender == address(tapOFT), "twTAP: only tapOFT");
390: require(msg.sender == address(tapOFT), "twTAP: only tapOFT");
File: contracts/option-airdrop/AirdropBroker.sol
447: require(PCNFT.ownerOf(_tokenID) == msg.sender, "adb: Not eligible");
File: contracts/tokens/TapOFT.sol
221: require(msg.sender == minter, "unauthorized");
File: contracts/Magnetar/MagnetarV2Storage.sol
337: require(_from == msg.sender, "MagnetarV2: operator not approved");
File: contracts/glp/GlpStrategy.sol
91: require(msg.sender == address(gmxWethPool), "Not the pool");
File: contracts/NativeTokenFactory.sol
77: require(msg.sender == _pendingOwner, "NTF: caller != pending owner");
The contract's interface should be imported first, followed by each of the interfaces it uses, followed by all other files. The examples below do not follow this layout.
There are 27 instances of this issue:
see instances
File: contracts/Penrose.sol
8: import "tapioca-sdk/dist/contracts/YieldBox/contracts/interfaces/IYieldBox.sol";
10: import "tapioca-periph/contracts/interfaces/ISingularity.sol";
File: contracts/markets/Market.sol
8: import "tapioca-periph/contracts/interfaces/IOracle.sol";
File: contracts/usd0/modules/USDOLeverageModule.sol
8: import {IUSDOBase} from "tapioca-periph/contracts/interfaces/IUSDO.sol";
File: contracts/usd0/modules/USDOOptionsModule.sol
8: import "tapioca-periph/contracts/interfaces/IPermitBorrow.sol";
File: contracts/tOFT/modules/BaseTOFTLeverageModule.sol
8: import {IUSDOBase} from "tapioca-periph/contracts/interfaces/IUSDO.sol";
File: contracts/tOFT/modules/BaseTOFTMarketModule.sol
8: import {IUSDOBase} from "tapioca-periph/contracts/interfaces/IUSDO.sol";
File: contracts/tOFT/modules/BaseTOFTOptionsModule.sol
8: import "tapioca-periph/contracts/interfaces/IPermitBorrow.sol";
File: contracts/tOFT/modules/BaseTOFTStrategyModule.sol
8: import {IUSDOBase} from "tapioca-periph/contracts/interfaces/IUSDO.sol";
File: contracts/option-airdrop/AirdropBroker.sol
7: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
File: contracts/option-airdrop/aoTAP.sol
7: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
File: contracts/options/TapiocaOptionLiquidityProvision.sol
9: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
12: import "tapioca-sdk/dist/contracts/YieldBox/contracts/interfaces/IYieldBox.sol";
File: contracts/options/oTAP.sol
6: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
File: contracts/tokens/BaseTapOFT.sol
7: import "tapioca-periph/contracts/interfaces/ITapiocaOFT.sol";
File: contracts/Magnetar/modules/MagnetarMarketModule.sol
10: import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
File: contracts/Swapper/UniswapV3Swapper.sol
8: import "@uniswap/v3-periphery/contracts/interfaces/IQuoterV2.sol";
File: contracts/aave/AaveStrategy.sol
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
File: contracts/balancer/BalancerStrategy.sol
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
File: contracts/compound/CompoundStrategy.sol
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
File: contracts/convex/ConvexTricryptoStrategy.sol
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
File: contracts/curve/TricryptoLPStrategy.sol
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
File: contracts/curve/TricryptoNativeStrategy.sol
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
File: contracts/lido/LidoEthStrategy.sol
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
File: contracts/stargate/StargateStrategy.sol
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
File: contracts/yearn/YearnStrategy.sol
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
File: contracts/YieldBox.sol
29: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC1155.sol";
Consider adding a NatSpec comment describing why the function doesn't need a body and or the purpose it serves
There are 4 instances of this issue:
File: contracts/markets/MarketERC20.sol
114: function totalSupply() public view virtual override returns (uint256) {}
File: contracts/markets/bigBang/BigBang.sol
426 function transfer(
427 address to,
428 uint256 amount
429: ) public override returns (bool) {}
431 function transferFrom(
432 address from,
433 address to,
434 uint256 amount
435: ) public override returns (bool) {}
File: contracts/markets/singularity/SGLStorage.sol
195: function _accrue() internal virtual override {}
Both implementations have been optimized and are usage-hardened, so writing your own is unnecessary
There are 20 instances of this issue:
see instances
File: contracts/Penrose.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/markets/Market.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/markets/bigBang/BigBang.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/markets/singularity/SGLStorage.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/Vesting.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/option-airdrop/AirdropBroker.sol
5: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/option-airdrop/aoTAP.sol
5: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/options/TapiocaOptionBroker.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/options/TapiocaOptionLiquidityProvision.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/tokens/LTap.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/aave/AaveStrategy.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/balancer/BalancerStrategy.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/compound/CompoundStrategy.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/convex/ConvexTricryptoStrategy.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/curve/TricryptoLPStrategy.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/curve/TricryptoNativeStrategy.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/glp/GlpStrategy.sol
7: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/lido/LidoEthStrategy.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/stargate/StargateStrategy.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: contracts/yearn/YearnStrategy.sol
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
Array entries are added but are never removed. Consider whether this should be the case, or whether there should be a maximum, or whether old entries should be removed. Cases where there are specific potential problems will be flagged separately under a different issue.
There are 5 instances of this issue:
File: contracts/Penrose.sol
329: singularityMasterContracts.push(mc);
351: bigbangMasterContracts.push(mc);
386: clonesOf[mc].push(_contract);
419: clonesOf[mc].push(_contract);
File: contracts/options/TapiocaOptionLiquidityProvision.sol
290: singularities.push(assetID);
There are 7 instances of this issue:
File: contracts/markets/Market.sol
158 function setMarketConfig(
159 uint256 _borrowOpeningFee,
160 IOracle _oracle,
161 bytes calldata _oracleData,
162 address _conservator,
163 uint256 _callerFee,
164 uint256 _protocolFee,
165 uint256 _liquidationBonusAmount,
166 uint256 _minLiquidatorReward,
167 uint256 _maxLiquidatorReward,
168 uint256 _totalBorrowCap,
169 uint256 _collateralizationRate
170: ) external onlyOwner {
File: contracts/markets/singularity/SGLCommon.sol
35 function _getInterestRate()
36 internal
37 view
38 returns (
39 ISingularity.AccrueInfo memory _accrueInfo,
40 Rebase memory _totalBorrow,
41 Rebase memory _totalAsset,
42 uint256 extraAmount,
43 uint256 feeFraction,
44 uint256 utilization,
45 bool logStartingInterest
46 )
47: {
File: contracts/markets/singularity/SGLLiquidation.sol
97 function _orderBookLiquidation(
98 address[] calldata users,
99 uint256 _exchangeRate,
100 bytes memory swapData
101: ) private {
File: contracts/markets/singularity/Singularity.sol
62: function init(bytes calldata data) external onlyOnce {
File: contracts/Magnetar/MagnetarV2.sol
194 function burst(
195 Call[] calldata calls
196: ) external payable returns (Result[] memory returnData) {
File: contracts/Magnetar/modules/MagnetarMarketModule.sol
292 function _mintFromBBAndLendOnSGL(
293 address user,
294 uint256 lendAmount,
295 IUSDOBase.IMintData calldata mintData,
296 ICommonData.IDepositData calldata depositData,
297 ITapiocaOptionLiquidityProvision.IOptionsLockData calldata lockData,
298 ITapiocaOptionsBroker.IOptionsParticipateData calldata participateData,
299 ICommonData.ICommonExternalContracts calldata externalContracts
300: ) private {
495 function _exitPositionAndRemoveCollateral(
496 address user,
497 ICommonData.ICommonExternalContracts calldata externalData,
498 IUSDOBase.IRemoveAndRepay calldata removeAndRepayData
499: ) private {
int256
/uint256
are the preferred type names (they're what are used for function signatures), so they should be used consistently
There are 7 instances of this issue:
File: contracts/markets/MarketERC20.sol
75: function _allowedLend(address from, uint share) internal {
84: function _allowedBorrow(address from, uint share) internal {
94: modifier allowedLend(address from, uint share) virtual {
99: modifier allowedBorrow(address from, uint share) virtual {
File: contracts/governance/twTAP.sol
156: uint _tokenId
File: contracts/tokens/BaseTapOFT.sol
129: (, , address to, uint256 amount, uint duration) = abi.decode(
228: for (uint i = 0; i < len; ) {
Solidity follows two's complement rules for its integers, meaning that the most significant bit for signed integers is used to denote the sign, and converting between the two requires inverting all of the bits and adding one. Because of this, casting an unsigned integer to a signed one may result in a change of the sign and or magnitude of the value. For example, int8(type(uint8).max)
is not equal to type(int8).max
, but is equal to -1
. type(uint8).max
in binary is 11111111
, which if cast to a signed value, means the first binary 1
indicates a negative value, and the binary 1
s, invert to all zeroes, and when one is added, it becomes one, but negative, and therefore the decimal value of binary 11111111
is -1
.
There are 10 instances of this issue:
File: tapioca-bar-audit/contracts/markets/Market.sol
/// @audit uint256 minLiquidatorReward -> int256
/// @audit uint256 maxLiquidatorReward -> int256
456: int256 diff = int256(minLiquidatorReward) - int256(maxLiquidatorReward);
/// @audit uint256 rewardPercentage -> int256
457: int256 reward = (diff * int256(rewardPercentage)) /
/// @audit uint256 FEE_PRECISION -> int256
458: int256(FEE_PRECISION) +
/// @audit uint256 maxLiquidatorReward -> int256
459: int256(maxLiquidatorReward);
File: tap-token-audit/contracts/governance/twTAP.sol
/// @audit uint256 votes -> int256
343: weekTotals[w0 + 1].netActiveVotes += int256(votes);
/// @audit uint256 votes -> int256
344: weekTotals[w1 + 1].netActiveVotes -= int256(votes);
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
/// @audit uint256 i -> int256
159: index = int256(i);
/// @audit uint256 i -> int256
228: index = int256(i);
File: tapioca-yieldbox-strategies-audit/contracts/glp/GlpStrategy.sol
/// @audit uint256 gmxAmount -> int256
327: int256(gmxAmount),
Contracts are allowed to override their parents' functions and change the visibility from external
to public
.
There are 74 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
242 function borrow(
243 address from,
244 address to,
245 uint256 amount
246: ) public notPaused solvent(from) returns (uint256 part, uint256 share) {
263 function repay(
264 address from,
265 address to,
266 bool,
267 uint256 part
268: ) public notPaused allowedBorrow(from, part) returns (uint256 amount) {
282 function addCollateral(
283 address from,
284 address to,
285 bool skim,
286 uint256 amount,
287 uint256 share
288: ) public allowedBorrow(from, share) notPaused {
296 function removeCollateral(
297 address from,
298 address to,
299 uint256 share
300: ) public notPaused solvent(from) allowedBorrow(from, share) {
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
116: function nonces(address owner) public view returns (uint256) {
201 function approveBorrow(
202 address spender,
203 uint256 amount
204: ) public returns (bool) {
File: tapioca-bar-audit/contracts/markets/singularity/SGLBorrow.sol
21 function borrow(
22 address from,
23 address to,
24 uint256 amount
25: ) public notPaused solvent(from) returns (uint256 part, uint256 share) {
45 function repay(
46 address from,
47 address to,
48 bool skim,
49 uint256 part
50: ) public notPaused allowedBorrow(from, part) returns (uint256 amount) {
File: tapioca-bar-audit/contracts/markets/singularity/SGLCollateral.sol
21 function addCollateral(
22 address from,
23 address to,
24 bool skim,
25 uint256 amount,
26 uint256 share
27: ) public notPaused allowedBorrow(from, share) {
35 function removeCollateral(
36 address from,
37 address to,
38 uint256 share
39: ) public notPaused solvent(from) allowedBorrow(from, share) {
File: tapioca-bar-audit/contracts/markets/singularity/SGLCommon.sol
17 function accrue() public {
18: _accrue();
File: tapioca-bar-audit/contracts/markets/singularity/SGLStorage.sol
154: function symbol() public view returns (string memory) {
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
204 function addAsset(
205 address from,
206 address to,
207 bool skim,
208 uint256 share
209: ) public notPaused allowedLend(from, share) returns (uint256 fraction) {
219 function removeAsset(
220 address from,
221 address to,
222 uint256 fraction
223: ) public notPaused returns (uint256 share) {
235 function addCollateral(
236 address from,
237 address to,
238 bool skim,
239 uint256 amount,
240: uint256 share
259: function removeCollateral(address from, address to, uint256 share) public {
277 function borrow(
278 address from,
279 address to,
280 uint256 amount
281: ) public returns (uint256 part, uint256 share) {
296 function repay(
297 address from,
298 address to,
299 bool skim,
300 uint256 part
301: ) public returns (uint256 amount) {
File: tapioca-bar-audit/contracts/Penrose.sol
199 function singularityMarkets()
200 public
201 view
202: returns (address[] memory markets)
209: function bigBangMarkets() public view returns (address[] memory markets) {
214: function singularityMasterContractLength() public view returns (uint256) {
219: function bigBangMasterContractLength() public view returns (uint256) {
232 function withdrawAllMarketFees(
233 IMarket[] calldata markets_,
234 ISwapper[] calldata swappers_,
235 IPenrose.SwapData[] calldata swapData_
236: ) public notPaused {
File: tapioca-bar-audit/contracts/usd0/modules/USDOLeverageModule.sol
93: function multiHop(bytes memory _payload) public {
133 function leverageUp(
134 address module,
135 uint16 _srcChainId,
136 bytes memory _srcAddress,
137 uint64 _nonce,
138: bytes memory _payload
190 function leverageUpInternal(
191 uint256 amount,
192 IUSDOBase.ILeverageSwapData memory swapData,
193 IUSDOBase.ILeverageExternalContractsData memory externalData,
194 IUSDOBase.ILeverageLZData memory lzData,
195: address leverageFor
File: tapioca-bar-audit/contracts/usd0/modules/USDOMarketModule.sol
104: function remove(bytes memory _payload) public {
134 function lend(
135 address module,
136 uint16 _srcChainId,
137 bytes memory _srcAddress,
138 uint64 _nonce,
139: bytes memory _payload
191 function lendInternal(
192 address to,
193 IUSDOBase.ILendOrRepayParams memory lendParams,
194 ICommonData.IApproval[] memory approvals,
195: ICommonData.IWithdrawParams memory withdrawParams
File: tapioca-bar-audit/contracts/usd0/modules/USDOOptionsModule.sol
103: function sendFromDestination(bytes memory _payload) public {
138 function exercise(
139 address module,
140 uint16 _srcChainId,
141 bytes memory _srcAddress,
142 uint64 _nonce,
143: bytes memory _payload
206 function exerciseInternal(
207 address from,
208 uint256 oTAPTokenID,
209 address paymentToken,
210 uint256 tapAmount,
211 address target,
212 ITapiocaOptionsBrokerCrossChain.IExerciseLZSendTapData
213 memory tapSendData,
214: ICommonData.IApproval[] memory approvals
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTLeverageModule.sol
111: function multiHop(bytes memory _payload) public {
148 function leverageDown(
149 address module,
150 uint16 _srcChainId,
151 bytes memory _srcAddress,
152 uint64 _nonce,
153: bytes memory _payload
205 function leverageDownInternal(
206 uint256 amount,
207 IUSDOBase.ILeverageSwapData memory swapData,
208 IUSDOBase.ILeverageExternalContractsData memory externalData,
209 IUSDOBase.ILeverageLZData memory lzData,
210: address leverageFor
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTMarketModule.sol
126 function borrow(
127 address module,
128 uint16 _srcChainId,
129 bytes memory _srcAddress,
130 uint64 _nonce,
131: bytes memory _payload
180 function borrowInternal(
181 bytes32 _to,
182 ITapiocaOFT.IBorrowParams memory borrowParams,
183 ICommonData.IWithdrawParams memory withdrawParams,
184: ICommonData.IApproval[] memory approvals
204: function remove(bytes memory _payload) public {
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTOptionsModule.sol
118: function sendFromDestination(bytes memory _payload) public {
153 function exercise(
154 address module,
155 uint16 _srcChainId,
156 bytes memory _srcAddress,
157 uint64 _nonce,
158: bytes memory _payload
221 function exerciseInternal(
222 address from,
223 uint256 oTAPTokenID,
224 address paymentToken,
225 uint256 tapAmount,
226 address target,
227 ITapiocaOptionsBrokerCrossChain.IExerciseLZSendTapData
228 memory tapSendData,
229: ICommonData.IApproval[] memory approvals
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTStrategyModule.sol
122 function strategyDeposit(
123 address module,
124 uint16 _srcChainId,
125 bytes memory _srcAddress,
126 uint64 _nonce,
127 bytes memory _payload,
128: IERC20 _erc20
173 function depositToYieldbox(
174 uint256 _assetId,
175 uint256 _amount,
176 uint256 _share,
177 IERC20 _erc20,
178 address _from,
179: address _to
188 function strategyWithdraw(
189 uint16 _srcChainId,
190: bytes memory _payload
File: tap-token-audit/contracts/governance/twTAP.sol
155 function getParticipation(
156 uint _tokenId
157: ) public view returns (Participation memory participant) {
397: function advanceWeek(uint256 _limit) public {
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2.sol
76 function getCollateralAmountForShare(
77 IMarket market,
78 uint256 share
79: ) public view returns (uint256 amount) {
89 function getCollateralSharesForBorrowPart(
90 IMarket market,
91 uint256 borrowPart,
92 uint256 liquidationMultiplierPrecision,
93 uint256 exchangeRatePrecision
94: ) public view returns (uint256 collateralShares) {
117 function getAmountForBorrowPart(
118 IMarket market,
119 uint256 borrowPart
120: ) public view returns (uint256 amount) {
133 function getBorrowPartForAmount(
134 IMarket market,
135 uint256 amount
136: ) public view returns (uint256 part) {
150 function getAmountForAssetFraction(
151 ISingularity singularity,
152 uint256 fraction
153: ) public view returns (uint256 amount) {
171 function getFractionForAmount(
172 ISingularity singularity,
173 uint256 amount
174: ) public view returns (uint256 fraction) {
File: tapioca-periph-audit/contracts/Multicall/Multicall3.sol
41 function multicall(
42 Call[] calldata calls
43: ) public payable returns (Result[] memory returnData) {
63 function multicallValue(
64 CallValue[] calldata calls
65: ) public payable returns (Result[] memory returnData) {
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
117: function compound(bytes memory) public {}
File: tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
80: function compoundAmount() public pure returns (uint256 result) {
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
103: function compoundAmount() public returns (uint256 result) {
File: tapioca-yieldbox-strategies-audit/contracts/glp/GlpStrategy.sol
104: function harvestGmx(uint256 priceNum, uint256 priceDenom) public onlyOwner {
File: tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
84: function compoundAmount() public pure returns (uint256 result) {
File: tapioca-yieldbox-strategies-audit/contracts/yearn/YearnStrategy.sol
81: function compoundAmount() public pure returns (uint256 result) {
File: YieldBox/contracts/NativeTokenFactory.sol
56: function transferOwnership(uint256 tokenId, address newOwner, bool direct, bool renounce) public onlyOwner(tokenId) {
73: function claimOwnership(uint256 tokenId) public {
90: function createToken(string calldata name, string calldata symbol, uint8 decimals, string calldata uri) public returns (uint32 tokenId) {
109: function mint(uint256 tokenId, address to, uint256 amount) public onlyOwner(tokenId) {
116: function burn(uint256 tokenId, address from, uint256 amount) public allowed(from, tokenId) {
127: function batchMint(uint256 tokenId, address[] calldata tos, uint256[] calldata amounts) public onlyOwner(tokenId) {
138: function batchBurn(uint256 tokenId, address[] calldata froms, uint256[] calldata amounts) public {
File: YieldBox/contracts/YieldBox.sol
168 function depositNFTAsset(
169 uint256 assetId,
170 address from,
171 address to
172: ) public allowed(from, assetId) returns (uint256 amountOut, uint256 shareOut) {
223 function withdraw(
224 uint256 assetId,
225 address from,
226 address to,
227 uint256 amount,
228 uint256 share
229: ) public allowed(from, assetId) returns (uint256 amountOut, uint256 shareOut) {
303: function transfer(address from, address to, uint256 assetId, uint256 share) public allowed(from, assetId) {
307: function batchTransfer(address from, address to, uint256[] calldata assetIds_, uint256[] calldata shares_) public {
336: function transferMultiple(address from, address[] calldata tos, uint256 assetId, uint256[] calldata shares) public allowed(from, assetId) {
477 function deposit(
478 TokenType tokenType,
479 address contractAddress,
480 IStrategy strategy,
481 uint256 tokenId,
482 address from,
483 address to,
484 uint256 amount,
485 uint256 share
486: ) public returns (uint256 amountOut, uint256 shareOut) {
500: function depositETH(IStrategy strategy, address to, uint256 amount) public payable returns (uint256 amountOut, uint256 shareOut) {
Even assembly can benefit from using readable constants instead of hex/numeric literals
There are 194 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
/// @audit 90000
148: callerFee = 90000; // 90%
/// @audit 10000
149: protocolFee = 10000; // 10%
/// @audit 75000
150: collateralizationRate = 75000; // 75%
/// @audit 1e18
154: : 1e18;
/// @audit 1e3
164: minLiquidatorReward = 1e3;
/// @audit 1e4
165: maxLiquidatorReward = 1e4;
/// @audit 1e4
166: liquidationBonusAmount = 1e4;
/// @audit 50
167: borrowOpeningFee = 50; // 0.05%
/// @audit 12000
168: liquidationMultiplier = 12000; //12%
/// @audit 1e18
188: debtRateAgainstEthMarket) / 1e18;
/// @audit 31536000
521: _accrueInfo.debtRate = uint64(annumDebtRate / 31536000); //per second
/// @audit 1e18
534: 1e18;
File: tapioca-bar-audit/contracts/markets/Market.sol
/// @audit 18
264: if (borrowPartDecimals > 18) {
/// @audit 18
265: borrowPartScaled = borrowPart / (10 ** (borrowPartDecimals - 18));
/// @audit 18
267: if (borrowPartDecimals < 18) {
/// @audit 18
268: borrowPartScaled = borrowPart * (10 ** (18 - borrowPartDecimals));
/// @audit 18
272: if (collateralPartDecimals > 18) {
/// @audit 18
275: (10 ** (collateralPartDecimals - 18));
/// @audit 18
277: if (collateralPartDecimals < 18) {
/// @audit 18
280: (10 ** (18 - collateralPartDecimals));
/// @audit 18
293: (10 ** ratesPrecision)) * (10 ** (18 - ratesPrecision));
/// @audit 1e18
295: uint256 x = (numerator * 1e18) / denominator;
/// @audit 68
376: if (_returnData.length < 68) return "Market: no return data";
/// @audit 0x04
380: _returnData := add(_returnData, 0x04)
/// @audit 5
489: uint256 _quotient = ((_numerator / denominator) + 5) / 10;
File: tapioca-bar-audit/contracts/markets/singularity/SGLCommon.sol
/// @audit 1e18
103: 1e18;
/// @audit 1000
210: if (_totalAsset.base + uint128(fraction) < 1000) {
/// @audit 1000
240: require(_totalAsset.base >= 1000, "SGL: min limit");
File: tapioca-bar-audit/contracts/markets/singularity/SGLLendingCommon.sol
/// @audit 1000
75: require(_totalAsset.base >= 1000, "SGL: min limit");
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
/// @audit 951293760
112: minimumInterestPerSecond = 951293760; // approx 3% APR
/// @audit 2536783360
113: maximumInterestPerSecond = 2536783360; // approx 8% APR
/// @audit 7200e36
114: interestElasticity = 7200e36; // Half or double in 28800 seconds (1 hours) if linear
/// @audit 1000
122: callerFee = 1000; // 1%
/// @audit 10000
123: protocolFee = 10000; // 10%
/// @audit 50
124: borrowOpeningFee = 50; // 0.05%
/// @audit 12000
127: liquidationMultiplier = 12000; //12%
/// @audit 75000
129: collateralizationRate = 75000;
/// @audit 25000
130: lqCollateralizationRate = 25000;
/// @audit 1e18
133: : 1e18;
/// @audit 1e3
135: minLiquidatorReward = 1e3;
/// @audit 1e4
136: maxLiquidatorReward = 1e4;
/// @audit 1e4
137: liquidationBonusAmount = 1e4;
/// @audit 3e17
139: minimumTargetUtilization = 3e17;
/// @audit 5e17
140: maximumTargetUtilization = 5e17;
File: tapioca-bar-audit/contracts/Penrose.sol
/// @audit 5e15
131: bigBangEthDebtRate = 5e15;
/// @audit 68
476: if (_returnData.length < 68) return "SGL: no return data";
/// @audit 0x04
480: _returnData := add(_returnData, 0x04)
File: tapioca-bar-audit/contracts/usd0/BaseUSDOStorage.sol
/// @audit 100_000
/// @audit 1e18
78: maxFlashMint = 100_000 * 1e18; // 100k USDO
/// @audit 8
73: ) OFTV2("USDO", "USDO", 8, _lzEndpoint) {
/// @audit 68
91: if (_returnData.length < 68) return "USDO: no return data";
/// @audit 0x04
95: _returnData := add(_returnData, 0x04)
File: tapiocaz-audit/contracts/Balancer.sol
/// @audit 1e5
118: if (_slippage >= 1e5) revert SlippageNotValid();
File: tapiocaz-audit/contracts/TapiocaWrapper.sol
/// @audit 0x0
160: if (address(tapiocaOFTsByErc20[_erc20]) != address(0x0)) {
File: tapiocaz-audit/contracts/tOFT/BaseTOFT.sol
/// @audit 18
85: if (_decimalCache == 0) return 18; //temporary fix for LZ _sharedDecimals check
File: tapiocaz-audit/contracts/tOFT/BaseTOFTStorage.sol
/// @audit 68
71: if (_returnData.length < 68) return "TOFT_data";
/// @audit 0x04
75: _returnData := add(_returnData, 0x04)
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
/// @audit 4
33: uint8[4] amountsPerUsers;
/// @audit 4
34: uint8[4] discountsPerUsers;
/// @audit 1e18
177: require(tapAmount >= 1e18, "adb: Too low");
/// @audit 4
204: require(cachedEpoch <= 4, "adb: Airdrop ended");
/// @audit 3
211: } else if (cachedEpoch == 3) {
/// @audit 4
213: } else if (cachedEpoch == 4) {
/// @audit 1e18
258: require(chosenAmount >= 1e18, "adb: Too low");
/// @audit 4
319: bytes32[4] calldata _merkleRoots
/// @audit 4
335: } else if (_phase == 4) {
/// @audit 20
424: uint256 subPhase = 20 + _role;
/// @audit 1e18
434: uint256 eligibleAmount = uint256(PHASE_2_AMOUNT_PER_USER[_role]) * 1e18;
/// @audit 1e4
435: uint128 discount = uint128(PHASE_2_DISCOUNT_PER_USER[_role]) * 1e4;
/// @audit 3
450: userParticipation[tokenIDToAddress][3] == false,
/// @audit 3
456: userParticipation[tokenIDToAddress][3] = true;
/// @audit 100e4
533: muldiv(rawPaymentAmount, _discount, 100e4); // 1e4 is discount decimals, 100 is discount percentage
/// @audit 18
535: paymentAmount = paymentAmount / (10 ** (18 - _paymentTokenDecimals));
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
/// @audit 1e18
190: require(tapAmount >= 1e18, "tOB: Too low");
/// @audit 1e18
391: require(chosenAmount >= 1e18, "tOB: Too low");
/// @audit 100e4
554: muldiv(rawPaymentAmount, _discount, 100e4); // 1e4 is discount decimals, 100 is discount percentage
/// @audit 18
555: paymentAmount = paymentAmount / (10 ** (18 - _paymentTokenDecimals));
File: tap-token-audit/contracts/tokens/TapOFT.sol
/// @audit 1e18
/// @audit 15_000_000
121: _mint(_contributors, 1e18 * 15_000_000);
/// @audit 1e18
/// @audit 3_686_595
122: _mint(_earlySupporters, 1e18 * 3_686_595);
/// @audit 1e18
/// @audit 12_500_000
123: _mint(_supporters, 1e18 * 12_500_000);
/// @audit 1e18
/// @audit 5_000_000
124: _mint(_lbp, 1e18 * 5_000_000);
/// @audit 1e18
/// @audit 8_000_000
125: _mint(_dao, 1e18 * 8_000_000);
/// @audit 1e18
/// @audit 2_500_000
126: _mint(_airdrop, 1e18 * 2_500_000);
/// @audit 8
117: ) BaseTapOFT("TapOFT", "TAP", 8, _lzEndpoint) ERC20Permit("TapOFT") {
File: tap-token-audit/contracts/twAML.sol
/// @audit 1
76: twos := add(div(sub(0, twos), twos), 1)
/// @audit 3
86: uint256 inv = (3 * denominator) ^ 2;
/// @audit 1e4
120: return mul >= 1e4 ? mul / 1e4 : _totalWeight;
/// @audit 3
148: if (y > 3) {
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2.sol
/// @audit 4
233: WrapData memory data = abi.decode(_action.call[4:], (WrapData));
/// @audit 4
257: _action.call[4:],
/// @audit 4
277: _action.call[4:],
/// @audit 4
297: _action.call[4:],
/// @audit 4
311: _action.call[4:],
/// @audit 4
337: _action.call[4:],
/// @audit 4
369: _action.call[4:],
/// @audit 4
386: _action.call[4:],
/// @audit 4
412: _action.call[4:],
/// @audit 4
449: _action.call[4:],
/// @audit 4
477: _action.call[4:],
/// @audit 4
503: _action.call[4:],
/// @audit 4
530: _action.call[4:],
/// @audit 4
557: _action.call[4:],
/// @audit 4
586: _action.call[4:],
/// @audit 4
603: _action.call[4:],
/// @audit 4
624: _action.call[4:],
/// @audit 4
638: _action.call[4:],
/// @audit 4
651: _action.call[4:],
/// @audit 4
663: _action.call[4:],
/// @audit 4
679: _action.call[4:],
/// @audit 4
695: _action.call[4:],
/// @audit 4
1033: actionCalldata[4:],
/// @audit 4
1039: actionCalldata[4:],
/// @audit 68
1080: if (_returnData.length < 68) revert("MagnetarV2: Reason unknown");
/// @audit 0x04
1084: _returnData := add(_returnData, 0x04)
File: tapioca-periph-audit/contracts/Multicall/Multicall3.sol
/// @audit 68
96: if (_returnData.length < 68) revert("Reason unknown");
/// @audit 0x04
100: _returnData := add(_returnData, 0x04)
File: tapioca-periph-audit/contracts/oracle/implementations/ARBTriCryptoOracle.sol
/// @audit 1e10
121: uint256 _btcPrice = uint256(BTC_FEED.latestAnswer()) * 1e10;
/// @audit 1e10
122: uint256 _wbtcPrice = uint256(WBTC_FEED.latestAnswer()) * 1e10;
/// @audit 1e10
123: uint256 _ethPrice = uint256(ETH_FEED.latestAnswer()) * 1e10;
/// @audit 1e10
124: uint256 _usdtPrice = uint256(USDT_FEED.latestAnswer()) * 1e10;
/// @audit 1e18
126: uint256 _minWbtcPrice = (_wbtcPrice < 1e18)
/// @audit 1e18
127: ? (_wbtcPrice * _btcPrice) / 1e18
/// @audit 3
132: _maxPrice = (3 * _vp * FixedPointMathLib.cbrt(_basePrices)) / 1 ether;
/// @audit 1e34
137: uint256 _discount = Math.max((_g ** 2 / 1 ether) * _a, 1e34); // handle qbrt nonconvergence
File: tapioca-periph-audit/contracts/Swapper/BaseSwapper.sol
/// @audit 0x095ea7b3
100: abi.encodeWithSelector(0x095ea7b3, to, value)
File: tapioca-periph-audit/contracts/Swapper/UniswapV3Swapper.sol
/// @audit 60
97: (int24 tick, ) = OracleLibrary.consult(pool, 60);
/// @audit 60
126: (int24 tick, ) = OracleLibrary.consult(pool, 60);
File: tapioca-periph-audit/contracts/TapiocaDeployer/TapiocaDeployer.sol
/// @audit 0x20
41: addr := create2(amount, add(bytecode, 0x20), mload(bytecode), salt)
/// @audit 0x40
74: let ptr := mload(0x40) // Get free memory pointer
/// @audit 0x40
86: mstore(add(ptr, 0x40), bytecodeHash)
/// @audit 0x20
87: mstore(add(ptr, 0x20), salt)
/// @audit 0x0b
89: let start := add(ptr, 0x0b) // The hashed data starts at the final garbage byte which we will set to 0xff
/// @audit 0xff
90: mstore8(start, 0xff)
/// @audit 85
91: addr := keccak256(start, 85)
File: tapioca-yieldbox-strategies-audit/contracts/aave/AaveStrategy.sol
/// @audit 50
/// @audit 10_000
113: result = result - (result * 50) / 10_000; //0.5%
/// @audit 12
170: bool daysPassed = (currentCooldown + 12 days) < block.timestamp;
/// @audit 50
/// @audit 10_000
193: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
/// @audit 50
/// @audit 10_000
122: toWithdraw = toWithdraw - (toWithdraw * 50) / 10_000; //0.5%
/// @audit 50
/// @audit 10_000
177: bptOut = bptOut - (bptOut * 50) / 10_000; //0.5%
/// @audit 250
/// @audit 10_000
250: bptIn = bptIn + (bptIn * 250) / 10_000; //2.5%
File: tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
/// @audit 18
116: uint256 invested = (shares * pricePerShare) / (10 ** 18);
/// @audit 18
146: uint256 toWithdraw = (((amount - queued) * (10 ** 18)) /
File: tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
/// @audit 50
/// @audit 10_000
143: result = result - (result * 50) / 10_000; //0.5%
/// @audit 50
/// @audit 10_000
154: uint256 minAmount = (calcWithdraw * 50) / 10_000; //0.5%
/// @audit 50
/// @audit 10_000
207: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
/// @audit 1e18
312: if (calcAmount >= 1e18) {
/// @audit 50
/// @audit 10_000
313: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
/// @audit 50
/// @audit 10_000
336: uint256 minAmount = calcWithdraw - (calcWithdraw * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
/// @audit 50
/// @audit 10_000
179: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
/// @audit 50
/// @audit 10_000
186: minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
/// @audit 50
/// @audit 10_000
116: result = result - (result * 50) / 10_000; //0.5%
/// @audit 50
/// @audit 10_000
170: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
/// @audit 50
/// @audit 10_000
188: uint256 minAmount = calcWithdraw - (calcWithdraw * 50) / 10_000; //0.5%
/// @audit 50
/// @audit 10_000
232: uint256 minAmount = calcWithdraw - (calcWithdraw * 50) / 10_000; //0.5%
/// @audit 50
/// @audit 10_000
249: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/glp/GlpStrategy.sol
/// @audit 10_000
171: uint256 fee = (wethAmount * FEE_BPS) / 10_000;
/// @audit 20
310: uint256 buffer = (freeEsGmx + stakedEsGmx) / 20;
File: tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
/// @audit 50
/// @audit 10_000
108: uint256 minAmount = (toWithdraw * 50) / 10_000; //0.5%
/// @audit 250
/// @audit 10_000
151: uint256 minAmount = toWithdraw - (toWithdraw * 250) / 10_000; //2.5%
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
/// @audit 50
/// @audit 10_000
133: result = result - (result * 50) / 10_000; //0.5%
/// @audit 50
/// @audit 10_000
182: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: YieldBox/contracts/YieldBoxRebase.sol
/// @audit 1e8
29: totalShares_ += 1e8;
/// @audit 1e8
52: totalShares_ += 1e8;
File: YieldBox/contracts/YieldBoxURIBuilder.sol
/// @audit 20
37: uint256(uint160(asset.contractAddress)).toHexString(20),
/// @audit 20
90: abi.encodePacked("ERC1155:", uint256(uint160(asset.contractAddress)).toHexString(20), "/", asset.tokenId.toString())
/// @audit 20
106: ? abi.encodePacked(',"tokenAddress":"', uint256(uint160(asset.contractAddress)).toHexString(20), '"')
/// @audit 20
124: uint256(uint160(address(asset.strategy))).toHexString(20),
Index event fields make the field more quickly accessible to off-chain tools that parse events. This is especially useful when it comes to filtering based on an address. However, note that each index field costs extra gas during emission, so it's not necessarily best to index the maximum allowed per event (three fields). Where applicable, each event
should use three indexed
fields if there are three or more fields, and gas usage is not particularly of concern for the events in question. If there are fewer than three applicable fields, all of the applicable fields should be indexed.
There are 22 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/Market.sol
102 event Liquidated(
103 address liquidator,
104 address[] users,
105 uint256 liquidatorReward,
106 uint256 protocolReward,
107 uint256 repayedAmount,
108 uint256 collateralShareRemoved
109: );
File: tapioca-bar-audit/contracts/markets/singularity/SGLStorage.sol
136: event BidExecutionSwapperUpdated(address newAddress);
138: event UsdoSwapperUpdated(address newAddress);
File: tapioca-bar-audit/contracts/Penrose.sol
140 event RegisterSingularityMasterContract(
141 address location,
142 IPenrose.ContractType risk
143: );
145 event RegisterBigBangMasterContract(
146 address location,
147 IPenrose.ContractType risk
148: );
150: event RegisterSingularity(address location, address masterContract);
152: event RegisterBigBang(address location, address masterContract);
154: event FeeToUpdate(address newFeeTo);
156: event SwapperUpdate(address swapper, bool isRegistered);
158: event UsdoTokenUpdated(address indexed usdoToken, uint256 assetId);
File: tapiocaz-audit/contracts/Balancer.sol
69 event ConnectedChainUpdated(
70 address indexed _srcOft,
71 uint16 _dstChainId,
72 address indexed _dstOft
73: );
76 event Rebalanced(
77 address indexed _srcOft,
78 uint16 _dstChainId,
79 uint256 _slippage,
80 uint256 _amount,
81 bool _isNative
82: );
84 event RebalanceAmountUpdated(
85 address _srcOft,
86 uint16 _dstChainId,
87 uint256 _amount,
88 uint256 _totalAmount
89: );
File: tap-token-audit/contracts/governance/twTAP.sol
144: event ExitPosition(uint256 tokenId, uint256 amount);
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
115: event Participate(uint256 indexed epoch, uint256 aoTAPTokenID);
File: tap-token-audit/contracts/options/TapiocaOptionLiquidityProvision.sol
94: event SetSGLPoolWeight(address sgl, uint256 poolWeight);
95: event RegisterSingularity(address sgl, uint256 assetID);
96: event UnregisterSingularity(address sgl, uint256 assetID);
File: tap-token-audit/contracts/tokens/BaseTapOFT.sol
41: event CallFailedStr(uint16 _srcChainId, bytes _payload, string _reason);
42: event CallFailedBytes(uint16 _srcChainId, bytes _payload, bytes _reason);
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2Storage.sol
331: event ApprovalForAll(address owner, address operator, bool approved);
File: YieldBox/contracts/NativeTokenFactory.sol
28: event TokenCreated(address indexed creator, string name, string symbol, uint8 decimals, uint256 tokenId);
The compiler will inline the function, which will avoid JUMP
instructions usually associated with functions
There are 33 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
391: require(penrose.swappers(swapper), "SGL: Invalid swapper");
413: require(amountOut >= minAmountOut, "SGL: not enough");
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
167: require(srcBalance >= amount, "ERC20: balance too low");
179: require(to != address(0), "ERC20: no zero address"); // Moved down so other failed calls safe some gas
File: tapioca-bar-audit/contracts/markets/singularity/SGLLeverage.sol
65 require(
66 penrose.swappers(ISwapper(externalData.swapper)),
67 "SGL: Invalid swapper"
68: );
155: require(penrose.swappers(swapper), "SGL: Invalid swapper");
182: require(amountOut >= minAmountOut, "SGL: not enough");
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
640: revert(_getRevertMsg(returnData));
File: tapioca-bar-audit/contracts/usd0/modules/USDOLeverageModule.sol
284: revert(reason);
File: tapioca-bar-audit/contracts/usd0/modules/USDOMarketModule.sol
273: revert(reason);
File: tapioca-bar-audit/contracts/usd0/modules/USDOOptionsModule.sol
274: revert(reason);
File: tapioca-bar-audit/contracts/usd0/USDO.sol
87: require(token == address(this), "USDO: token not valid");
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTLeverageModule.sol
314: revert(reason);
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTMarketModule.sol
290: revert(reason);
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTOptionsModule.sol
289: revert(reason);
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTStrategyModule.sol
98: require(amount > 0, "TOFT_0");
File: tapiocaz-audit/contracts/tOFT/mTapiocaOFT.sol
106: require(!balancers[msg.sender], "TOFT_auth");
File: tap-token-audit/contracts/governance/twTAP.sol
390: require(msg.sender == address(tapOFT), "twTAP: only tapOFT");
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
233: require(aoTapOption.expiry > block.timestamp, "adb: Option expired");
242 require(
243 paymentTokenOracle.oracle != IOracle(address(0)),
244 "adb: Payment token not supported"
245: );
255: require(eligibleTapAmount >= _tapAmount, "adb: Too high");
467: require(_eligibleAmount > 0, "adb: Not eligible");
File: tap-token-audit/contracts/option-airdrop/aoTAP.sol
129 require(
130 _isApprovedOrOwner(msg.sender, _tokenId),
131 "AOTAP: only approved or owner"
132: );
File: tap-token-audit/contracts/options/oTAP.sol
116 require(
117 _isApprovedOrOwner(msg.sender, _tokenId),
118 "OTAP: only approved or owner"
119: );
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
368 require(
369 paymentTokenOracle.oracle != IOracle(address(0)),
370 "tOB: Payment token not supported"
371: );
376: require(isPositionActive, "tOB: Option expired");
388: require(eligibleTapAmount >= _tapAmount, "tOB: Too high");
File: tap-token-audit/contracts/tokens/BaseTapOFT.sol
307: require(twTap.ownerOf(tokenID) == to, "TapOFT: Not owner");
File: YieldBox/contracts/NativeTokenFactory.sol
139: require(assets[tokenId].tokenType == TokenType.Native, "NTF: Not native");
File: YieldBox/contracts/YieldBoxPermit.sol
80: require(block.timestamp <= deadline, "YieldBoxPermit: expired deadline");
87: require(signer == owner, "YieldBoxPermit: invalid signature");
File: YieldBox/contracts/YieldBox.sol
382: require(operator != address(0), "YieldBox: operator not set"); // Important for security
383: require(operator != address(this), "YieldBox: can't approve yieldBox");
This project's specific package versions are vulnerable to the specific CVEs listed below. Consider switching to more recent versions of these packages that don't have these vulnerabilities
There are 6 instances of this issue:
File: Various Files
/// @audit Vulnerabilities:
///
- CVE-2022-34338 - MEDIUM - (@types/node >=21.0.0 <21.0.3) - IBM Robotic Process Automation 21.0.0, 21.0.1, and 21.0.2 could disclose sensitive information due to improper privilege management for storage provider types. IBM X-Force ID: 229962.
File: Various Files
/// @audit Vulnerabilities:
///
- CVE-2022-34338 - MEDIUM - (@types/node >=21.0.0 <21.0.3) - IBM Robotic Process Automation 21.0.0, 21.0.1, and 21.0.2 could disclose sensitive information due to improper privilege management for storage provider types. IBM X-Force ID: 229962.
File: Various Files
/// @audit Vulnerabilities:
///
- CVE-2022-34338 - MEDIUM - (@types/node >=21.0.0 <21.0.3) - IBM Robotic Process Automation 21.0.0, 21.0.1, and 21.0.2 could disclose sensitive information due to improper privilege management for storage provider types. IBM X-Force ID: 229962.
File: Various Files
/// @audit Vulnerabilities:
///
- CVE-2022-34338 - MEDIUM - (@types/node >=21.0.0 <21.0.3) - IBM Robotic Process Automation 21.0.0, 21.0.1, and 21.0.2 could disclose sensitive information due to improper privilege management for storage provider types. IBM X-Force ID: 229962.
File: Various Files
/// @audit Vulnerabilities:
///
- CVE-2022-34338 - MEDIUM - (@types/node >=21.0.0 <21.0.3) - IBM Robotic Process Automation 21.0.0, 21.0.1, and 21.0.2 could disclose sensitive information due to improper privilege management for storage provider types. IBM X-Force ID: 229962.
File: Various Files
/// @audit Vulnerabilities:
///
- CVE-2022-34338 - MEDIUM - (@types/node >=21.0.0 <21.0.3) - IBM Robotic Process Automation 21.0.0, 21.0.1, and 21.0.2 could disclose sensitive information due to improper privilege management for storage provider types. IBM X-Force ID: 229962.
Using import declarations of the form import {<identifier_name>} from "some/file.sol"
avoids polluting the symbol namespace making flattened files smaller, and speeds up compilation (but does not save any gas)
There are 345 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
5: import "@boringcrypto/boring-solidity/contracts/ERC20.sol";
7: import "tapioca-periph/contracts/interfaces/IBigBang.sol";
8: import "tapioca-periph/contracts/interfaces/ISendFrom.sol";
9: import "tapioca-periph/contracts/interfaces/ISwapper.sol";
12: import "../Market.sol";
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
6: import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
File: tapioca-bar-audit/contracts/markets/Market.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
5: import "@boringcrypto/boring-solidity/contracts/libraries/BoringRebase.sol";
7: import "tapioca-sdk/dist/contracts/YieldBox/contracts/YieldBox.sol";
8: import "tapioca-periph/contracts/interfaces/IOracle.sol";
9: import "tapioca-periph/contracts/interfaces/IPenrose.sol";
10: import "./MarketERC20.sol";
File: tapioca-bar-audit/contracts/markets/singularity/SGLBorrow.sol
4: import "./SGLLendingCommon.sol";
File: tapioca-bar-audit/contracts/markets/singularity/SGLCollateral.sol
4: import "./SGLLendingCommon.sol";
File: tapioca-bar-audit/contracts/markets/singularity/SGLCommon.sol
4: import "./SGLStorage.sol";
File: tapioca-bar-audit/contracts/markets/singularity/SGLLendingCommon.sol
4: import "./SGLCommon.sol";
File: tapioca-bar-audit/contracts/markets/singularity/SGLLeverage.sol
4: import "./SGLLendingCommon.sol";
File: tapioca-bar-audit/contracts/markets/singularity/SGLLiquidation.sol
4: import "./SGLCommon.sol";
File: tapioca-bar-audit/contracts/markets/singularity/SGLStorage.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
5: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
6: import "@boringcrypto/boring-solidity/contracts/libraries/BoringRebase.sol";
8: import "tapioca-periph/contracts/interfaces/ISwapper.sol";
9: import "tapioca-periph/contracts/interfaces/IPenrose.sol";
10: import "tapioca-periph/contracts/interfaces/ISingularity.sol";
11: import "tapioca-periph/contracts/interfaces/ILiquidationQueue.sol";
12: import "tapioca-sdk/dist/contracts/YieldBox/contracts/YieldBox.sol";
14: import "../Market.sol";
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
4: import "./SGLCommon.sol";
5: import "./SGLLiquidation.sol";
6: import "./SGLCollateral.sol";
7: import "./SGLBorrow.sol";
8: import "./SGLLeverage.sol";
10: import "tapioca-periph/contracts/interfaces/ISendFrom.sol";
11: import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";
File: tapioca-bar-audit/contracts/Penrose.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
5: import "@boringcrypto/boring-solidity/contracts/BoringFactory.sol";
7: import "tapioca-sdk/dist/contracts/YieldBox/contracts/YieldBox.sol";
8: import "tapioca-sdk/dist/contracts/YieldBox/contracts/interfaces/IYieldBox.sol";
9: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/ERC20WithoutStrategy.sol";
10: import "tapioca-periph/contracts/interfaces/ISingularity.sol";
11: import "tapioca-periph/contracts/interfaces/IPenrose.sol";
File: tapioca-bar-audit/contracts/usd0/BaseUSDO.sol
5: import "tapioca-sdk/dist/contracts/token/oft/v2/OFTV2.sol";
8: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
9: import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
12: import "tapioca-periph/contracts/interfaces/IYieldBoxBase.sol";
14: import "tapioca-periph/contracts/interfaces/ICommonData.sol";
16: import "./BaseUSDOStorage.sol";
17: import "./modules/USDOLeverageModule.sol";
18: import "./modules/USDOMarketModule.sol";
19: import "./modules/USDOOptionsModule.sol";
File: tapioca-bar-audit/contracts/usd0/BaseUSDOStorage.sol
5: import "tapioca-sdk/dist/contracts/token/oft/v2/OFTV2.sol";
8: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
9: import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
12: import "tapioca-periph/contracts/interfaces/IYieldBoxBase.sol";
File: tapioca-bar-audit/contracts/usd0/modules/USDOLeverageModule.sol
5: import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";
9: import "tapioca-periph/contracts/interfaces/ISwapper.sol";
10: import "tapioca-periph/contracts/interfaces/ITapiocaOFT.sol";
11: import "tapioca-periph/contracts/interfaces/ISingularity.sol";
12: import "tapioca-periph/contracts/interfaces/IPermitBorrow.sol";
13: import "tapioca-periph/contracts/interfaces/IPermitAll.sol";
15: import "../BaseUSDOStorage.sol";
File: tapioca-bar-audit/contracts/usd0/modules/USDOMarketModule.sol
5: import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringRebase.sol";
10: import "tapioca-periph/contracts/interfaces/ITapiocaOFT.sol";
11: import "tapioca-periph/contracts/interfaces/IMagnetar.sol";
12: import "tapioca-periph/contracts/interfaces/IMarket.sol";
13: import "tapioca-periph/contracts/interfaces/ISingularity.sol";
14: import "tapioca-periph/contracts/interfaces/IPermitBorrow.sol";
15: import "tapioca-periph/contracts/interfaces/IPermitAll.sol";
17: import "../BaseUSDOStorage.sol";
File: tapioca-bar-audit/contracts/usd0/modules/USDOOptionsModule.sol
5: import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";
8: import "tapioca-periph/contracts/interfaces/IPermitBorrow.sol";
9: import "tapioca-periph/contracts/interfaces/IPermitAll.sol";
10: import "tapioca-periph/contracts/interfaces/ITapiocaOptionsBroker.sol";
11: import "tapioca-periph/contracts/interfaces/ISendFrom.sol";
12: import "../BaseUSDOStorage.sol";
File: tapioca-bar-audit/contracts/usd0/USDO.sol
4: import "tapioca-sdk/dist/contracts/interfaces/ILayerZeroEndpoint.sol";
5: import "tapioca-periph/contracts/interfaces/IERC3156FlashLender.sol";
6: import "./BaseUSDO.sol";
File: tapiocaz-audit/contracts/Balancer.sol
4: import "tapioca-periph/contracts/interfaces/ITapiocaOFT.sol";
5: import "tapioca-periph/contracts/interfaces/IStargateRouter.sol";
6: import "@rari-capital/solmate/src/auth/Owned.sol";
7: import "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
File: tapiocaz-audit/contracts/TapiocaWrapper.sol
4: import "./tOFT/TapiocaOFT.sol";
5: import "./tOFT/mTapiocaOFT.sol";
6: import "tapioca-periph/contracts/interfaces/ITapiocaOFT.sol";
8: import "@openzeppelin/contracts/utils/Create2.sol";
9: import "@openzeppelin/contracts/access/Ownable.sol";
File: tapiocaz-audit/contracts/tOFT/BaseTOFT.sol
4: import "./BaseTOFTStorage.sol";
7: import "./modules/BaseTOFTLeverageModule.sol";
8: import "./modules/BaseTOFTStrategyModule.sol";
9: import "./modules/BaseTOFTMarketModule.sol";
10: import "./modules/BaseTOFTOptionsModule.sol";
File: tapiocaz-audit/contracts/tOFT/BaseTOFTStorage.sol
5: import "tapioca-sdk/dist/contracts/token/oft/v2/OFTV2.sol";
6: import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";
9: import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
10: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
11: import "@openzeppelin/contracts/utils/introspection/ERC165.sol";
14: import "tapioca-periph/contracts/interfaces/IYieldBoxBase.sol";
15: import "tapioca-periph/contracts/interfaces/ITapiocaOFT.sol";
16: import "tapioca-periph/contracts/interfaces/ICommonData.sol";
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTLeverageModule.sol
5: import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";
9: import "tapioca-periph/contracts/interfaces/ISwapper.sol";
10: import "tapioca-periph/contracts/interfaces/IMagnetar.sol";
11: import "tapioca-periph/contracts/interfaces/ISingularity.sol";
12: import "tapioca-periph/contracts/interfaces/IPermitBorrow.sol";
13: import "tapioca-periph/contracts/interfaces/IPermitAll.sol";
14: import "tapioca-periph/contracts/interfaces/ITapiocaOptionsBroker.sol";
15: import "tapioca-periph/contracts/interfaces/ITapiocaOptionLiquidityProvision.sol";
17: import "../BaseTOFTStorage.sol";
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTMarketModule.sol
5: import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";
9: import "tapioca-periph/contracts/interfaces/ISwapper.sol";
10: import "tapioca-periph/contracts/interfaces/ITapiocaOFT.sol";
11: import "tapioca-periph/contracts/interfaces/IMagnetar.sol";
12: import "tapioca-periph/contracts/interfaces/IMarket.sol";
13: import "tapioca-periph/contracts/interfaces/IPermitBorrow.sol";
14: import "tapioca-periph/contracts/interfaces/IPermitAll.sol";
16: import "../BaseTOFTStorage.sol";
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTOptionsModule.sol
5: import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";
8: import "tapioca-periph/contracts/interfaces/IPermitBorrow.sol";
9: import "tapioca-periph/contracts/interfaces/IPermitAll.sol";
10: import "tapioca-periph/contracts/interfaces/ITapiocaOptionsBroker.sol";
12: import "../BaseTOFTStorage.sol";
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTStrategyModule.sol
5: import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";
9: import "tapioca-periph/contracts/interfaces/ISwapper.sol";
10: import "tapioca-periph/contracts/interfaces/ITapiocaOFT.sol";
12: import "../BaseTOFTStorage.sol";
File: tapiocaz-audit/contracts/tOFT/mTapiocaOFT.sol
3: import "./BaseTOFT.sol";
File: tapiocaz-audit/contracts/tOFT/TapiocaOFT.sol
3: import "./BaseTOFT.sol";
File: tap-token-audit/contracts/governance/twTAP.sol
6: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
7: import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
8: import "tapioca-sdk/dist/contracts/util/ERC4494.sol";
9: import "../tokens/TapOFT.sol";
10: import "../twAML.sol";
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
4: import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol";
5: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
6: import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
7: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
8: import "@openzeppelin/contracts/security/Pausable.sol";
9: import "tapioca-periph/contracts/interfaces/IOracle.sol";
10: import "../tokens/TapOFT.sol";
11: import "../twAML.sol";
12: import "./aoTAP.sol";
File: tap-token-audit/contracts/option-airdrop/aoTAP.sol
5: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
6: import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
7: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
9: import "tapioca-sdk/dist/contracts/util/ERC4494.sol";
File: tap-token-audit/contracts/options/oTAP.sol
5: import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
6: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
7: import "tapioca-sdk/dist/contracts/util/ERC4494.sol";
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
5: import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
6: import "@openzeppelin/contracts/security/Pausable.sol";
7: import "tapioca-periph/contracts/interfaces/IOracle.sol";
8: import "./TapiocaOptionLiquidityProvision.sol";
9: import "../tokens/TapOFT.sol";
10: import "../twAML.sol";
11: import "./oTAP.sol";
File: tap-token-audit/contracts/options/TapiocaOptionLiquidityProvision.sol
5: import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
7: import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
8: import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
9: import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
10: import "@openzeppelin/contracts/security/Pausable.sol";
11: import "tapioca-sdk/dist/contracts/util/ERC4494.sol";
12: import "tapioca-sdk/dist/contracts/YieldBox/contracts/interfaces/IYieldBox.sol";
File: tap-token-audit/contracts/tokens/BaseTapOFT.sol
5: import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
7: import "tapioca-periph/contracts/interfaces/ITapiocaOFT.sol";
8: import "tapioca-sdk/dist/contracts/token/oft/v2/OFTV2.sol";
File: tap-token-audit/contracts/tokens/LTap.sol
4: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
5: import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
File: tap-token-audit/contracts/tokens/TapOFT.sol
5: import "./BaseTapOFT.sol";
File: tap-token-audit/contracts/Vesting.sol
4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
5: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2.sol
5: import "@openzeppelin/contracts/access/Ownable.sol";
6: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
9: import "./MagnetarV2Storage.sol";
10: import "./modules/MagnetarMarketModule.sol";
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2Storage.sol
5: import "@boringcrypto/boring-solidity/contracts/libraries/BoringRebase.sol";
8: import "../interfaces/IOracle.sol";
9: import "../interfaces/ISingularity.sol";
10: import "../interfaces/IBigBang.sol";
11: import "../interfaces/ITapiocaOFT.sol";
12: import "../interfaces/ISwapper.sol";
13: import "../interfaces/ITapiocaOptionsBroker.sol";
14: import "../interfaces/ITapiocaOptionLiquidityProvision.sol";
15: import "../interfaces/IPenrose.sol";
16: import "../interfaces/ITapiocaOptionsBroker.sol";
21: import "tapioca-sdk/dist/contracts/YieldBox/contracts/enums/YieldBoxTokenType.sol";
File: tapioca-periph-audit/contracts/Magnetar/modules/MagnetarMarketModule.sol
5: import "tapioca-sdk/dist/contracts/libraries/LzLib.sol";
8: import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
9: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
10: import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
13: import "../../interfaces/IYieldBoxBase.sol";
14: import "../../interfaces/ITapiocaOptions.sol";
16: import "../MagnetarV2Storage.sol";
File: tapioca-periph-audit/contracts/Multicall/Multicall3.sol
4: import "@openzeppelin/contracts/access/Ownable.sol";
File: tapioca-periph-audit/contracts/oracle/Seer.sol
4: import "./OracleMulti.sol";
File: tapioca-periph-audit/contracts/Swapper/BaseSwapper.sol
4: import "@openzeppelin/contracts/access/Ownable.sol";
5: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
7: import "tapioca-sdk/dist/contracts/YieldBox/contracts/interfaces/IYieldBox.sol";
9: import "../interfaces/ISwapper.sol";
File: tapioca-periph-audit/contracts/Swapper/CurveSwapper.sol
4: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
5: import "./interfaces/ICurvePool.sol";
6: import "./BaseSwapper.sol";
File: tapioca-periph-audit/contracts/Swapper/UniswapV2Swapper.sol
4: import "./interfaces/IUniswapV2Factory.sol";
5: import "./interfaces/IUniswapV2Router02.sol";
6: import "./BaseSwapper.sol";
File: tapioca-periph-audit/contracts/Swapper/UniswapV3Swapper.sol
4: import "@uniswap/v3-periphery/contracts/interfaces/ISwapRouter.sol";
5: import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
6: import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Factory.sol";
7: import "@uniswap/v3-periphery/contracts/libraries/TransferHelper.sol";
8: import "@uniswap/v3-periphery/contracts/interfaces/IQuoterV2.sol";
9: import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
11: import "./libraries/OracleLibrary.sol";
12: import "./BaseSwapper.sol";
File: tapioca-yieldbox-strategies-audit/contracts/aave/AaveStrategy.sol
4: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
10: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/BaseStrategy.sol";
11: import "../../tapioca-periph/contracts/interfaces/ISwapper.sol";
12: import "./interfaces/IStkAave.sol";
13: import "./interfaces/ILendingPool.sol";
14: import "./interfaces/IIncentivesController.sol";
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
4: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
10: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/BaseStrategy.sol";
11: import "./interfaces/IBalancerVault.sol";
12: import "./interfaces/IBalancerPool.sol";
13: import "./interfaces/IBalancerHelpers.sol";
File: tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
4: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
10: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/BaseStrategy.sol";
12: import "../../tapioca-periph/contracts/interfaces/INative.sol";
13: import "./interfaces/ICToken.sol";
File: tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
4: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
10: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/BaseStrategy.sol";
11: import "../../tapioca-periph/contracts/interfaces/ISwapper.sol";
12: import "../curve/interfaces/ITricryptoLPGetter.sol";
14: import "./interfaces/IConvexBooster.sol";
15: import "./interfaces/IConvexRewardPool.sol";
16: import "./interfaces/IConvexZap.sol";
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
4: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
10: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/BaseStrategy.sol";
11: import "../../tapioca-periph/contracts/interfaces/ISwapper.sol";
13: import "./interfaces/ITricryptoLPGetter.sol";
14: import "./interfaces/ITricryptoLPGauge.sol";
15: import "./interfaces/ICurveMinter.sol";
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
4: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
10: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/BaseStrategy.sol";
11: import "../../tapioca-periph/contracts/interfaces/ISwapper.sol";
13: import "./interfaces/ITricryptoLPGetter.sol";
14: import "./interfaces/ITricryptoLPGauge.sol";
15: import "./interfaces/ICurveMinter.sol";
File: tapioca-yieldbox-strategies-audit/contracts/glp/GlpStrategy.sol
5: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
6: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
7: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
9: import "@uniswap/v3-core/contracts/interfaces/IUniswapV3Pool.sol";
11: import "tapioca-sdk/dist/contracts/YieldBox/contracts/enums/YieldBoxTokenType.sol";
12: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/BaseStrategy.sol";
14: import "../interfaces/IFeeCollector.sol";
15: import "../interfaces/gmx/IGlpManager.sol";
16: import "../interfaces/gmx/IGmxRewardDistributor.sol";
17: import "../interfaces/gmx/IGmxRewardRouter.sol";
18: import "../interfaces/gmx/IGmxRewardTracker.sol";
19: import "../interfaces/gmx/IGmxVester.sol";
20: import "../interfaces/gmx/IGmxVault.sol";
File: tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
4: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
10: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/BaseStrategy.sol";
12: import "./interfaces/IStEth.sol";
13: import "./interfaces/ICurveEthStEthPool.sol";
14: import "../../tapioca-periph/contracts/interfaces/INative.sol";
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
4: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
10: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/BaseStrategy.sol";
11: import "../../tapioca-periph/contracts/interfaces/ISwapper.sol";
13: import "./interfaces/IRouter.sol";
14: import "./interfaces/IRouterETH.sol";
15: import "./interfaces/ILPStaking.sol";
16: import "../../tapioca-periph/contracts/interfaces/INative.sol";
File: tapioca-yieldbox-strategies-audit/contracts/yearn/YearnStrategy.sol
4: import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
6: import "@boringcrypto/boring-solidity/contracts/BoringOwnable.sol";
7: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC20.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
10: import "tapioca-sdk/dist/contracts/YieldBox/contracts/strategies/BaseStrategy.sol";
12: import "./interfaces/IYearnVault.sol";
File: YieldBox/contracts/NativeTokenFactory.sol
3: import "./AssetRegister.sol";
4: import "./BoringMath.sol";
File: YieldBox/contracts/YieldBoxPermit.sol
5: import "@openzeppelin/contracts/utils/cryptography/EIP712.sol";
6: import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
7: import "@openzeppelin/contracts/utils/Counters.sol";
8: import "./interfaces/IYieldBox.sol";
File: YieldBox/contracts/YieldBoxRebase.sol
5: import "./interfaces/IStrategy.sol";
6: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC1155.sol";
7: import "@boringcrypto/boring-solidity/contracts/libraries/Base64.sol";
8: import "@boringcrypto/boring-solidity/contracts/libraries/BoringAddress.sol";
9: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
10: import "@boringcrypto/boring-solidity/contracts/Domain.sol";
11: import "./ERC1155TokenReceiver.sol";
12: import "./ERC1155.sol";
13: import "@boringcrypto/boring-solidity/contracts/BoringBatchable.sol";
14: import "@boringcrypto/boring-solidity/contracts/BoringFactory.sol";
File: YieldBox/contracts/YieldBox.sol
26: import "./interfaces/IWrappedNative.sol";
27: import "./interfaces/IStrategy.sol";
28: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC721.sol";
29: import "@boringcrypto/boring-solidity/contracts/interfaces/IERC1155.sol";
30: import "@boringcrypto/boring-solidity/contracts/libraries/Base64.sol";
31: import "@boringcrypto/boring-solidity/contracts/Domain.sol";
32: import "./ERC721TokenReceiver.sol";
33: import "./ERC1155TokenReceiver.sol";
34: import "./ERC1155.sol";
35: import "@boringcrypto/boring-solidity/contracts/BoringBatchable.sol";
36: import "@openzeppelin/contracts/utils/Strings.sol";
37: import "./AssetRegister.sol";
38: import "./NativeTokenFactory.sol";
39: import "./YieldBoxRebase.sol";
40: import "./YieldBoxURIBuilder.sol";
41: import "./YieldBoxPermit.sol";
File: YieldBox/contracts/YieldBoxURIBuilder.sol
3: import "@openzeppelin/contracts/utils/Strings.sol";
4: import "@boringcrypto/boring-solidity/contracts/libraries/Base64.sol";
5: import "@boringcrypto/boring-solidity/contracts/libraries/BoringERC20.sol";
6: import "./interfaces/IYieldBox.sol";
7: import "./NativeTokenFactory.sol";
Not all IERC20
implementations revert()
when there's a failure in approve()
. The function signature has a boolean
return value and they indicate errors that way instead. By not checking the return value, operations that should have marked as failed, may potentially go through without actually approving anything
There are 45 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/usd0/modules/USDOLeverageModule.sol
217: IERC20(swapData.tokenOut).approve(externalData.tOft, amountOut);
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTLeverageModule.sol
215: IERC20(erc20).approve(externalData.swapper, amount);
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTStrategyModule.sol
184: _erc20.approve(address(yieldBox), _amount);
File: tapioca-periph-audit/contracts/Magnetar/modules/MagnetarMarketModule.sol
157 IERC20(collateralAddress).approve(
158 address(yieldBox),
159 collateralAmount
160: );
234: IERC20(assetAddress).approve(address(yieldBox), depositAmount);
339 IERC20(bbCollateralAddress).approve(
340 address(yieldBox),
341 mintData.collateralDepositData.amount
342: );
386 IERC20(sglAssetAddress).approve(
387 address(yieldBox),
388 depositData.amount
389: );
428: IERC20(address(singularity)).approve(address(yieldBox), fraction);
File: tapioca-yieldbox-strategies-audit/contracts/aave/AaveStrategy.sol
75: wrappedNative.approve(_lendingPool, type(uint256).max);
76: rewardToken.approve(_multiSwapper, type(uint256).max);
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
77: wrappedNative.approve(_vault, type(uint256).max);
78: IERC20(address(pool)).approve(_vault, type(uint256).max);
File: tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
58: wrappedNative.approve(_cToken, type(uint256).max);
File: tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
105: wrappedNative.approve(_lpGetter, type(uint256).max);
106: lpToken.approve(_lpGetter, type(uint256).max);
107: lpToken.approve(_booster, type(uint256).max);
108: rewardToken.approve(_multiSwapper, type(uint256).max);
172: rewardToken.approve(address(swapper), 0);
174: rewardToken.approve(_swapper, type(uint256).max);
181: wrappedNative.approve(address(lpGetter), 0);
183: wrappedNative.approve(_lpGetter, type(uint256).max);
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
79: lpToken.approve(_lpGauge, type(uint256).max);
80: lpToken.approve(_lpGetter, type(uint256).max);
81: rewardToken.approve(_multiSwapper, type(uint256).max);
82: wrappedNative.approve(_lpGetter, type(uint256).max);
143: rewardToken.approve(address(swapper), 0);
144: rewardToken.approve(_swapper, type(uint256).max);
152: wrappedNative.approve(address(lpGetter), 0);
154: wrappedNative.approve(_lpGetter, type(uint256).max);
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
78: IERC20(lpGetter.lpToken()).approve(_lpGauge, type(uint256).max);
79: IERC20(lpGetter.lpToken()).approve(_lpGetter, type(uint256).max);
80: rewardToken.approve(_multiSwapper, type(uint256).max);
81: wrappedNative.approve(_lpGetter, type(uint256).max);
134: rewardToken.approve(address(swapper), 0);
135: rewardToken.approve(_swapper, type(uint256).max);
143: wrappedNative.approve(address(lpGetter), 0);
145: wrappedNative.approve(_lpGetter, type(uint256).max);
File: tapioca-yieldbox-strategies-audit/contracts/glp/GlpStrategy.sol
175: weth.approve(address(glpManager), wethAmount);
File: tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
62: IERC20(_stEth).approve(_curvePool, type(uint256).max);
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
89: stgNative.approve(_lpStaking, type(uint256).max);
90: stgNative.approve(address(router), type(uint256).max);
94: stgTokenReward.approve(_swapper, type(uint256).max);
151: stgTokenReward.approve(address(swapper), 0);
153: stgTokenReward.approve(_swapper, type(uint256).max);
File: tapioca-yieldbox-strategies-audit/contracts/yearn/YearnStrategy.sol
59: wrappedNative.approve(address(vault), type(uint256).max);
Not extending the interface may lead to the wrong function signature being used, leading to unexpected behavior. If the interface is in fact being implemented, use the override
keyword to indicate that fact
There are 9 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
/// @audit IAPWineIBT.transfer(), IAPWineIBT.transferFrom()
24: contract MarketERC20 is IERC20, IERC20Permit, EIP712 {
File: tapioca-bar-audit/contracts/markets/singularity/SGLStorage.sol
/// @audit IAPWineIBT.symbol(), IAPWineIBT.name(), IAPWineIBT.decimals()
34: contract SGLStorage is BoringOwnable, Market {
File: tapioca-bar-audit/contracts/usd0/USDO.sol
/// @audit IAPWineIBT.mint()
24: contract USDO is BaseUSDO, IERC3156FlashLender {
File: tap-token-audit/contracts/option-airdrop/aoTAP.sol
/// @audit IAPWineIBT.burn()
32: contract AOTAP is ERC721, ERC721Permit, BaseBoringBatchable, BoringOwnable {
File: tap-token-audit/contracts/options/oTAP.sol
/// @audit IAPWineIBT.burn()
30: contract OTAP is ERC721, ERC721Permit, BaseBoringBatchable {
File: tap-token-audit/contracts/options/TapiocaOptionLiquidityProvision.sol
/// @audit IERC1155Receiver.onERC1155Received()
48: contract TapiocaOptionLiquidityProvision is
File: tapioca-periph-audit/contracts/oracle/implementations/ARBTriCryptoOracle.sol
/// @audit IAPWineIBT.decimals()
30: contract ARBTriCryptoOracle is ITOracle {
File: tapioca-periph-audit/contracts/oracle/implementations/GLPOracle.sol
/// @audit IAPWineIBT.decimals()
7: contract GLPOracle is IOracle {
File: tapioca-periph-audit/contracts/oracle/implementations/SGOracle.sol
/// @audit IAPWineIBT.decimals()
23: contract SGOracle is IOracle {
[N‑32] override
function arguments that are unused should have the variable name removed or commented out to avoid compiler warnings
There are 5 instances of this issue:
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
427: address to,
428: uint256 amount
432: address from,
433: address to,
434: uint256 amount
If address foo
is being used in an expression such as IERC20 token = FooToken(foo)
, then the more specific cast to FooToken
is a waste because the only thing the compiler will check for is that FooToken
extends IERC20
- it won't check any of the function signatures. Therefore, it makes more sense to do IERC20 token = IERC20(token)
or better yet FooToken token = FooToken(foo)
. The former may allow the file in which it's used to remove the import for FooToken
There are 8 instances of this issue:
File: tapioca-bar-audit/contracts/Penrose.sol
/// @audit uint96 vs uint256
104 tapAssetId = uint96(
105 _yieldBox.registerAsset(
106 TokenType.ERC20,
107 address(tapToken_),
108 emptyStrategies[address(tapToken_)],
109 0
110 )
111: );
/// @audit uint96 vs uint256
122 wethAssetId = uint96(
123 _yieldBox.registerAsset(
124 TokenType.ERC20,
125 address(wethToken_),
126 emptyStrategies[address(wethToken_)],
127 0
128 )
129: );
/// @audit IERC20 vs address
292: usdoToken = IERC20(_usdoToken);
/// @audit uint96 vs uint256
302 usdoAssetId = uint96(
303 yieldBox.registerAsset(
304 TokenType.ERC20,
305 _usdoToken,
306 emptyStrategies[_usdoToken],
307 0
308 )
309: );
/// @audit deploy vs address
373: _contract = deploy(mc, data, useCreate2);
/// @audit deploy vs address
406: _contract = deploy(mc, data, useCreate2);
/// @audit clonesOfCount vs uint256
566: clonesOfLength = clonesOfCount(mcLocation);
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
/// @audit uint128 vs uint256
292: epochTAPValuation = uint128(_epochTAPValuation);
This should especially be done if the new value is not required to be different from the old value
There are 59 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
/// @audit setBigBangConfig()
477: emit MinDebtRateUpdated(minDebtRate, _minDebtRate);
/// @audit setBigBangConfig()
483: emit MaxDebtRateUpdated(maxDebtRate, _maxDebtRate);
/// @audit setBigBangConfig()
488 emit DebtRateAgainstEthUpdated(
489 debtRateAgainstEthMarket,
490 _debtRateAgainstEthMarket
491: );
/// @audit setBigBangConfig()
500 emit LiquidationMultiplierUpdated(
501 liquidationMultiplier,
502 _liquidationMultiplier
503: );
File: tapioca-bar-audit/contracts/markets/Market.sol
/// @audit setBorrowOpeningFee()
144: emit LogBorrowingFee(borrowOpeningFee, _val);
/// @audit setBorrowCap()
152: emit LogBorrowCapUpdated(totalBorrowCap, _cap);
/// @audit setMarketConfig()
173: emit LogBorrowingFee(borrowOpeningFee, _borrowOpeningFee);
/// @audit setMarketConfig()
179: emit OracleUpdated();
/// @audit setMarketConfig()
184: emit OracleDataUpdated();
/// @audit setMarketConfig()
188: emit ConservatorUpdated(conservator, _conservator);
/// @audit setMarketConfig()
229: emit LogBorrowCapUpdated(totalBorrowCap, _totalBorrowCap);
/// @audit updatePause()
248: emit PausedUpdated(paused, val);
/// @audit updateExchangeRate()
346: emit LogExchangeRate(rate);
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
/// @audit setSingularityConfig()
499 emit MinimumTargetUtilizationUpdated(
500 minimumTargetUtilization,
501 _minimumTargetUtilization
502: );
/// @audit setSingularityConfig()
511 emit MaximumTargetUtilizationUpdated(
512 maximumTargetUtilization,
513 _maximumTargetUtilization
514: );
/// @audit setSingularityConfig()
526 emit MinimumInterestPerSecondUpdated(
527 minimumInterestPerSecond,
528 _minimumInterestPerSecond
529: );
/// @audit setSingularityConfig()
538 emit MaximumInterestPerSecondUpdated(
539 maximumInterestPerSecond,
540 _maximumInterestPerSecond
541: );
/// @audit setSingularityConfig()
558 emit LqCollateralizationRateUpdated(
559 lqCollateralizationRate,
560 _lqCollateralizationRate
561: );
/// @audit setSingularityConfig()
567 emit LiquidationMultiplierUpdated(
568 liquidationMultiplier,
569 _liquidationMultiplier
570: );
/// @audit setLiquidationQueueConfig()
587: emit BidExecutionSwapperUpdated(_bidExecutionSwapper);
/// @audit setLiquidationQueueConfig()
592: emit UsdoSwapperUpdated(_usdoSwapper);
File: tapioca-bar-audit/contracts/Penrose.sol
/// @audit setBigBangEthMarketDebtRate()
258: emit BigBangEthMarketDebtRate(_rate);
/// @audit setBigBangEthMarket()
265: emit BigBangEthMarketSet(_market);
/// @audit updatePause()
274: emit PausedUpdated(paused, val);
/// @audit setConservator()
283: emit ConservatorUpdated(conservator, _conservator);
/// @audit setUsdoToken()
310: emit UsdoTokenUpdated(_usdoToken, usdoAssetId);
/// @audit registerSingularityMasterContract()
332: emit RegisterSingularityMasterContract(mcAddress, contractType_);
/// @audit registerBigBangMasterContract()
354: emit RegisterBigBangMasterContract(mcAddress, contractType_);
/// @audit registerSingularity()
375: emit RegisterSingularity(_contract, mc);
/// @audit registerBigBang()
408: emit RegisterBigBang(_contract, mc);
/// @audit setFeeTo()
457: emit FeeToUpdate(feeTo_);
/// @audit setSwapper()
466: emit SwapperUpdate(address(swapper), enable);
File: tapioca-bar-audit/contracts/usd0/BaseUSDO.sol
/// @audit setMaxFlashMintable()
89: emit MaxFlashMintUpdated(maxFlashMint, _val);
/// @audit setFlashMintFee()
98: emit FlashMintFeeUpdated(flashMintFee, _val);
/// @audit setConservator()
107: emit ConservatorUpdated(conservator, _conservator);
/// @audit updatePause()
117: emit PausedUpdated(paused, val);
/// @audit setMinterStatus()
127: emit SetMinterStatus(_for, _status);
/// @audit setBurnerStatus()
136: emit SetBurnerStatus(_for, _status);
File: tapiocaz-audit/contracts/tOFT/mTapiocaOFT.sol
/// @audit updateConnectedChain()
120 emit ConnectedChainStatusUpdated(
121 _chain,
122 connectedChains[_chain],
123 _status
124: );
/// @audit updateBalancerState()
135: emit BalancerStatusUpdated(_balancer, balancers[_balancer], _status);
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
/// @audit setTapOracle()
315: emit SetTapOracle(_tapOracle, _tapOracleData);
/// @audit setPaymentToken()
352: emit SetPaymentToken(_paymentToken, _oracle, _oracleData);
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
/// @audit setTapOracle()
453: emit SetTapOracle(_tapOracle, _tapOracleData);
/// @audit setPaymentToken()
466: emit SetPaymentToken(_paymentToken, _oracle, _oracleData);
File: tap-token-audit/contracts/options/TapiocaOptionLiquidityProvision.sol
/// @audit setSGLPoolWEight()
269: emit SetSGLPoolWeight(address(singularity), weight);
/// @audit registerSingularity()
292: emit RegisterSingularity(address(singularity), assetID);
File: tap-token-audit/contracts/tokens/TapOFT.sol
/// @audit setGovernanceChainIdentifier()
143 emit GovernanceChainIdentifierUpdated(
144 governanceChainIdentifier,
145 _identifier
146: );
/// @audit updatePause()
154: emit PausedUpdated(paused, val);
/// @audit setMinter()
162: emit MinterUpdated(minter, _minter);
File: tap-token-audit/contracts/Vesting.sol
/// @audit registerUser()
145: emit UserRegistered(_user, _amount);
File: tapioca-periph-audit/contracts/Swapper/UniswapV3Swapper.sol
/// @audit setPoolFee()
62: emit PoolFee(poolFee, _newFee);
File: tapioca-yieldbox-strategies-audit/contracts/aave/AaveStrategy.sol
/// @audit setMultiSwapper()
130: emit MultiSwapper(address(swapper), _swapper);
File: tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
/// @audit setMultiSwapper()
171: emit MultiSwapper(address(swapper), _swapper);
/// @audit setTricryptoLPGetter()
180: emit LPGetterSet(address(lpGetter), _lpGetter);
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
/// @audit setMultiSwapper()
142: emit MultiSwapper(address(swapper), _swapper);
/// @audit setTricryptoLPGetter()
151: emit LPGetterSet(address(lpGetter), _lpGetter);
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
/// @audit setMultiSwapper()
133: emit MultiSwapper(address(swapper), _swapper);
/// @audit setTricryptoLPGetter()
142: emit LPGetterSet(address(lpGetter), _lpGetter);
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
/// @audit setMultiSwapper()
150: emit MultiSwapper(address(swapper), _swapper);
Consider defining in only one contract so that values cannot become out of sync when only one location is updated. A cheap way to store constants in a single location is to create an internal constant
in a library
. If the variable is a local cache of another contract's value, consider making the cache variable internal or private, which will require external users to query the contract with the source of truth, so that callers don't get out of sync.
There are 23 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/usd0/BaseUSDOStorage.sol
/// @audit seen in tapioca-bar-audit/contracts/Penrose.sol
19: IYieldBoxBase public immutable yieldBox;
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
/// @audit seen in tap-token-audit/contracts/governance/twTAP.sol
45: TapOFT public immutable tapOFT;
/// @audit seen in tap-token-audit/contracts/governance/twTAP.sol
95: uint256 public constant EPOCH_DURATION = 2 days;
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
/// @audit seen in tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
56: TapOFT public immutable tapOFT;
/// @audit seen in tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
78: uint256 public immutable EPOCH_DURATION; // 7 days = 604800
File: tapioca-periph-audit/contracts/Swapper/UniswapV2Swapper.sol
/// @audit seen in tapioca-periph-audit/contracts/Swapper/CurveSwapper.sol
28: IYieldBox public immutable yieldBox;
File: tapioca-periph-audit/contracts/Swapper/UniswapV3Swapper.sol
/// @audit seen in tapioca-periph-audit/contracts/Swapper/UniswapV2Swapper.sol
35: ISwapRouter public immutable swapRouter;
/// @audit seen in tapioca-periph-audit/contracts/Swapper/UniswapV2Swapper.sol
36: IUniswapV3Factory public immutable factory;
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/aave/AaveStrategy.sol
34: IERC20 public immutable wrappedNative;
File: tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
34: IERC20 public immutable wrappedNative;
File: tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
41: IERC20 public immutable wrappedNative;
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/aave/AaveStrategy.sol
52: IERC20 public immutable rewardToken;
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
40: IERC20 public immutable lpToken;
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
41: IERC20 public immutable wrappedNative;
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
47: IERC20 public immutable rewardToken; //CRV token
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
40: IERC20 public immutable wrappedNative;
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
43: ITricryptoLPGauge public immutable lpGauge;
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
44: ICurveMinter public immutable minter;
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
46: IERC20 public immutable rewardToken; //CRV token
File: tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
36: IERC20 public immutable wrappedNative;
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
41: IERC20 public immutable wrappedNative;
File: tapioca-yieldbox-strategies-audit/contracts/yearn/YearnStrategy.sol
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
36: IERC20 public immutable wrappedNative;
/// @audit seen in tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
37: IYearnVault public immutable vault;
There are 5 instances of this issue:
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
120 /**
121 * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
122 */
123 // solhint-disable-next-line func-name-mixedcase
124: function DOMAIN_SEPARATOR() external view override returns (bytes32) {
209 /**
210 * @dev See {IERC20Permit-permit}.
211 */
212 function permit(
213 address owner,
214 address spender,
215 uint256 value,
216 uint256 deadline,
217 uint8 v,
218 bytes32 r,
219: bytes32 s
File: tap-token-audit/contracts/governance/twTAP.sol
579 /**
580 * @dev See {IERC165-supportsInterface}.
581 */
582 function supportsInterface(
583 bytes4 interfaceId
584: ) public view virtual override(ONFT721, ERC721) returns (bool) {
File: YieldBox/contracts/YieldBoxPermit.sol
98 /**
99 * @dev See {IERC20Permit-nonces}.
100 */
101: function nonces(address owner) public view virtual returns (uint256) {
105 /**
106 * @dev See {IERC20Permit-DOMAIN_SEPARATOR}.
107 */
108 // solhint-disable-next-line func-name-mixedcase
109: function DOMAIN_SEPARATOR() external view returns (bytes32) {
Some lines use // x
and some use //x
. The instances below point out the usages that don't follow the majority, within each file
There are 315 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
18: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
19: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
22: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
25: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
168: liquidationMultiplier = 12000; //12%
420: //repay as much as we can
519: //update debt rate
521: _accrueInfo.debtRate = uint64(annumDebtRate / 31536000); //per second
730: uint256 toWithdraw = (amount - part); //acrrued
733: //burn USDO
757: //mint USDO
760: //deposit borrowed amount to user
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
11: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
12: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
13: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
14: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
15: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
18: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-bar-audit/contracts/markets/Market.sol
66: uint256 public minLiquidatorReward = 1e3; //1%
68: uint256 public maxLiquidatorReward = 1e4; //10%
71: uint256 public liquidationBonusAmount = 1e4; //10%
75: uint256 public borrowOpeningFee = 50; //0.05%
77: uint256 public liquidationMultiplier = 12000; //12%
82: uint256 internal EXCHANGE_RATE_PRECISION; //not costant, but can only be set in the 'init' method
File: tapioca-bar-audit/contracts/markets/singularity/SGLCommon.sol
246: _yieldBoxShares[from][ASSET_SIG] = 0; //some assets accrue in time
File: tapioca-bar-audit/contracts/markets/singularity/SGLLendingCommon.sol
51: _yieldBoxShares[from][COLLATERAL_SIG] = 0; //accrues in time
File: tapioca-bar-audit/contracts/markets/singularity/SGLLeverage.sol
34: //add collateral
43: //borrow
46: //withdraw
80: //send for unwrap
133: //repay as much as we can
File: tapioca-bar-audit/contracts/markets/singularity/SGLStorage.sol
21: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
22: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
25: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
26: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
27: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
28: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
18: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
19: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
22: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
25: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
121: //default fees
126: //liquidation
127: liquidationMultiplier = 12000; //12%
File: tapioca-bar-audit/contracts/Penrose.sol
16: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
17: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
19: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
20: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
21: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
23: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-bar-audit/contracts/usd0/modules/USDOMarketModule.sol
201: // Use market helper to deposit and add asset to market
File: tapioca-bar-audit/contracts/usd0/USDO.sol
11: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
12: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
13: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
14: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
15: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
18: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapiocaz-audit/contracts/Balancer.sol
155: 1e3, //1% slippage
188: //check if OFT is still valid
197: //extract
200: //send
290: _oft, //refund
326: _oft, //refund,
File: tapiocaz-audit/contracts/TapiocaWrapper.sol
13: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
14: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
15: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
16: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
17: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
File: tapiocaz-audit/contracts/tOFT/BaseTOFT.sol
85: if (_decimalCache == 0) return 18; //temporary fix for LZ _sharedDecimals check
347: //---internal-
378: //---private---
441: //---LZ---
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTMarketModule.sol
135: address _from, //from
174: revert(_getRevertMsg(reason)); //forward revert because it's handled by the main executor
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTStrategyModule.sol
167: revert(_getRevertMsg(reason)); //forward revert because it's handled by the main executor
File: tapiocaz-audit/contracts/tOFT/TapiocaOFT.sol
7: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
8: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
9: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
10: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
11: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
12: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
13: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
File: tap-token-audit/contracts/governance/twTAP.sol
14: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
15: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
18: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
17: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
18: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
20: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
21: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
24: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tap-token-audit/contracts/option-airdrop/aoTAP.sol
14: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
15: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
18: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
21: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tap-token-audit/contracts/options/oTAP.sol
12: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
13: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
14: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
15: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
16: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
19: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
16: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
17: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
19: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
20: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
21: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
23: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tap-token-audit/contracts/options/TapiocaOptionLiquidityProvision.sol
17: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
18: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
20: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
21: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
24: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tap-token-audit/contracts/tokens/BaseTapOFT.sol
13: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
14: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
15: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
16: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
17: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
20: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
51: //---LZ---
File: tap-token-audit/contracts/tokens/LTap.sol
28: /// @notice Creates a new LTAP token
29: /// @dev LTAP tokens are minted by depositing TAP
30: /// @param _tapToken Address of the TAP token
31: /// @param _maxLockedUntil Latest possible end of locking period
File: tap-token-audit/contracts/tokens/TapOFT.sol
10: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
11: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
12: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
13: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
14: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
15: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
17: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
137: ///-- Owner methods --
166: //-- View methods --
194: ///-- Write methods --
238: ///-- Internal methods --
245: ///-- Private methods --
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2.sol
15: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
16: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
18: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
19: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
22: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-periph-audit/contracts/Magnetar/modules/MagnetarMarketModule.sol
144: //deposit to YieldBox
274: //withdraw
354: //add collateral to BingBang
590: //withdraw
651: //withdraw
File: tapioca-periph-audit/contracts/Multicall/Multicall3.sol
74: // Humanity will be a Type V Kardashev Civilization before this overflows - andreas
75: // ~ 10^25 Wei in existence << ~ 10^76 size uint fits in a uint256
89: // Finally, make sure the msg.value = SUM(call[0...i].value)
94: // If the _res length is less than 68, then
95: // the transaction failed with custom error or silently (without a revert message)
99: // Slice the sighash.
102: revert(abi.decode(_returnData, (string))); // All that remains is the revert string
File: tapioca-periph-audit/contracts/Swapper/CurveSwapper.sol
11: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
12: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
13: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
14: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
15: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
18: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-periph-audit/contracts/Swapper/UniswapV2Swapper.sol
11: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
12: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
13: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
14: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
15: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
File: tapioca-periph-audit/contracts/Swapper/UniswapV3Swapper.sol
17: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
18: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
20: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
21: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
File: tapioca-yieldbox-strategies-audit/contracts/aave/AaveStrategy.sol
18: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
19: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
22: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
38: //AAVE
113: result = result - (result * 50) / 10_000; //0.5%
140: //first claim stkAave
154: //try to claim AAVE
162: //try to cooldown
169: //we have an active cooldown; check if we need to cooldown again
178: //try to stake
183: //swap AAVE to wrappedNative
193: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
196: //stake if > depositThreshold
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
18: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
19: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
22: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
39: IBalancerPool public immutable pool; //lp token
122: toWithdraw = toWithdraw - (toWithdraw * 50) / 10_000; //0.5%
177: bptOut = bptOut - (bptOut * 50) / 10_000; //0.5%
250: bptIn = bptIn + (bptIn * 250) / 10_000; //2.5%
File: tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
18: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
19: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
22: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
File: tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
21: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
22: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
25: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
26: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
27: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
143: result = result - (result * 50) / 10_000; //0.5%
154: uint256 minAmount = (calcWithdraw * 50) / 10_000; //0.5%
207: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
313: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
336: uint256 minAmount = calcWithdraw - (calcWithdraw * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
20: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
21: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
23: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
24: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
25: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
26: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
47: IERC20 public immutable rewardToken; //CRV token
179: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
186: minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
20: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
21: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
23: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
24: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
25: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
26: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
46: IERC20 public immutable rewardToken; //CRV token
116: result = result - (result * 50) / 10_000; //0.5%
170: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
188: uint256 minAmount = calcWithdraw - (calcWithdraw * 50) / 10_000; //0.5%
201: return assetAmount + queued; //+ compoundAmount;
232: uint256 minAmount = calcWithdraw - (calcWithdraw * 50) / 10_000; //0.5%
249: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
19: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
20: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
21: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
22: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
23: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
25: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
108: uint256 minAmount = (toWithdraw * 50) / 10_000; //0.5%
133: stEth.submit{value: queued}(address(0)); //1:1 between eth<>stEth
150: uint256 toWithdraw = amount - queued; //1:1 between eth<>stEth
151: uint256 minAmount = toWithdraw - (toWithdraw * 250) / 10_000; //2.5%
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
21: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
22: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
25: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
26: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
27: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
51: IERC20 public stgNative; //ex: stEth
133: result = result - (result * 50) / 10_000; //0.5%
182: uint256 minAmount = calcAmount - (calcAmount * 50) / 10_000; //0.5%
File: tapioca-yieldbox-strategies-audit/contracts/yearn/YearnStrategy.sol
16: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
17: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
19: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
20: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
21: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
147: wrappedNative.safeTransfer(to, amount - 1); //rounding error
Usually lines in source code are limited to 80 characters. Today's screens are much larger so it's reasonable to stretch this in some cases. The solidity style guide recommends a maximumum line length of 120 characters, so the lines below should be split when they reach that length.
There are 361 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
17: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
18: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
19: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
22: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
25: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
34: /// - interest rate is not fixed, but dynamic based on the main BigBang market, minDebtRate, maxDebtRate and debtRateAgainstEthMarket
35: /// - BigBang markets can either be main or secondary markets; the main market is set on Penrose and has a fixed rate
37: /// - if current debt is over _maxDebtPoint = (_ethMarketTotalDebt * debtRateAgainstEthMarket) / 1e18, the interest rate is automatically `maxDebtRate`
258: /// @dev The bool param is not used but we added it to respect the ISingularity interface for MarketsHelper compatibility
306: /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
655: /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
10: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
11: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
12: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
13: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
14: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
15: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
18: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-bar-audit/contracts/markets/Market.sol
299: /// @notice return the amount of collateral for a `user` to be solvent, min TVL and max TVL. Returns 0 if user already solvent.
File: tapioca-bar-audit/contracts/markets/singularity/SGLLiquidation.sol
21: /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
373: /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
File: tapioca-bar-audit/contracts/markets/singularity/SGLStorage.sol
20: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
21: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
22: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
25: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
26: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
27: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
28: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
44: Rebase public totalAsset; // elastic = yieldBox shares held by the Singularity, base = Total fractions held by asset suppliers
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
17: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
18: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
19: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
22: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
25: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
35: /// - adding assets to the contract, mints shares to the `to` address which can later be used in the oTap & twTap system
36: /// - interest rate is automatically updated based on the interest elasticity time and it's bounded by `minimumInterestPerSecond` and `maximumInterestPerSecond`
432: /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
File: tapioca-bar-audit/contracts/Penrose.sol
15: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
16: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
17: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
19: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
20: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
21: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
23: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-bar-audit/contracts/usd0/USDO.sol
10: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
11: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
12: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
13: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
14: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
15: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
18: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapiocaz-audit/contracts/TapiocaWrapper.sol
12: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
13: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
14: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
15: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
16: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
17: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
20: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapiocaz-audit/contracts/tOFT/mTapiocaOFT.sol
8: /// - wrapping & unwrapping of the ERC20/the gas token can happen on multiple chains defined by the `connectedChains` mapping
85: /// @dev Since it can be executed only on the main chain, if an address exists on the OP chain it will not allowed to wrap.
File: tapiocaz-audit/contracts/tOFT/TapiocaOFT.sol
6: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
7: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
8: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
9: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
10: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
11: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
12: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
13: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
14: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
65: /// @dev Since it can be executed only on the main chain, if an address exists on the OP chain it will not allowed to wrap.
File: tap-token-audit/contracts/governance/twTAP.sol
13: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
14: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
15: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
18: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
21: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
64: /// @dev This contract allow the locking of TAP to twTAP. The amount of twTAP received is based on the amount of locked TAP, and the duration of the lock.
65: /// It uses twAML to compute the amount of twTAP received, details about the model can be found here https://docs.tapioca.xyz/tapioca/core-technologies/twaml.
66: /// The contract distributes a set of rewards tokens each week to the twTAP holders. The amount of rewards received is based on the amount of twTAP held.
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
16: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
17: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
18: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
20: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
21: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
24: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
38: /// @notice Forked version of TapiocaOptionBroker. More details found here https://docs.tapioca.xyz/tapioca/launch/option-airdrop#eligibility-and-details
39: /// @dev This contract is used to manage the Tapioca Option Airdrop. It allows for users to participate in the airdrop and exercise their options.
136: /// @param _tapAmount The amount of TAP to be exchanged. If 0 it will use the full amount of TAP eligible for the deal
407: /// @notice Participate in phase 2 of the Airdrop. Guild members will receive pre-defined discounts and TAP, based on role.
File: tap-token-audit/contracts/option-airdrop/aoTAP.sol
13: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
14: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
15: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
18: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
21: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tap-token-audit/contracts/options/oTAP.sol
11: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
12: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
13: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
14: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
15: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
16: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
19: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
15: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
16: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
17: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
19: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
20: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
21: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
23: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
45: /// @notice This contract handles the creation of oTAP, the oTAP options creates an expiry dates to exercise the option, and an eligible amount of TAP that can be exercised.
46: /// The amount of TAP that can be exercised is calculated by the TWAML algorithm, which takes into account the size of the participant as well his lock time.
48: /// More info about the mechanic of how to receive oTAP can be found here https://docs.tapioca.xyz/tapioca/token-economy/dso-dao-share-options
141: /// @param _tapAmount The amount of TAP to be exchanged. If 0 it will use the full amount of TAP eligible for the deal
File: tap-token-audit/contracts/options/TapiocaOptionLiquidityProvision.sol
16: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
17: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
18: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
20: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
21: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
24: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
42: /// tOLP tokens are minted when a user locks their Singularity position and can be burned only when the position is unlocked,
62: mapping(uint256 => IERC20) public sglAssetIDToAddress; // Singularity market YieldBox asset ID => Singularity market address
File: tap-token-audit/contracts/tokens/BaseTapOFT.sol
12: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
13: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
14: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
15: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
16: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
17: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
20: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tap-token-audit/contracts/tokens/LTap.sol
9: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
10: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
11: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
12: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
13: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
14: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
15: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
17: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tap-token-audit/contracts/tokens/TapOFT.sol
9: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
10: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
11: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
12: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
13: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
14: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
15: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
17: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2.sol
14: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
15: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
16: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
18: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
19: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
22: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
880: /// @notice helper to exit from tOB, unlock from tOLP, remove from SGL, repay on BB, remove collateral from BB and withdraw
885: /// - if `!removeAndRepayData.assetWithdrawData.withdraw && removeAndRepayData.repayAssetOnBB`, the repay operation is performed
887: /// - the helper can either stop at the remove asset from SGL step or it can continue until is removes & withdraws collateral from BB
File: tapioca-periph-audit/contracts/Magnetar/modules/MagnetarMarketModule.sol
257: // if `withdrawCollateralParams.withdraw` it uses `withdrawTo` to withdraw collateral on the same chain or to another one
File: tapioca-periph-audit/contracts/Multicall/Multicall3.sol
8: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
9: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
10: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
11: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
12: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
13: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
14: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
15: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
16: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-periph-audit/contracts/oracle/implementations/ARBTriCryptoOracle.sol
68: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
79: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
88: /// @notice Check the current spot exchange rate without any state changes. For oracles like TWAP this will be different from peek().
90: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
100: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
108: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
File: tapioca-periph-audit/contracts/oracle/implementations/SGOracle.sol
58: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
69: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
78: /// @notice Check the current spot exchange rate without any state changes. For oracles like TWAP this will be different from peek().
80: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
90: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
98: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
File: tapioca-periph-audit/contracts/oracle/Seer.sol
49: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
61: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
71: /// @notice Check the current spot exchange rate without any state changes. For oracles like TWAP this will be different from peek().
73: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
84: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
92: /// (string memory collateralSymbol, string memory assetSymbol, uint256 division) = abi.decode(data, (string, string, uint256));
File: tapioca-periph-audit/contracts/Swapper/CurveSwapper.sol
10: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
11: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
12: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
13: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
14: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
15: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
18: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-periph-audit/contracts/Swapper/UniswapV2Swapper.sol
10: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
11: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
12: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
13: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
14: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
15: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
16: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
17: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
18: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-periph-audit/contracts/Swapper/UniswapV3Swapper.sol
16: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
17: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
18: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
19: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
20: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
21: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
24: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-yieldbox-strategies-audit/contracts/aave/AaveStrategy.sol
17: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
18: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
19: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
22: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
25: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
17: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
18: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
19: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
22: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
25: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
17: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
18: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
19: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
20: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
21: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
22: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
25: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
20: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
21: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
22: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
25: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
26: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
27: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
28: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
19: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
20: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
21: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
23: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
24: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
25: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
26: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
27: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
19: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
20: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
21: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
23: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
24: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
25: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
26: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
27: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
18: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
19: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
20: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
21: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
22: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
23: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
24: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
25: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
26: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
20: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
21: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
22: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
23: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
24: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
25: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
26: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
27: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
28: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
31: //TODO: decide if we need to start with ETH and wrap it into WETH; stargate allows ETH. not WETH, while others allow WETH, not ETH
File: tapioca-yieldbox-strategies-audit/contracts/yearn/YearnStrategy.sol
15: __/\\\\\\\\\\\\\\\_____/\\\\\\\\\_____/\\\\\\\\\\\\\____/\\\\\\\\\\\_______/\\\\\_____________/\\\\\\\\\_____/\\\\\\\\\____
16: _\///////\\\/////____/\\\\\\\\\\\\\__\/\\\/////////\\\_\/////\\\///______/\\\///\\\________/\\\////////____/\\\\\\\\\\\\\__
17: _______\/\\\________/\\\/////////\\\_\/\\\_______\/\\\_____\/\\\_______/\\\/__\///\\\____/\\\/____________/\\\/////////\\\_
18: _______\/\\\_______\/\\\_______\/\\\_\/\\\\\\\\\\\\\/______\/\\\______/\\\______\//\\\__/\\\_____________\/\\\_______\/\\\_
19: _______\/\\\_______\/\\\\\\\\\\\\\\\_\/\\\/////////________\/\\\_____\/\\\_______\/\\\_\/\\\_____________\/\\\\\\\\\\\\\\\_
20: _______\/\\\_______\/\\\/////////\\\_\/\\\_________________\/\\\_____\//\\\______/\\\__\//\\\____________\/\\\/////////\\\_
21: _______\/\\\_______\/\\\_______\/\\\_\/\\\_________________\/\\\______\///\\\__/\\\_____\///\\\__________\/\\\_______\/\\\_
22: _______\/\\\_______\/\\\_______\/\\\_\/\\\______________/\\\\\\\\\\\____\///\\\\\/________\////\\\\\\\\\_\/\\\_______\/\\\_
23: _______\///________\///________\///__\///______________\///////////_______\/////_____________\/////////__\///________\///__
26: //TODO: decide if we need to start with ETH and wrap it into WETH; stargate allows ETH. not WETH, while others allow WETH, not ETH
File: YieldBox/contracts/NativeTokenFactory.sol
55: /// @param renounce Allows the `newOwner` to be `address(0)` if `direct` and `renounce` is True. Has no effect otherwise.
56: function transferOwnership(uint256 tokenId, address newOwner, bool direct, bool renounce) public onlyOwner(tokenId) {
89: /// @param decimals The number of decimals of the token (this is just for display purposes). Should be set to 18 in normal cases.
90: function createToken(string calldata name, string calldata symbol, uint8 decimals, string calldata uri) public returns (uint32 tokenId) {
91: // To keep each Token unique in the AssetRegister, we use the assetId as the tokenId. So for native assets, the tokenId is always equal to the assetId.
104: /// @notice The `owner` can mint tokens. If a fixed supply is needed, the `owner` should mint the totalSupply and renounce ownership.
108: /// @dev For security reasons, operators are not allowed to mint. Only the actual owner can do this. Of course the owner can be a contract.
121: /// @notice The `owner` can mint tokens. If a fixed supply is needed, the `owner` should mint the totalSupply and renounce ownership.
125: /// @dev If the tos array is longer than the amounts array there will be an out of bounds error. If the amounts array is longer, the extra amounts are simply ignored.
126: /// @dev For security reasons, operators are not allowed to mint. Only the actual owner can do this. Of course the owner can be a contract.
File: YieldBox/contracts/YieldBoxPermit.sol
53: bytes32 structHash = keccak256(abi.encode(_PERMIT_TYPEHASH, owner, spender, assetId, _useNonce(owner), deadline));
File: YieldBox/contracts/YieldBox.sol
4: // The original BentoBox is owned by the Sushi team to set strategies for each token. Abracadabra wanted different strategies, which led to
5: // them launching their own DegenBox. The YieldBox solves this by allowing an unlimited number of strategies for each token in a fully
127: require(asset.tokenType != TokenType.Native && asset.tokenType != TokenType.ERC721, "YieldBox: can't deposit type");
135: // amount may be lower than the value of share due to rounding, in that case, add 1 to amount (Always round up)
143: // For ERC20 tokens, use the safe helper function to deal with broken ERC20 implementations. This actually calls transferFrom on the ERC20 contract.
151: IERC1155(asset.contractAddress).safeTransferFrom(from, address(asset.strategy), asset.tokenId, amount, "");
196: function depositETHAsset(uint256 assetId, address to, uint256 amount) public payable returns (uint256 amountOut, uint256 shareOut) {
199: require(asset.tokenType == TokenType.ERC20 && asset.contractAddress == address(wrappedNative), "YieldBox: not wrappedNative");
208: // Strategies always receive wrappedNative (supporting both wrapped and raw native tokens adds too much complexity)
281: // value of the share paid could be lower than the amount paid due to rounding, in that case, add a share (Always round up)
316: function _transferBatch(address from, address to, uint256[] calldata ids, uint256[] calldata values) internal override {
336: function transferMultiple(address from, address[] calldata tos, uint256 assetId, uint256[] calldata shares) public allowed(from, assetId) {
400: // This functionality has been split off into a separate contract. This is only a view function, so gas usage isn't a huge issue.
489: return depositAsset(registerAsset(TokenType.ERC1155, address(this), strategy, tokenId), from, to, amount, share);
500: function depositETH(IStrategy strategy, address to, uint256 amount) public payable returns (uint256 amountOut, uint256 shareOut) {
File: YieldBox/contracts/YieldBoxURIBuilder.sol
90: abi.encodePacked("ERC1155:", uint256(uint160(asset.contractAddress)).toHexString(20), "/", asset.tokenId.toString())
107: : abi.encodePacked(',"totalSupply":', totalSupply.toString(), ',"fixedSupply":', owner == address(0) ? "true" : "false")
129: asset.tokenType == TokenType.ERC1155 ? string(abi.encodePacked(',"tokenId":', asset.tokenId.toString())) : "",
[N‑39] Variable names that consist of all capital letters should be reserved for constant
/immutable
variables
If the variable needs to be different based on which class it comes from, a view
/pure
function should be used instead (e.g. like this).
There are 6 instances of this issue:
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
45: bytes32 private _PERMIT_TYPEHASH_DEPRECATED_SLOT;
File: tapioca-bar-audit/contracts/markets/Market.sol
82: uint256 internal EXCHANGE_RATE_PRECISION; //not costant, but can only be set in the 'init' method
File: tapioca-bar-audit/contracts/markets/singularity/SGLStorage.sol
50 bytes32 internal ASSET_SIG =
51: 0x0bd4060688a1800ae986e4840aebc924bb40b5bf44de4583df2257220b54b77c; // keccak256("asset")
52 bytes32 internal COLLATERAL_SIG =
53: 0x7d1dc38e60930664f8cbf495da6556ca091d2f92d6550877750c049864b18230; // keccak256("collateral")
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
77: uint8[4] public PHASE_2_AMOUNT_PER_USER = [200, 190, 200, 190];
78: uint8[4] public PHASE_2_DISCOUNT_PER_USER = [50, 40, 40, 33];
There are 59 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/markets/singularity/SGLBorrow.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/markets/singularity/SGLCollateral.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/markets/singularity/SGLCommon.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/markets/singularity/SGLLendingCommon.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/markets/singularity/SGLLeverage.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/markets/singularity/SGLLiquidation.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/markets/singularity/SGLStorage.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/Penrose.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/usd0/BaseUSDO.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/usd0/BaseUSDOStorage.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/usd0/modules/USDOLeverageModule.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/usd0/modules/USDOMarketModule.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/usd0/modules/USDOOptionsModule.sol
2: pragma solidity ^0.8.18;
File: tapioca-bar-audit/contracts/usd0/USDO.sol
2: pragma solidity ^0.8.18;
File: tapiocaz-audit/contracts/Balancer.sol
2: pragma solidity ^0.8.18;
File: tapiocaz-audit/contracts/TapiocaWrapper.sol
2: pragma solidity ^0.8.18;
File: tapiocaz-audit/contracts/tOFT/BaseTOFT.sol
2: pragma solidity ^0.8.18;
File: tapiocaz-audit/contracts/tOFT/BaseTOFTStorage.sol
2: pragma solidity ^0.8.18;
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTLeverageModule.sol
2: pragma solidity ^0.8.18;
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTMarketModule.sol
2: pragma solidity ^0.8.18;
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTOptionsModule.sol
2: pragma solidity ^0.8.18;
File: tapiocaz-audit/contracts/tOFT/modules/BaseTOFTStrategyModule.sol
2: pragma solidity ^0.8.18;
File: tapiocaz-audit/contracts/tOFT/mTapiocaOFT.sol
2: pragma solidity ^0.8.18;
File: tapiocaz-audit/contracts/tOFT/TapiocaOFT.sol
2: pragma solidity ^0.8.18;
File: tap-token-audit/contracts/option-airdrop/AirdropBroker.sol
2: pragma solidity ^0.8.18;
File: tap-token-audit/contracts/option-airdrop/aoTAP.sol
2: pragma solidity ^0.8.18;
File: tap-token-audit/contracts/options/oTAP.sol
2: pragma solidity ^0.8.18;
File: tap-token-audit/contracts/options/TapiocaOptionBroker.sol
2: pragma solidity ^0.8.18;
File: tap-token-audit/contracts/options/TapiocaOptionLiquidityProvision.sol
2: pragma solidity ^0.8.18;
File: tap-token-audit/contracts/tokens/LTap.sol
2: pragma solidity ^0.8.18;
File: tap-token-audit/contracts/tokens/TapOFT.sol
2: pragma solidity ^0.8.18;
File: tap-token-audit/contracts/Vesting.sol
2: pragma solidity ^0.8.18;
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2.sol
2: pragma solidity ^0.8.18;
File: tapioca-periph-audit/contracts/Magnetar/MagnetarV2Storage.sol
2: pragma solidity ^0.8.18;
File: tapioca-periph-audit/contracts/Magnetar/modules/MagnetarMarketModule.sol
2: pragma solidity ^0.8.18;
File: tapioca-periph-audit/contracts/Multicall/Multicall3.sol
2: pragma solidity ^0.8.18;
File: tapioca-periph-audit/contracts/oracle/implementations/ARBTriCryptoOracle.sol
2: pragma solidity ^0.8.9;
File: tapioca-periph-audit/contracts/oracle/implementations/SGOracle.sol
2: pragma solidity ^0.8.9;
File: tapioca-periph-audit/contracts/oracle/Seer.sol
2: pragma solidity ^0.8.18;
File: tapioca-periph-audit/contracts/Swapper/CurveSwapper.sol
2: pragma solidity ^0.8.18;
File: tapioca-periph-audit/contracts/Swapper/UniswapV2Swapper.sol
2: pragma solidity ^0.8.18;
File: tapioca-periph-audit/contracts/Swapper/UniswapV3Swapper.sol
2: pragma solidity ^0.8.18;
File: tapioca-periph-audit/contracts/TapiocaDeployer/TapiocaDeployer.sol
2: pragma solidity ^0.8.18;
File: tapioca-yieldbox-strategies-audit/contracts/aave/AaveStrategy.sol
2: pragma solidity ^0.8.18;
File: tapioca-yieldbox-strategies-audit/contracts/balancer/BalancerStrategy.sol
2: pragma solidity ^0.8.18;
File: tapioca-yieldbox-strategies-audit/contracts/compound/CompoundStrategy.sol
2: pragma solidity ^0.8.18;
File: tapioca-yieldbox-strategies-audit/contracts/convex/ConvexTricryptoStrategy.sol
2: pragma solidity ^0.8.18;
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoLPStrategy.sol
2: pragma solidity ^0.8.18;
File: tapioca-yieldbox-strategies-audit/contracts/curve/TricryptoNativeStrategy.sol
2: pragma solidity ^0.8.18;
File: tapioca-yieldbox-strategies-audit/contracts/glp/GlpStrategy.sol
2: pragma solidity ^0.8.18;
File: tapioca-yieldbox-strategies-audit/contracts/lido/LidoEthStrategy.sol
2: pragma solidity ^0.8.18;
File: tapioca-yieldbox-strategies-audit/contracts/stargate/StargateStrategy.sol
2: pragma solidity ^0.8.18;
File: tapioca-yieldbox-strategies-audit/contracts/yearn/YearnStrategy.sol
2: pragma solidity ^0.8.18;
File: YieldBox/contracts/NativeTokenFactory.sol
2: pragma solidity ^0.8.9;
File: YieldBox/contracts/YieldBox.sol
24: pragma solidity ^0.8.9;
File: YieldBox/contracts/YieldBoxURIBuilder.sol
2: pragma solidity ^0.8.9;
There are 31 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
/// @audit repayed
262: /// @return amount The total amount repayed.
/// @audit Mininal
332: /// @param minAmountOut Mininal collateral amount to receive
/// @audit Mininal
380: /// @param minAmountOut Mininal proceeds required for the sale
/// @audit necessar
657: /// @param swapData Swap necessar data
/// @audit acrrued
730: uint256 toWithdraw = (amount - part); //acrrued
File: tapioca-bar-audit/contracts/markets/Market.sol
/// @audit repayed
50: /// @dev elastic = Total token amount to be repayed by borrowers, base = Total parts of the debt held by borrowers
/// @audit costant
82: uint256 internal EXCHANGE_RATE_PRECISION; //not costant, but can only be set in the 'init' method
File: tapioca-bar-audit/contracts/markets/singularity/SGLBorrow.sol
/// @audit repayed
44: /// @return amount The total amount repayed.
File: tapioca-bar-audit/contracts/markets/singularity/SGLLeverage.sol
/// @audit Mininal
93: /// @param minAmountOut Mininal proceeds required for the sale
/// @audit Mininal
143: /// @param minAmountOut Mininal collateral amount to receive
File: tapioca-bar-audit/contracts/markets/singularity/SGLLiquidation.sol
/// @audit necessar
375: /// @param swapData Swap necessar data
File: tapioca-bar-audit/contracts/markets/singularity/SGLStorage.sol
/// @audit repayed
110: /// @notice event emitted when asset is repayed
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
/// @audit repayed
295: /// @return amount The total amount repayed.
/// @audit Mininal
318: /// @param minAmountOut Mininal proceeds required for the sale
/// @audit Mininal
347: /// @param minAmountOut Mininal collateral amount to receive
File: tapioca-bar-audit/contracts/usd0/BaseUSDO.sol
/// @audit transer
183: /// @param lzData data needed for the cross chain transer
File: tapiocaz-audit/contracts/Balancer.sol
/// @audit registeres
214: /// @notice registeres mTapiocaOFT for rebalancing
/// @audit assings
246: /// @notice assings more rebalanceable amount for TOFT
File: tapiocaz-audit/contracts/tOFT/BaseTOFT.sol
/// @audit transer
124: /// @param lzData data needed for the cross chain transer
File: tapiocaz-audit/contracts/tOFT/mTapiocaOFT.sol
/// @audit reigstered
26: /// @notice event emitted when a connected chain is reigstered or unregistered
File: tap-token-audit/contracts/twAML.sol
/// @audit precoditions
100: // correct result modulo 2**256. Since the precoditions guarantee
File: YieldBox/contracts/YieldBoxRebase.sol
/// @audit reseting
24: // To prevent reseting the ratio due to withdrawal of all shares, we start with
/// @audit Calculte
31: // Calculte the shares using te current amount to share ratio
/// @audit reseting
47: // To prevent reseting the ratio due to withdrawal of all shares, we start with
/// @audit Calculte
54: // Calculte the amount using te current amount to share ratio
File: YieldBox/contracts/YieldBox.sol
/// @audit repesented
117: /// @return shareOut The deposited amount repesented in shares.
/// @audit repesented
167: /// @return shareOut The deposited amount repesented in shares.
/// @audit repesented
195: /// @return shareOut The deposited amount repesented in shares.
/// @audit regierestered
421: /// @param assetId The regierestered asset id
/// @audit repesented
476: /// @return shareOut The deposited amount repesented in shares.
/// @audit repesented
499: /// @return shareOut The deposited amount repesented in shares.
There are 329 instances of this issue:
see instances
File: tapioca-bar-audit/contracts/markets/bigBang/BigBang.sol
/// @audit Missing: '@param data'
100 /// @notice The init function that acts as a constructor
101: function init(bytes calldata data) external onlyOnce {
/// @audit Missing: '@param operator'
225 /// @notice allows 'operator' to act on behalf of the sender
226 /// @param status true/false
227: function updateOperator(address operator, bool status) external {
/// @audit Missing: '@param bool'
257 /// @notice Repays a loan.
258 /// @dev The bool param is not used but we added it to respect the ISingularity interface for MarketsHelper compatibility
259 /// @param from Address to repay from.
260 /// @param to Address of the user this payment should go.
261 /// @param part The amount to repay. See `userBorrowPart`.
262 /// @return amount The total amount repayed.
263 function repay(
264 address from,
265 address to,
266 bool,
267 uint256 part
268: ) public notPaused allowedBorrow(from, part) returns (uint256 amount) {
/// @audit Missing: '@param amount'
276 /// @notice Adds `collateral` from msg.sender to the account `to`.
277 /// @param from Account to transfer shares from.
278 /// @param to The receiver of the tokens.
279 /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.
280 /// False if tokens from msg.sender in `yieldBox` should be transferred.
281 /// @param share The amount of shares to add for `to`.
282 function addCollateral(
283 address from,
284 address to,
285 bool skim,
286 uint256 amount,
287 uint256 share
288: ) public allowedBorrow(from, share) notPaused {
/// @audit Missing: '@param address'
441 /// @notice Transfers fees to penrose
442 function refreshPenroseFees(
443 address
444: ) external onlyOwner notPaused returns (uint256 feeShares) {
/// @audit Missing: '@param _minDebtRate'
/// @audit Missing: '@param _maxDebtRate'
/// @audit Missing: '@param _debtRateAgainstEthMarket'
/// @audit Missing: '@param _liquidationMultiplier'
464 /// @notice sets BigBang specific configuration
465 /// @dev values are updated only if > 0 or not address(0)
466 function setBigBangConfig(
467 uint256 _minDebtRate,
468 uint256 _maxDebtRate,
469 uint256 _debtRateAgainstEthMarket,
470 uint256 _liquidationMultiplier
471: ) external onlyOwner {
/// @audit Missing: '@param _exchangeRate'
652 /// @notice Handles the liquidation of users' balances, once the users' amount of collateral is too low.
653 /// @dev Closed liquidations Only, 90% of extra shares goes to caller and 10% to protocol
654 /// @param users An array of user addresses.
655 /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
656 /// @param swapper Contract address of the `MultiSwapper` implementation. See `setSwapper`.
657 /// @param swapData Swap necessar data
658 function _closedLiquidation(
659 address[] calldata users,
660 uint256[] calldata maxBorrowParts,
661 ISwapper swapper,
662 uint256 _exchangeRate,
663: bytes calldata swapData
/// @audit Missing: '@param from'
/// @audit Missing: '@param to'
/// @audit Missing: '@param share'
708 /// @dev Concrete implementation of `removeCollateral`.
709 function _removeCollateral(
710 address from,
711 address to,
712: uint256 share
/// @audit Missing: '@param from'
/// @audit Missing: '@param to'
/// @audit Missing: '@param part'
720 /// @dev Concrete implementation of `repay`.
721 function _repay(
722 address from,
723 address to,
724 uint256 part
725: ) internal returns (uint256 amount) {
/// @audit Missing: '@param from'
/// @audit Missing: '@param to'
/// @audit Missing: '@param amount'
741 /// @dev Concrete implementation of `borrow`.
742 function _borrow(
743 address from,
744 address to,
745 uint256 amount
746: ) internal returns (uint256 part, uint256 share) {
File: tapioca-bar-audit/contracts/markets/MarketERC20.sol
/// @audit Missing: '@param from'
/// @audit Missing: '@param share'
72 // ***************** //
73 // *** MODIFIERS *** //
74 // ***************** //
75: function _allowedLend(address from, uint share) internal {
/// @audit Missing: '@param name'
104 /**
105 * @dev Initializes the {EIP712} domain separator using the `name` parameter, and setting `version` to `"1"`.
106 *
107 * It's a good idea to use the same `name` that is defined as the ERC20 token name.
108 */
109: constructor(string memory name) EIP712(name, "1") {}
/// @audit Missing: '@param owner'
/// @audit Missing: '@param spender'
/// @audit Missing: '@param value'
/// @audit Missing: '@param deadline'
/// @audit Missing: '@param v'
/// @audit Missing: '@param r'
/// @audit Missing: '@param s'
209 /**
210 * @dev See {IERC20Permit-permit}.
211 */
212 function permit(
213 address owner,
214 address spender,
215 uint256 value,
216 uint256 deadline,
217 uint8 v,
218 bytes32 r,
219: bytes32 s
/// @audit Missing: '@param owner'
240 /**
241 * @dev "Consume a nonce": return the current value and increment.
242 *
243 * _Available since v4.1._
244 */
245 function _useNonce(
246 address owner
247: ) internal virtual returns (uint256 current) {
File: tapioca-bar-audit/contracts/markets/Market.sol
/// @audit Missing: '@param _borrowOpeningFee'
/// @audit Missing: '@param _oracle'
/// @audit Missing: '@param _oracleData'
/// @audit Missing: '@param _conservator'
/// @audit Missing: '@param _callerFee'
/// @audit Missing: '@param _protocolFee'
/// @audit Missing: '@param _liquidationBonusAmount'
/// @audit Missing: '@param _minLiquidatorReward'
/// @audit Missing: '@param _maxLiquidatorReward'
/// @audit Missing: '@param _totalBorrowCap'
/// @audit Missing: '@param _collateralizationRate'
156 /// @notice sets common market configuration
157 /// @dev values are updated only if > 0 or not address(0)
158 function setMarketConfig(
159 uint256 _borrowOpeningFee,
160 IOracle _oracle,
161 bytes calldata _oracleData,
162 address _conservator,
163 uint256 _callerFee,
164 uint256 _protocolFee,
165 uint256 _liquidationBonusAmount,
166 uint256 _minLiquidatorReward,
167 uint256 _maxLiquidatorReward,
168 uint256 _totalBorrowCap,
169 uint256 _collateralizationRate
170: ) external onlyOwner {
/// @audit Missing: '@param borrowPart'
/// @audit Missing: '@param collateralPartInAsset'
/// @audit Missing: '@param borrowPartDecimals'
/// @audit Missing: '@param collateralPartDecimals'
/// @audit Missing: '@param ratesPrecision'
252 // ********************** //
253 // *** VIEW FUNCTIONS *** //
254 // ********************** //
255 /// @notice returns the maximum liquidatable amount for user
256 function computeClosingFactor(
257 uint256 borrowPart,
258 uint256 collateralPartInAsset,
259 uint256 borrowPartDecimals,
260 uint256 collateralPartDecimals,
261 uint256 ratesPrecision
262: ) public view returns (uint256) {
/// @audit Missing: '@param user'
353 /// @notice computes the possible liquidator reward
354 /// @notice user the user for which a liquidation operation should be performed
355 /// @param _exchangeRate the exchange rate asset/collateral to use for internal computations
356 function computeLiquidatorReward(
357 address user,
358 uint256 _exchangeRate
359: ) public view returns (uint256) {
/// @audit Missing: '@param user'
400 /// @notice Concrete implementation of `isSolvent`. Includes a parameter to allow caching `exchangeRate`.
401 /// @param _exchangeRate The exchange rate. Used to cache the `exchangeRate` between calls.
402 function _isSolvent(
403 address user,
404 uint256 _exchangeRate
405: ) internal view returns (bool) {
/// @audit Missing: '@param collateralShare'
/// @audit Missing: '@param _exchangeRate'
427 /// @notice Returns the min and max LTV for user in asset price
428 function _computeMaxAndMinLTVInAsset(
429 uint256 collateralShare,
430 uint256 _exchangeRate
431: ) internal view returns (uint256 min, uint256 max) {
File: tapioca-bar-audit/contracts/markets/singularity/SGLCollateral.sol
/// @audit Missing: '@param amount'
12 // ************************ //
13 // *** PUBLIC FUNCTIONS *** //
14 // ************************ //
15 /// @notice Adds `collateral` from msg.sender to the account `to`.
16 /// @param from Account to transfer shares from.
17 /// @param to The receiver of the tokens.
18 /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.
19 /// False if tokens from msg.sender in `yieldBox` should be transferred.
20 /// @param share The amount of shares to add for `to`.
21 function addCollateral(
22 address from,
23 address to,
24 bool skim,
25 uint256 amount,
26 uint256 share
27: ) public notPaused allowedBorrow(from, share) {
File: tapioca-bar-audit/contracts/markets/singularity/SGLCommon.sol
/// @audit Missing: '@param from'
/// @audit Missing: '@param to'
/// @audit Missing: '@param skim'
/// @audit Missing: '@param share'
196 /// @dev Concrete implementation of `addAsset`.
197 function _addAsset(
198 address from,
199 address to,
200 bool skim,
201 uint256 share
202: ) internal returns (uint256 fraction) {
/// @audit Missing: '@param to'
/// @audit Missing: '@param fraction'
/// @audit Missing: '@param updateYieldBoxShares'
221 /// @dev Concrete implementation of `removeAsset`.
222 /// @param from The account to remove from. Should always be msg.sender except for `depositFeesToyieldBox()`.
223 function _removeAsset(
224 address from,
225 address to,
226 uint256 fraction,
227 bool updateYieldBoxShares
228: ) internal returns (uint256 share) {
/// @audit Missing: '@param borrowPart'
253 /// @dev Return the equivalent of collateral borrow part in asset amount.
254 function _getAmountForBorrowPart(
255 uint256 borrowPart
256: ) internal view returns (uint256) {
File: tapioca-bar-audit/contracts/markets/singularity/SGLLendingCommon.sol
/// @audit Missing: '@param from'
/// @audit Missing: '@param to'
/// @audit Missing: '@param skim'
/// @audit Missing: '@param amount'
/// @audit Missing: '@param share'
12 // ************************** //
13 // *** PRIVATE FUNCTIONS *** //
14 // ************************* //
15 /// @dev Concrete implementation of `addCollateral`.
16 function _addCollateral(
17 address from,
18 address to,
19 bool skim,
20 uint256 amount,
21: uint256 share
/// @audit Missing: '@param from'
/// @audit Missing: '@param to'
/// @audit Missing: '@param share'
40 /// @dev Concrete implementation of `removeCollateral`.
41 function _removeCollateral(
42 address from,
43 address to,
44: uint256 share
/// @audit Missing: '@param from'
/// @audit Missing: '@param to'
/// @audit Missing: '@param amount'
57 /// @dev Concrete implementation of `borrow`.
58 function _borrow(
59 address from,
60 address to,
61 uint256 amount
62: ) internal returns (uint256 part, uint256 share) {
/// @audit Missing: '@param from'
/// @audit Missing: '@param to'
/// @audit Missing: '@param skim'
/// @audit Missing: '@param part'
82 /// @dev Concrete implementation of `repay`.
83 function _repay(
84 address from,
85 address to,
86 bool skim,
87 uint256 part
88: ) internal returns (uint256 amount) {
File: tapioca-bar-audit/contracts/markets/singularity/SGLLiquidation.sol
/// @audit Missing: '@param user'
/// @audit Missing: '@param _exchangeRate'
67 // ************************* //
68 // *** PRIVATE FUNCTIONS *** //
69 // ************************* //
70 function _computeAssetAmountToSolvency(
71 address user,
72 uint256 _exchangeRate
73: ) private view returns (uint256) {
/// @audit Missing: '@param _exchangeRate'
370 /// @notice Handles the liquidation of users' balances, once the users' amount of collateral is too low.
371 /// @dev Closed liquidations Only, 90% of extra shares goes to caller and 10% to protocol
372 /// @param users An array of user addresses.
373 /// @param maxBorrowParts A one-to-one mapping to `users`, contains maximum (partial) borrow amounts (to liquidate) of the respective user.
374 /// @param swapper Contract address of the `MultiSwapper` implementation. See `setSwapper`.
375 /// @param swapData Swap necessar data
376 function _closedLiquidation(
377 address[] calldata users,
378 uint256[] calldata maxBorrowParts,
379 ISwapper swapper,
380 uint256 _exchangeRate,
381: bytes calldata swapData
File: tapioca-bar-audit/contracts/markets/singularity/Singularity.sol
/// @audit Missing: '@param data'
61 /// @notice The init function that acts as a constructor
62: function init(bytes calldata data) external onlyOnce {
/// @audit Missing: '@param amount'
229 /// @notice Adds `collateral` from msg.sender to the account `to`.
230 /// @param from Account to transfer shares from.
231 /// @param to The receiver of the tokens.
232 /// @param skim True if the amount should be skimmed from the deposit balance of msg.sender.
233 /// False if tokens from msg.sender in `yieldBox` should be transferred.
234 /// @param share The amount of shares to add for `to`.
235 function addCollateral(
236 address from,
237 address to,
238 bool skim,
239 uint256 amount,
240: uint256 share
/// @audit Missing: '@param _lqCollateralizationRate'
/// @audit Missing: '@param _liquidationMultiplier'
/// @audit Missing: '@param _minimumTargetUtilization'
/// @audit Missing: '@param _maximumTargetUtilization'
/// @audit Missing: '@param _minimumInterestPerSecond'
/// @audit Missing: '@param _maximumInterestPerSecond'
/// @audit Missing: '@param _interestElasticity'
487 /// @notice sets Singularity specific configuration
488 /// @dev values are updated only if > 0 or not address(0)
489 function setSingularityConfig(
490 uint256 _lqCollateralizationRate,
491 uint256 _liquidationMultiplier,
492 uint256 _minimumTargetUtilization,
493 uint256 _maximumTargetUtilization,
494 uint64 _minimumInterestPerSecond,
495 uint64 _maximumInterestPerSecond,
496 uint256 _interestElasticity
497: ) external onlyOwner {
/// @audit Missing: '@param _liquidationQueue'
/// @audit Missing: '@param _bidExecutionSwapper'
/// @audit Missing: '@param _usdoSwapper'
575 /// @notice sets LQ specific confinguration
576 function setLiquidationQueueConfig(
577 ILiquidationQueue _liquidationQueue,
578 address _bidExecutionSwapper,
579 address _usdoSwapper
580: ) external onlyOwner {
/// @audit Missing: '@param _module'
597 // ************************* //
598 // *** PRIVATE FUNCTIONS *** //
599 // ************************* //
600: function _extractModule(Module _module) private view returns (address) {
File: tapioca-bar-audit/contracts/Penrose.sol
/// @audit Missing: '@param _market'
261 /// @notice sets the main BigBang market
262 /// @dev needed for the variable debt computation
263: function setBigBangEthMarket(address _market) external onlyOwner {
/// @audit Missing: '@param _contract'
378 /// @notice Registers an existing Singularity market (without deployment)
379 /// @dev can only be called by the owner
380 /// @param mc The address of the master contract which must be already registered
381 function addSingularity(
382 address mc,
383 address _contract
384: ) external onlyOwner registeredSingularityMasterContract(mc) {
/// @audit Missing: '@param _contract'
411 /// @notice Registers an existing BigBang market (without deployment)
412 /// @dev can only be called by the owner
413 /// @param mc The address of the master contract which must be already registered
414 function addBigBang(
415 address mc,
416 address _contract
417: ) external onlyOwner registeredBigBangMasterContract(mc) {
/// @audit Missing: '@param mc'
/// @audit Missing: '@param data'
/// @audit Missing: '@param forceSuccess'
423 /// @notice Execute an only owner function inside of a Singularity or a BigBang market
424 function executeMarketFn(
425 address[] calldata mc,
426 bytes[] memory data,
427 bool forceSuccess
428 )
429 external
430 onlyOwner
431 notPaused
432: returns (bool[] memory success, bytes[] memory result)
/// @audit Missing: '@param _returnData'
469 // ************************* //
470 // *** PRIVATE FUNCTIONS *** //
471 // ************************* //
472 function _getRevertMsg(
473 bytes memory _returnData
474: ) private pure returns (string memory) {
/// @audit Missing: '@param market'
/// @audit Missing: '@param swapper'
/// @audit Missing: '@param dexData'
499 /// @notice Withdraw the balance of `feeTo`, swap asset into TAP and deposit it to yieldBox of `feeTo`
500 function _depositFeesToYieldBox(
501 IMarket market,
502 ISwapper swapper,
503: IPenrose.SwapData calldata dexData
File: tapioca-bar-audit/contracts/usd0/BaseUSDO.sol
/// @audit Missing: '@param airdropAdapterParams'
207 /// @notice inits multiHopBuyCollateral
208 /// @param from The user who sells
209 /// @param collateralAmount Extra collateral to be added
210 /// @param borrowAmount Borrowed amount that will be swapped into collateral
211 /// @param swapData Swap data used on destination chain for swapping USDO to the underlying TOFT token
212 /// @param lzData LayerZero specific data
213 /// @param externalData External contracts used for the cross chain operation
214 /// @param approvals array
215 function initMultiHopBuy(
216 address from,
217 uint256 collateralAmount,
218 uint256 borrowAmount,
219 IUSDOBase.ILeverageSwapData calldata swapData,
220 IUSDOBase.ILeverageLZData calldata lzData,
221 IUSDOBase.ILeverageExternalContractsData calldata externalData,
222 bytes calldata airdropAdapterParams,
223: ICommonData.IApproval[] memory approvals
/// @audit Missing: '@param zroPaymentAddress'
305 /// @notice sends to YieldBox over layer and lends asset to market
306 /// @param _from sending address
307 /// @param _to receiver address
308 /// @param lzDstChainId LayerZero destination chain id
309 /// @param lendParams lend specific params
310 /// @param approvals approvals specific params
311 /// @param withdrawParams parameter to withdraw the SGL collateral
312 /// @param adapterParams adapter params of the withdrawn collateral
313 function sendAndLendOrRepay(
314 address _from,
315 address _to,
316 uint16 lzDstChainId,
317 address zroPaymentAddress,
318 IUSDOBase.ILendOrRepayParams calldata lendParams,
319 ICommonData.IApproval[] calldata approvals,
320 ICommonData.IWithdrawParams calldata withdrawParams,
321: bytes calldata adapterParams
/// @audit Missing: '@param _module'
340 // ************************* //
341 // *** PRIVATE FUNCTIONS *** //
342 // ************************* //
343
344: function _extractModule(Module _module) private view returns (address) {
File: tapioca-bar-audit/contracts/usd0/USDO.sol
/// @audit Missing: '@param _marketModule'
/// @audit Missing: '@param _optionsModule'
30 /// @notice creates a new USDO0 OFT contract
31 /// @param _lzEndpoint LayerZero endpoint
32 /// @param _yieldBox the YieldBox address
33 /// @param _owner owner address
34 /// @param _leverageModule USDOLeverageModule address
35 constructor(
36 address _lzEndpoint,
37 IYieldBoxBase _yieldBox,
38 address _owner,
39 address payable _leverageModule,
40 address payable _marketModule,
41 address payable _optionsModule
42 )
43 BaseUSDO(
44 _lzEndpoint,
45 _yieldBox,
46 _owner,
47 _leverageModule,
48 _marketModule,
49 _optionsModule
50: )
/// @audit Missing: '@param address'
53 // ********************** //
54 // *** VIEW FUNCTIONS *** //
55 // ********************** //
56 /// @notice returns the maximum amount of tokens available for a flash mint
57: function maxFlashLoan(address) public view override returns (uint256) {
File: tapiocaz-audit/contracts/Balancer.sol
/// @audit Missing: '@param _srcOft'
/// @audit Missing: '@param _dstChainId'
133 // ************************ //
134 // *** PUBLIC FUNCTIONS *** //
135 // ************************ //
136
137 function checker(
138 address payable _srcOft,
139 uint16 _dstChainId
140: ) external view returns (bool canExec, bytes memory execPayload) {
/// @audit Missing: '@param _srcOft'
/// @audit Missing: '@param _dstOft'
/// @audit Missing: '@param _dstChainId'
264 // ************************* //
265 // *** PRIVATE FUNCTIONS *** //
266 // ***********************
Acknowledged
Confirmed
Confirmed
Confirmed
Confirmed
Related to M-03? Confirmed
Confirmed