Contract changes

NestContracts

All contracts are forked from the PieDao deployment on the Ethereum Mainnet, with some minor changes that to allow them to function on Pollygon. These changes are detailed below. In order to understand the smart contract setup and query the nests correctly, you will have to familiarize yourself with the Diamond Standard architecture, with which these contracts where build https://eips.ethereum.org/EIPS/eip-2535.

Contract Changes

The original contracts deployed by PieDao can be found here: https://docs.piedao.org/technical/deployed-smart-contracts The contracts where ported as is from the PieDaos implementation on Main net with a few exceptions: On the Polygon network the Aave protocol requires the sender to state the address where the amTokens or underlying tokens should be send when depositing or withdrawing. This required small changes in the following contracts: ILendingLogic.sol
1
function lend(address _underlying, uint256 _amount, address _tokenHolder) external view returns(address[] memory targets, bytes[] memory data);
2
​
3
function unlend(address _wrapped, uint256 _amount, address _tokenHolder) external view returns(address[] memory targets, bytes[] memory data);
Copied!
LendingRegestry.sol
1
function getLendTXData(address _underlying, uint256 _amount, address _tokenHolder, bytes32 _protocol) external view returns(address[] memory targets, bytes[] memory data) {
2
ILendingLogic lendingLogic = ILendingLogic(protocolToLogic[_protocol]);
3
require(address(lendingLogic) != address(0), "NO_LENDING_LOGIC_SET");
4
​
5
return lendingLogic.lend(_underlying, _amount, _tokenHolder);
6
}
Copied!
AaveLendingLogic.sol
1
function lend(address _underlying,uint256 _amount, address _tokenHolder) external view override returns(address[] memory targets, bytes[] memory data) {
2
[...]
3
data[2] = abi.encodeWithSelector(lendingPool.deposit.selector, _underlying, _amount, _tokenHolder, referralCode);
4
}
5
​
6
function unlend(address _wrapped, uint256 _amount,address _tokenHolder) external view override returns(address[] memory targets, bytes[] memory data) {
7
[...]
8
data[0] = abi.encodeWithSelector(
9
lendingPool.withdraw.selector,
10
wrapped.UNDERLYING_ASSET_ADDRESS(),
11
_amount,
12
_tokenHolder
13
);
14
}
Copied!
CREAMLendingLogic.sol
1
function lend(address _underlying, uint256 _amount, address _tokenHolder) external view override returns(address[] memory targets, bytes[] memory data) {
2
}
3
​
4
function unlend(address _wrapped, uint256 _amount, address _tokenHolder) external view override returns(address[] memory targets, bytes[] memory data) {
5
}
Copied!
The contracts listed above do not have any access to the funds that are held by the nest. Worst case scenario, errors in these contracts would result in user minting a wrong amount of a nest or the user would fail to mint the nest.
LendingManger.sol
Changing the LendingManager requires increased vigilance, as it has direct access to the Nests funds. This is the only change made to the LendingManager:
BEFORE CHANGE
1
) = lendingRegistry.getLendTXData(_underlying, amount, _protocol);
Copied!
AFTER CHANGE
1
) = lendingRegistry.getLendTXData(_underlying, amount, address(basket),_protocol);
Copied!
The basket constant is set on deployment and cannot be changed retroactively.
1
constructor(address _lendingRegistry, address _basket) public {
2
require(_lendingRegistry != address(0), "INVALID_LENDING_REGISTRY");
3
require(_basket != address(0), "INVALID_BASKET");
4
lendingRegistry = LendingRegistry(_lendingRegistry);
5
basket = IExperiPie(_basket);
6
}
Copied!
The basket address is the address of the nest that the LendingManager is assigned to.
The "Recipe" contract is used to swap the users wETH for the index assets and lend them in a specific protocol when needed. As the recipe does not have access to any funds deposited in the index, we felt like more liberties could be made adjusting the code. The following is a change that allows us to take an entry fee that is exchanged for polly and then burned:
1
if(remainingInputBalance > 0 && feeAmount != 0) {
2
WETH.approve(address(sushiRouter), 0);
3
WETH.approve(address(sushiRouter), type(uint256).max);
4
address[] memory route = getRoute(address(WETH), baoAddress);
5
uint256 estimatedAmount = sushiRouter.getAmountsOut(feeAmount, route)[1];
6
sushiRouter.swapExactTokensForTokens(feeAmount, estimatedAmount, route, address(this), block.timestamp + 1);
7
baoToken.burn(baoToken.balanceOf(address(this)));
8
}
Copied!
Originally the recipe always looks at Uniswap and SushiSwap to identify the best price. The new Recipe does not check the prices and only trades on SushiSwap.
1
function getBestPriceSushiUni(address _inputToken, address _outputToken, uint256 _outputAmount) internal returns(uint256, DexChoice) {
2
uint256 sushiAmount = getPriceUniLike(_inputToken, _outputToken, _outputAmount, sushiRouter);
3
​
4
return (sushiAmount, DexChoice.Sushi);
5
}
Copied!

Changes difference

Fabiaz from the Quality Assurance Galaxy put a detailed comparaison between the two versions of the code here : Fabiaz diff comparaison on GitHub​
Last modified 2mo ago