Fixed swap rate tests

This commit is contained in:
The3D 2020-07-07 12:07:31 +02:00
parent 0d182d6436
commit dd1982010c
20 changed files with 188 additions and 832 deletions

View File

@ -245,16 +245,17 @@ library ValidationLogic {
) external view { ) external view {
require(_reserve.isActive, 'Action requires an active reserve'); require(_reserve.isActive, 'Action requires an active reserve');
require(!_reserve.isFreezed, 'Action requires an unfreezed reserve'); require(!_reserve.isFreezed, 'Action requires an unfreezed reserve');
if (_currentRateMode == CoreLibrary.InterestRateMode.STABLE) {
require( require(
_currentRateMode == CoreLibrary.InterestRateMode.STABLE && _stableBorrowBalance > 0, _stableBorrowBalance > 0,
'User does not have a stable rate loan in progress on this reserve' 'User does not have a stable rate loan in progress on this reserve'
); );
} else if (_currentRateMode == CoreLibrary.InterestRateMode.VARIABLE) {
require( require(
_currentRateMode == CoreLibrary.InterestRateMode.VARIABLE && _variableBorrowBalance > 0, _variableBorrowBalance > 0,
'User does not have a variable rate loan in progress on this reserve' 'User does not have a variable rate loan in progress on this reserve'
); );
if (_currentRateMode == CoreLibrary.InterestRateMode.VARIABLE) {
/** /**
* user wants to swap to stable, before swapping we need to ensure that * user wants to swap to stable, before swapping we need to ensure that
* 1. stable borrow rate is enabled on the reserve * 1. stable borrow rate is enabled on the reserve
@ -272,6 +273,9 @@ library ValidationLogic {
'12' '12'
); );
} }
else {
revert("Invalid interest rate mode selected");
}
} }
/** /**

673
package-lock.json generated
View File

@ -4213,679 +4213,6 @@
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
"dev": true "dev": true
}, },
"ganache-cli": {
"version": "6.9.1",
"resolved": "https://registry.npmjs.org/ganache-cli/-/ganache-cli-6.9.1.tgz",
"integrity": "sha512-VPBumkNUZzXDRQwVOby5YyQpd5t1clkr06xMgB28lZdEIn5ht1GMwUskOTFOAxdkQ4J12IWP0gdeacVRGowqbA==",
"dev": true,
"requires": {
"ethereumjs-util": "6.1.0",
"source-map-support": "0.5.12",
"yargs": "13.2.4"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"bundled": true,
"dev": true
},
"ansi-styles": {
"version": "3.2.1",
"bundled": true,
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"bindings": {
"version": "1.5.0",
"bundled": true,
"dev": true,
"requires": {
"file-uri-to-path": "1.0.0"
}
},
"bip66": {
"version": "1.1.5",
"bundled": true,
"dev": true,
"requires": {
"safe-buffer": "^5.0.1"
}
},
"bn.js": {
"version": "4.11.8",
"bundled": true,
"dev": true
},
"brorand": {
"version": "1.1.0",
"bundled": true,
"dev": true
},
"browserify-aes": {
"version": "1.2.0",
"bundled": true,
"dev": true,
"requires": {
"buffer-xor": "^1.0.3",
"cipher-base": "^1.0.0",
"create-hash": "^1.1.0",
"evp_bytestokey": "^1.0.3",
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
"buffer-from": {
"version": "1.1.1",
"bundled": true,
"dev": true
},
"buffer-xor": {
"version": "1.0.3",
"bundled": true,
"dev": true
},
"camelcase": {
"version": "5.3.1",
"bundled": true,
"dev": true
},
"cipher-base": {
"version": "1.0.4",
"bundled": true,
"dev": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
"cliui": {
"version": "5.0.0",
"bundled": true,
"dev": true,
"requires": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
}
},
"color-convert": {
"version": "1.9.3",
"bundled": true,
"dev": true,
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"bundled": true,
"dev": true
},
"create-hash": {
"version": "1.2.0",
"bundled": true,
"dev": true,
"requires": {
"cipher-base": "^1.0.1",
"inherits": "^2.0.1",
"md5.js": "^1.3.4",
"ripemd160": "^2.0.1",
"sha.js": "^2.4.0"
}
},
"create-hmac": {
"version": "1.1.7",
"bundled": true,
"dev": true,
"requires": {
"cipher-base": "^1.0.3",
"create-hash": "^1.1.0",
"inherits": "^2.0.1",
"ripemd160": "^2.0.0",
"safe-buffer": "^5.0.1",
"sha.js": "^2.4.8"
}
},
"cross-spawn": {
"version": "6.0.5",
"bundled": true,
"dev": true,
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"decamelize": {
"version": "1.2.0",
"bundled": true,
"dev": true
},
"drbg.js": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"requires": {
"browserify-aes": "^1.0.6",
"create-hash": "^1.1.2",
"create-hmac": "^1.1.4"
}
},
"elliptic": {
"version": "6.5.0",
"bundled": true,
"dev": true,
"requires": {
"bn.js": "^4.4.0",
"brorand": "^1.0.1",
"hash.js": "^1.0.0",
"hmac-drbg": "^1.0.0",
"inherits": "^2.0.1",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.0"
}
},
"emoji-regex": {
"version": "7.0.3",
"bundled": true,
"dev": true
},
"end-of-stream": {
"version": "1.4.1",
"bundled": true,
"dev": true,
"requires": {
"once": "^1.4.0"
}
},
"ethereumjs-util": {
"version": "6.1.0",
"bundled": true,
"dev": true,
"requires": {
"bn.js": "^4.11.0",
"create-hash": "^1.1.2",
"ethjs-util": "0.1.6",
"keccak": "^1.0.2",
"rlp": "^2.0.0",
"safe-buffer": "^5.1.1",
"secp256k1": "^3.0.1"
}
},
"ethjs-util": {
"version": "0.1.6",
"bundled": true,
"dev": true,
"requires": {
"is-hex-prefixed": "1.0.0",
"strip-hex-prefix": "1.0.0"
}
},
"evp_bytestokey": {
"version": "1.0.3",
"bundled": true,
"dev": true,
"requires": {
"md5.js": "^1.3.4",
"safe-buffer": "^5.1.1"
}
},
"execa": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"requires": {
"cross-spawn": "^6.0.0",
"get-stream": "^4.0.0",
"is-stream": "^1.1.0",
"npm-run-path": "^2.0.0",
"p-finally": "^1.0.0",
"signal-exit": "^3.0.0",
"strip-eof": "^1.0.0"
}
},
"file-uri-to-path": {
"version": "1.0.0",
"bundled": true,
"dev": true
},
"find-up": {
"version": "3.0.0",
"bundled": true,
"dev": true,
"requires": {
"locate-path": "^3.0.0"
}
},
"get-caller-file": {
"version": "2.0.5",
"bundled": true,
"dev": true
},
"get-stream": {
"version": "4.1.0",
"bundled": true,
"dev": true,
"requires": {
"pump": "^3.0.0"
}
},
"hash-base": {
"version": "3.0.4",
"bundled": true,
"dev": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
"hash.js": {
"version": "1.1.7",
"bundled": true,
"dev": true,
"requires": {
"inherits": "^2.0.3",
"minimalistic-assert": "^1.0.1"
}
},
"hmac-drbg": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"requires": {
"hash.js": "^1.0.3",
"minimalistic-assert": "^1.0.0",
"minimalistic-crypto-utils": "^1.0.1"
}
},
"inherits": {
"version": "2.0.4",
"bundled": true,
"dev": true
},
"invert-kv": {
"version": "2.0.0",
"bundled": true,
"dev": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"bundled": true,
"dev": true
},
"is-hex-prefixed": {
"version": "1.0.0",
"bundled": true,
"dev": true
},
"is-stream": {
"version": "1.1.0",
"bundled": true,
"dev": true
},
"isexe": {
"version": "2.0.0",
"bundled": true,
"dev": true
},
"keccak": {
"version": "1.4.0",
"bundled": true,
"dev": true,
"requires": {
"bindings": "^1.2.1",
"inherits": "^2.0.3",
"nan": "^2.2.1",
"safe-buffer": "^5.1.0"
}
},
"lcid": {
"version": "2.0.0",
"bundled": true,
"dev": true,
"requires": {
"invert-kv": "^2.0.0"
}
},
"locate-path": {
"version": "3.0.0",
"bundled": true,
"dev": true,
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
}
},
"map-age-cleaner": {
"version": "0.1.3",
"bundled": true,
"dev": true,
"requires": {
"p-defer": "^1.0.0"
}
},
"md5.js": {
"version": "1.3.5",
"bundled": true,
"dev": true,
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1",
"safe-buffer": "^5.1.2"
}
},
"mem": {
"version": "4.3.0",
"bundled": true,
"dev": true,
"requires": {
"map-age-cleaner": "^0.1.1",
"mimic-fn": "^2.0.0",
"p-is-promise": "^2.0.0"
}
},
"mimic-fn": {
"version": "2.1.0",
"bundled": true,
"dev": true
},
"minimalistic-assert": {
"version": "1.0.1",
"bundled": true,
"dev": true
},
"minimalistic-crypto-utils": {
"version": "1.0.1",
"bundled": true,
"dev": true
},
"nan": {
"version": "2.14.0",
"bundled": true,
"dev": true
},
"nice-try": {
"version": "1.0.5",
"bundled": true,
"dev": true
},
"npm-run-path": {
"version": "2.0.2",
"bundled": true,
"dev": true,
"requires": {
"path-key": "^2.0.0"
}
},
"once": {
"version": "1.4.0",
"bundled": true,
"dev": true,
"requires": {
"wrappy": "1"
}
},
"os-locale": {
"version": "3.1.0",
"bundled": true,
"dev": true,
"requires": {
"execa": "^1.0.0",
"lcid": "^2.0.0",
"mem": "^4.0.0"
}
},
"p-defer": {
"version": "1.0.0",
"bundled": true,
"dev": true
},
"p-finally": {
"version": "1.0.0",
"bundled": true,
"dev": true
},
"p-is-promise": {
"version": "2.1.0",
"bundled": true,
"dev": true
},
"p-limit": {
"version": "2.2.0",
"bundled": true,
"dev": true,
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "3.0.0",
"bundled": true,
"dev": true,
"requires": {
"p-limit": "^2.0.0"
}
},
"p-try": {
"version": "2.2.0",
"bundled": true,
"dev": true
},
"path-exists": {
"version": "3.0.0",
"bundled": true,
"dev": true
},
"path-key": {
"version": "2.0.1",
"bundled": true,
"dev": true
},
"pump": {
"version": "3.0.0",
"bundled": true,
"dev": true,
"requires": {
"end-of-stream": "^1.1.0",
"once": "^1.3.1"
}
},
"require-directory": {
"version": "2.1.1",
"bundled": true,
"dev": true
},
"require-main-filename": {
"version": "2.0.0",
"bundled": true,
"dev": true
},
"ripemd160": {
"version": "2.0.2",
"bundled": true,
"dev": true,
"requires": {
"hash-base": "^3.0.0",
"inherits": "^2.0.1"
}
},
"rlp": {
"version": "2.2.3",
"bundled": true,
"dev": true,
"requires": {
"bn.js": "^4.11.1",
"safe-buffer": "^5.1.1"
}
},
"safe-buffer": {
"version": "5.2.0",
"bundled": true,
"dev": true
},
"secp256k1": {
"version": "3.7.1",
"bundled": true,
"dev": true,
"requires": {
"bindings": "^1.5.0",
"bip66": "^1.1.5",
"bn.js": "^4.11.8",
"create-hash": "^1.2.0",
"drbg.js": "^1.0.1",
"elliptic": "^6.4.1",
"nan": "^2.14.0",
"safe-buffer": "^5.1.2"
}
},
"semver": {
"version": "5.7.0",
"bundled": true,
"dev": true
},
"set-blocking": {
"version": "2.0.0",
"bundled": true,
"dev": true
},
"sha.js": {
"version": "2.4.11",
"bundled": true,
"dev": true,
"requires": {
"inherits": "^2.0.1",
"safe-buffer": "^5.0.1"
}
},
"shebang-command": {
"version": "1.2.0",
"bundled": true,
"dev": true,
"requires": {
"shebang-regex": "^1.0.0"
}
},
"shebang-regex": {
"version": "1.0.0",
"bundled": true,
"dev": true
},
"signal-exit": {
"version": "3.0.2",
"bundled": true,
"dev": true
},
"source-map": {
"version": "0.6.1",
"bundled": true,
"dev": true
},
"source-map-support": {
"version": "0.5.12",
"bundled": true,
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"string-width": {
"version": "3.1.0",
"bundled": true,
"dev": true,
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"bundled": true,
"dev": true,
"requires": {
"ansi-regex": "^4.1.0"
}
},
"strip-eof": {
"version": "1.0.0",
"bundled": true,
"dev": true
},
"strip-hex-prefix": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"requires": {
"is-hex-prefixed": "1.0.0"
}
},
"which": {
"version": "1.3.1",
"bundled": true,
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
},
"which-module": {
"version": "2.0.0",
"bundled": true,
"dev": true
},
"wrap-ansi": {
"version": "5.1.0",
"bundled": true,
"dev": true,
"requires": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
}
},
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
},
"y18n": {
"version": "4.0.0",
"bundled": true,
"dev": true
},
"yargs": {
"version": "13.2.4",
"bundled": true,
"dev": true,
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"os-locale": "^3.1.0",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.0"
}
},
"yargs-parser": {
"version": "13.1.1",
"bundled": true,
"dev": true,
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},
"ganache-core": { "ganache-core": {
"version": "2.10.2", "version": "2.10.2",
"resolved": "https://registry.npmjs.org/ganache-core/-/ganache-core-2.10.2.tgz", "resolved": "https://registry.npmjs.org/ganache-core/-/ganache-core-2.10.2.tgz",

View File

@ -350,6 +350,10 @@ export const borrow = async (
timestamp, timestamp,
txCost txCost
); );
console.log(userDataAfter.stableBorrowRate.toFixed(), expectedUserData.stableBorrowRate.toFixed());
console.log(userDataAfter.principalStableBorrowBalance.toFixed(), expectedUserData.principalStableBorrowBalance.toFixed());
expectEqual(reserveDataAfter, expectedReserveData); expectEqual(reserveDataAfter, expectedReserveData);
expectEqual(userDataAfter, expectedUserData); expectEqual(userDataAfter, expectedUserData);
@ -555,6 +559,7 @@ export const setUseAsCollateral = async (
export const swapBorrowRateMode = async ( export const swapBorrowRateMode = async (
reserveSymbol: string, reserveSymbol: string,
user: SignerWithAddress, user: SignerWithAddress,
rateMode: string,
expectedResult: string, expectedResult: string,
testEnv: TestEnv, testEnv: TestEnv,
revertMessage?: string revertMessage?: string
@ -570,7 +575,7 @@ export const swapBorrowRateMode = async (
); );
if (expectedResult === 'success') { if (expectedResult === 'success') {
const txResult = await waitForTx(await pool.connect(user.signer).swapBorrowRateMode(reserve)); const txResult = await waitForTx(await pool.connect(user.signer).swapBorrowRateMode(reserve, rateMode));
const {txCost, txTimestamp} = await getTxCostAndTimestamp(txResult); const {txCost, txTimestamp} = await getTxCostAndTimestamp(txResult);
@ -583,6 +588,7 @@ export const swapBorrowRateMode = async (
const expectedReserveData = calcExpectedReserveDataAfterSwapRateMode( const expectedReserveData = calcExpectedReserveDataAfterSwapRateMode(
reserveDataBefore, reserveDataBefore,
userDataBefore, userDataBefore,
rateMode,
txTimestamp txTimestamp
); );
@ -590,6 +596,7 @@ export const swapBorrowRateMode = async (
reserveDataBefore, reserveDataBefore,
expectedReserveData, expectedReserveData,
userDataBefore, userDataBefore,
rateMode,
txCost, txCost,
txTimestamp txTimestamp
); );
@ -607,7 +614,7 @@ export const swapBorrowRateMode = async (
// ); // );
// }); // });
} else if (expectedResult === 'revert') { } else if (expectedResult === 'revert') {
await expect(pool.connect(user.signer).swapBorrowRateMode(reserve), revertMessage).to.be await expect(pool.connect(user.signer).swapBorrowRateMode(reserve, rateMode), revertMessage).to.be
.reverted; .reverted;
} }
}; };

View File

@ -45,7 +45,7 @@ const executeAction = async (
users: SignerWithAddress[], users: SignerWithAddress[],
testEnv: TestEnv testEnv: TestEnv
) => { ) => {
const {reserve, user: userIndex} = action.args; const {reserve, user: userIndex, borrowRateMode} = action.args;
const {name, expected, revertMessage} = action; const {name, expected, revertMessage} = action;
if (!name || name === "") { if (!name || name === "") {
@ -62,6 +62,21 @@ const executeAction = async (
throw `An expected resut for action ${name} is required`; throw `An expected resut for action ${name} is required`;
} }
let rateMode: string = RateMode.None;
if(borrowRateMode) {
if (borrowRateMode === "none") {
RateMode.None;
} else if (borrowRateMode === "stable") {
rateMode = RateMode.Stable;
} else if (borrowRateMode === "variable") {
rateMode = RateMode.Variable;
} else {
//random value, to test improper selection of the parameter
rateMode = "4";
}
}
const user = users[parseInt(userIndex)]; const user = users[parseInt(userIndex)];
switch (name) { switch (name) {
@ -112,25 +127,12 @@ const executeAction = async (
break; break;
case "borrow": case "borrow":
{ {
const {amount, borrowRateMode, timeTravel} = action.args; const {amount, timeTravel} = action.args;
if (!amount || amount === "") { if (!amount || amount === "") {
throw `Invalid amount to borrow from the ${reserve} reserve`; throw `Invalid amount to borrow from the ${reserve} reserve`;
} }
let rateMode: string = RateMode.None;
if (borrowRateMode === "none") {
RateMode.None;
} else if (borrowRateMode === "stable") {
rateMode = RateMode.Stable;
} else if (borrowRateMode === "variable") {
rateMode = RateMode.Variable;
} else {
//random value, to test improper selection of the parameter
rateMode = "4";
}
await borrow( await borrow(
reserve, reserve,
amount, amount,
@ -152,18 +154,6 @@ const executeAction = async (
if (!amount || amount === "") { if (!amount || amount === "") {
throw `Invalid amount to repay into the ${reserve} reserve`; throw `Invalid amount to repay into the ${reserve} reserve`;
} }
let rateMode: string = RateMode.None;
if (borrowRateMode === "none") {
rateMode = RateMode.None;
} else if (borrowRateMode === "stable") {
rateMode = RateMode.Stable;
} else if (borrowRateMode === "variable") {
rateMode = RateMode.Variable;
} else {
//random value, to test improper selection of the parameter
rateMode = "4";
}
let userToRepayOnBehalf: SignerWithAddress; let userToRepayOnBehalf: SignerWithAddress;
if (!onBehalfOfIndex || onBehalfOfIndex === "") { if (!onBehalfOfIndex || onBehalfOfIndex === "") {
@ -175,8 +165,6 @@ const executeAction = async (
userToRepayOnBehalf = users[parseInt(onBehalfOfIndex)]; userToRepayOnBehalf = users[parseInt(onBehalfOfIndex)];
} }
console.log(user.address, userToRepayOnBehalf.address)
await repay( await repay(
reserve, reserve,
amount, amount,
@ -210,7 +198,7 @@ const executeAction = async (
break; break;
case "swapBorrowRateMode": case "swapBorrowRateMode":
await swapBorrowRateMode(reserve, user, expected, testEnv, revertMessage); await swapBorrowRateMode(reserve, user, rateMode, expected, testEnv, revertMessage);
break; break;
case "rebalanceStableBorrowRate": case "rebalanceStableBorrowRate":

View File

@ -10,10 +10,11 @@
"args": { "args": {
"reserve": "DAI", "reserve": "DAI",
"user": "0", "user": "0",
"target": "1" "target": "1",
"borrowRateMode": "variable"
}, },
"expected": "revert", "expected": "revert",
"revertMessage": "User does not have any borrow for this reserve" "revertMessage": "User does not have any stable rate loan for this reserve"
} }
] ]
}, },
@ -86,7 +87,8 @@
"name": "swapBorrowRateMode", "name": "swapBorrowRateMode",
"args": { "args": {
"reserve": "DAI", "reserve": "DAI",
"user": "1" "user": "1",
"borrowRateMode": "variable"
}, },
"expected": "success" "expected": "success"
}, },

View File

@ -3,16 +3,33 @@
"description": "Test cases for the swapBorrowRateMode() function.", "description": "Test cases for the swapBorrowRateMode() function.",
"stories": [ "stories": [
{ {
"description": "User 0 tries to swap rate mode without any borrow in progress (revert expected)", "description": "User 0 tries to swap rate mode without any variable rate loan in progress (revert expected)",
"actions": [ "actions": [
{ {
"name": "swapBorrowRateMode", "name": "swapBorrowRateMode",
"args": { "args": {
"reserve": "DAI", "reserve": "DAI",
"user": "1" "user": "1",
"borrowRateMode": "variable"
}, },
"expected": "revert", "expected": "revert",
"revertMessage": "User does not have a borrow in progress on this reserve" "revertMessage": "User does not have a variable rate loan in progress on this reserve"
}
]
},
{
"description": "User 0 tries to swap rate mode without any stable rate loan in progress (revert expected)",
"actions": [
{
"name": "swapBorrowRateMode",
"args": {
"reserve": "DAI",
"user": "1",
"borrowRateMode": "stable"
},
"expected": "revert",
"revertMessage": "User does not have a stable rate loan in progress on this reserve"
} }
] ]
}, },
@ -70,7 +87,8 @@
"name": "swapBorrowRateMode", "name": "swapBorrowRateMode",
"args": { "args": {
"reserve": "DAI", "reserve": "DAI",
"user": "1" "user": "1",
"borrowRateMode": "variable"
}, },
"expected": "success" "expected": "success"
} }
@ -94,7 +112,8 @@
"name": "swapBorrowRateMode", "name": "swapBorrowRateMode",
"args": { "args": {
"reserve": "DAI", "reserve": "DAI",
"user": "1" "user": "1",
"borrowRateMode": "stable"
}, },
"expected": "success" "expected": "success"
}, },
@ -122,7 +141,8 @@
"reserve": "DAI", "reserve": "DAI",
"amount": "-1", "amount": "-1",
"user": "1", "user": "1",
"onBehalfOf": "1" "onBehalfOf": "1",
"borrowRateMode": "variable"
}, },
"expected": "success" "expected": "success"
} }

View File

@ -326,6 +326,8 @@ export const calcExpectedReserveDataAfterBorrow = (
): ReserveData => { ): ReserveData => {
const expectedReserveData = <ReserveData>{}; const expectedReserveData = <ReserveData>{};
console.log('Computing borrow, amountBorrowed: ', amountBorrowed, ' Rate mode: ', borrowRateMode);
expectedReserveData.address = reserveDataBeforeAction.address; expectedReserveData.address = reserveDataBeforeAction.address;
const amountBorrowedBN = new BigNumber(amountBorrowed); const amountBorrowedBN = new BigNumber(amountBorrowed);
@ -354,8 +356,8 @@ export const calcExpectedReserveDataAfterBorrow = (
expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate( expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate(
reserveDataBeforeAction.averageStableBorrowRate, reserveDataBeforeAction.averageStableBorrowRate,
reserveDataBeforeAction.totalBorrowsStable, reserveDataBeforeAction.totalBorrowsStable.plus(debtAccrued),
userStableBorrowBalance.plus(amountBorrowedBN), amountBorrowedBN,
reserveDataBeforeAction.stableBorrowRate reserveDataBeforeAction.stableBorrowRate
); );
expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable; expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable;
@ -417,6 +419,8 @@ export const calcExpectedReserveDataAfterRepay = (
txTimestamp: BigNumber, txTimestamp: BigNumber,
currentTimestamp: BigNumber currentTimestamp: BigNumber
): ReserveData => { ): ReserveData => {
console.log('Computing repay, amount repaid: ', amountRepaid, ' Rate mode: ', borrowRateMode);
const expectedReserveData: ReserveData = <ReserveData>{}; const expectedReserveData: ReserveData = <ReserveData>{};
expectedReserveData.address = reserveDataBeforeAction.address; expectedReserveData.address = reserveDataBeforeAction.address;
@ -551,36 +555,39 @@ export const calcExpectedUserDataAfterBorrow = (
); );
if (interestRateMode == RateMode.Stable) { if (interestRateMode == RateMode.Stable) {
expectedUserData.principalStableBorrowBalance = currentStableBorrowBalance.plus( const debtAccrued = currentStableBorrowBalance.minus(
amountBorrowed userDataBeforeAction.principalStableBorrowBalance
); );
expectedUserData.principalVariableBorrowBalance = userDataBeforeAction.principalVariableBorrowBalance;
expectedUserData.stableBorrowRate = reserveDataBeforeAction.stableBorrowRate; expectedUserData.principalStableBorrowBalance = currentStableBorrowBalance.plus(amountBorrowed);
expectedUserData.principalVariableBorrowBalance =
userDataBeforeAction.principalVariableBorrowBalance;
expectedUserData.stableBorrowRate = calcExpectedUserStableRate(
userDataBeforeAction.principalStableBorrowBalance.plus(debtAccrued),
userDataBeforeAction.stableBorrowRate,
new BigNumber(amountBorrowed),
reserveDataBeforeAction.stableBorrowRate
);
expectedUserData.stableRateLastUpdated = txTimestamp; expectedUserData.stableRateLastUpdated = txTimestamp;
} else { } else {
expectedUserData.principalVariableBorrowBalance = currentVariableBorrowBalance.plus( expectedUserData.principalVariableBorrowBalance = currentVariableBorrowBalance.plus(
amountBorrowed amountBorrowed
); );
expectedUserData.principalStableBorrowBalance = userDataBeforeAction.principalStableBorrowBalance; expectedUserData.principalStableBorrowBalance =
userDataBeforeAction.principalStableBorrowBalance;
expectedUserData.stableBorrowRate = userDataBeforeAction.stableBorrowRate; expectedUserData.stableBorrowRate = userDataBeforeAction.stableBorrowRate;
expectedUserData.stableRateLastUpdated = userDataBeforeAction.stableRateLastUpdated; expectedUserData.stableRateLastUpdated = userDataBeforeAction.stableRateLastUpdated;
} }
//calculate also the accrued balance after the time passed
expectedUserData.currentStableBorrowBalance = calcExpectedStableDebtTokenBalance( expectedUserData.currentStableBorrowBalance = calcExpectedStableDebtTokenBalance(
{ {
...userDataBeforeAction, ...userDataBeforeAction,
currentStableBorrowBalance: expectedUserData.principalStableBorrowBalance, currentStableBorrowBalance: expectedUserData.principalStableBorrowBalance,
principalStableBorrowBalance: expectedUserData.principalStableBorrowBalance, principalStableBorrowBalance: expectedUserData.principalStableBorrowBalance,
stableBorrowRate: stableBorrowRate: expectedUserData.stableBorrowRate,
interestRateMode == RateMode.Stable
? reserveDataBeforeAction.stableBorrowRate
: userDataBeforeAction.stableBorrowRate,
stableRateLastUpdated: expectedUserData.stableRateLastUpdated, stableRateLastUpdated: expectedUserData.stableRateLastUpdated,
}, },
currentTimestamp currentTimestamp
@ -595,7 +602,7 @@ export const calcExpectedUserDataAfterBorrow = (
variableBorrowIndex: variableBorrowIndex:
interestRateMode == RateMode.Variable interestRateMode == RateMode.Variable
? expectedDataAfterAction.variableBorrowIndex ? expectedDataAfterAction.variableBorrowIndex
: userDataBeforeAction.variableBorrowIndex : userDataBeforeAction.variableBorrowIndex,
}, },
currentTimestamp currentTimestamp
); );
@ -669,7 +676,6 @@ export const calcExpectedUserDataAfterRepay = (
} }
if (rateMode == RateMode.Stable) { if (rateMode == RateMode.Stable) {
expectedUserData.principalVariableBorrowBalance = expectedUserData.principalVariableBorrowBalance =
userDataBeforeAction.principalVariableBorrowBalance; userDataBeforeAction.principalVariableBorrowBalance;
expectedUserData.currentVariableBorrowBalance = variableBorrowBalance; expectedUserData.currentVariableBorrowBalance = variableBorrowBalance;
@ -681,7 +687,9 @@ export const calcExpectedUserDataAfterRepay = (
if (expectedUserData.currentStableBorrowBalance.eq('0')) { if (expectedUserData.currentStableBorrowBalance.eq('0')) {
//user repaid everything //user repaid everything
expectedUserData.stableBorrowRate = expectedUserData.stableRateLastUpdated = new BigNumber('0'); expectedUserData.stableBorrowRate = expectedUserData.stableRateLastUpdated = new BigNumber(
'0'
);
} }
} else { } else {
expectedUserData.currentStableBorrowBalance = stableBorrowBalance; expectedUserData.currentStableBorrowBalance = stableBorrowBalance;
@ -755,29 +763,27 @@ export const calcExpectedUserDataAfterSetUseAsCollateral = (
export const calcExpectedReserveDataAfterSwapRateMode = ( export const calcExpectedReserveDataAfterSwapRateMode = (
reserveDataBeforeAction: ReserveData, reserveDataBeforeAction: ReserveData,
userDataBeforeAction: UserReserveData, userDataBeforeAction: UserReserveData,
rateMode: string,
txTimestamp: BigNumber txTimestamp: BigNumber
): ReserveData => { ): ReserveData => {
console.log('Computing swap, Rate mode: ', rateMode);
const expectedReserveData: ReserveData = <ReserveData>{}; const expectedReserveData: ReserveData = <ReserveData>{};
expectedReserveData.address = reserveDataBeforeAction.address; expectedReserveData.address = reserveDataBeforeAction.address;
let userBalanceIncrease: BigNumber = new BigNumber(0);
const variableBorrowBalance = calcExpectedVariableDebtTokenBalance( const variableBorrowBalance = calcExpectedVariableDebtTokenBalance(
reserveDataBeforeAction, reserveDataBeforeAction,
userDataBeforeAction, userDataBeforeAction,
txTimestamp txTimestamp
); );
const stableBorrowBalance = calcExpectedStableDebtTokenBalance( const stableBorrowBalance = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp);
userDataBeforeAction,
txTimestamp
);
expectedReserveData.availableLiquidity = reserveDataBeforeAction.availableLiquidity; expectedReserveData.availableLiquidity = reserveDataBeforeAction.availableLiquidity;
if (userDataBeforeAction.borrowRateMode === RateMode.Stable) { if (rateMode === RateMode.Stable) {
//swap to variable //swap user stable debt to variable
const debtAccrued = stableBorrowBalance.minus( const debtAccrued = stableBorrowBalance.minus(
userDataBeforeAction.principalStableBorrowBalance userDataBeforeAction.principalStableBorrowBalance
); );
@ -786,22 +792,27 @@ export const calcExpectedReserveDataAfterSwapRateMode = (
expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate( expectedReserveData.averageStableBorrowRate = calcExpectedAverageStableBorrowRate(
reserveDataBeforeAction.averageStableBorrowRate, reserveDataBeforeAction.averageStableBorrowRate,
reserveDataBeforeAction.totalBorrowsStable.plus(userBalanceIncrease), reserveDataBeforeAction.totalBorrowsStable.plus(debtAccrued),
stableBorrowBalance.negated(), stableBorrowBalance.negated(),
userDataBeforeAction.stableBorrowRate userDataBeforeAction.stableBorrowRate
); );
expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable.plus( expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable.plus(
stableBorrowBalance stableBorrowBalance
); );
} else {
const debtAccrued = stableBorrowBalance.minus( expectedReserveData.totalBorrowsStable = reserveDataBeforeAction.totalBorrowsStable.minus(
userDataBeforeAction.principalStableBorrowBalance userDataBeforeAction.principalStableBorrowBalance
); );
} else {
const debtAccrued = variableBorrowBalance.minus(
userDataBeforeAction.principalVariableBorrowBalance
);
expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued); expectedReserveData.totalLiquidity = reserveDataBeforeAction.totalLiquidity.plus(debtAccrued);
expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable expectedReserveData.totalBorrowsVariable = reserveDataBeforeAction.totalBorrowsVariable.minus(
.plus(debtAccrued) userDataBeforeAction.principalVariableBorrowBalance
.minus(variableBorrowBalance); );
expectedReserveData.totalBorrowsStable = reserveDataBeforeAction.totalBorrowsStable.plus( expectedReserveData.totalBorrowsStable = reserveDataBeforeAction.totalBorrowsStable.plus(
variableBorrowBalance variableBorrowBalance
@ -850,6 +861,7 @@ export const calcExpectedUserDataAfterSwapRateMode = (
reserveDataBeforeAction: ReserveData, reserveDataBeforeAction: ReserveData,
expectedDataAfterAction: ReserveData, expectedDataAfterAction: ReserveData,
userDataBeforeAction: UserReserveData, userDataBeforeAction: UserReserveData,
rateMode: string,
txCost: BigNumber, txCost: BigNumber,
txTimestamp: BigNumber txTimestamp: BigNumber
): UserReserveData => { ): UserReserveData => {
@ -861,16 +873,14 @@ export const calcExpectedUserDataAfterSwapRateMode = (
txTimestamp txTimestamp
); );
const stableBorrowBalance = calcExpectedStableDebtTokenBalance( const stableBorrowBalance = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp);
userDataBeforeAction,
txTimestamp
);
expectedUserData.currentATokenBalance = calcExpectedATokenBalance( expectedUserData.currentATokenBalance = calcExpectedATokenBalance(
reserveDataBeforeAction, reserveDataBeforeAction,
userDataBeforeAction, userDataBeforeAction,
txTimestamp txTimestamp
); );
expectedUserData.principalATokenBalance = userDataBeforeAction.principalATokenBalance; expectedUserData.principalATokenBalance = userDataBeforeAction.principalATokenBalance;
expectedUserData.redirectedBalance = userDataBeforeAction.redirectedBalance; expectedUserData.redirectedBalance = userDataBeforeAction.redirectedBalance;
expectedUserData.interestRedirectionAddress = userDataBeforeAction.interestRedirectionAddress; expectedUserData.interestRedirectionAddress = userDataBeforeAction.interestRedirectionAddress;
@ -883,31 +893,38 @@ export const calcExpectedUserDataAfterSwapRateMode = (
txTimestamp txTimestamp
); );
if (userDataBeforeAction.borrowRateMode === RateMode.Stable) { if (rateMode === RateMode.Stable) {
expectedUserData.currentStableBorrowBalance = new BigNumber(0); // swap to variable
expectedUserData.currentStableBorrowBalance = expectedUserData.principalStableBorrowBalance = new BigNumber(
0
);
expectedUserData.stableBorrowRate = new BigNumber(0); expectedUserData.stableBorrowRate = new BigNumber(0);
expectedUserData.currentVariableBorrowBalance = userDataBeforeAction.currentVariableBorrowBalance.plus(
expectedUserData.principalVariableBorrowBalance = expectedUserData.currentVariableBorrowBalance = userDataBeforeAction.currentVariableBorrowBalance.plus(
stableBorrowBalance stableBorrowBalance
); );
expectedUserData.variableBorrowIndex = expectedDataAfterAction.variableBorrowIndex; expectedUserData.variableBorrowIndex = expectedDataAfterAction.variableBorrowIndex;
expectedUserData.stableRateLastUpdated = new BigNumber(0);
} else { } else {
expectedUserData.currentStableBorrowBalance = userDataBeforeAction.currentStableBorrowBalance.plus( expectedUserData.principalStableBorrowBalance = expectedUserData.currentStableBorrowBalance = userDataBeforeAction.currentStableBorrowBalance.plus(
variableBorrowBalance variableBorrowBalance
); );
expectedUserData.principalStableBorrowBalance = expectedUserData.currentStableBorrowBalance;
//weighted average of the previous and the current //weighted average of the previous and the current
expectedUserData.stableBorrowRate = userDataBeforeAction.currentVariableBorrowBalance expectedUserData.stableBorrowRate = calcExpectedUserStableRate(
.times(userDataBeforeAction.stableBorrowRate) userDataBeforeAction.principalStableBorrowBalance,
.plus(variableBorrowBalance.times(reserveDataBeforeAction.stableBorrowRate)) userDataBeforeAction.stableBorrowRate,
.div(expectedUserData.currentStableBorrowBalance); variableBorrowBalance,
reserveDataBeforeAction.stableBorrowRate
expectedUserData.currentVariableBorrowBalance = userDataBeforeAction.currentVariableBorrowBalance.plus( );
stableBorrowBalance
expectedUserData.stableRateLastUpdated = txTimestamp;
expectedUserData.currentVariableBorrowBalance = expectedUserData.principalVariableBorrowBalance = new BigNumber(
0
); );
expectedUserData.variableBorrowIndex = expectedDataAfterAction.variableBorrowIndex;
expectedUserData.borrowRate = reserveDataBeforeAction.stableBorrowRate;
expectedUserData.variableBorrowIndex = new BigNumber(0); expectedUserData.variableBorrowIndex = new BigNumber(0);
} }
@ -928,10 +945,7 @@ export const calcExpectedReserveDataAfterStableRateRebalance = (
expectedReserveData.address = reserveDataBeforeAction.address; expectedReserveData.address = reserveDataBeforeAction.address;
const stableBorrowBalance = calcExpectedStableDebtTokenBalance( const stableBorrowBalance = calcExpectedStableDebtTokenBalance(userDataBeforeAction, txTimestamp);
userDataBeforeAction,
txTimestamp
);
const debtAccrued = stableBorrowBalance.minus(userDataBeforeAction.principalStableBorrowBalance); const debtAccrued = stableBorrowBalance.minus(userDataBeforeAction.principalStableBorrowBalance);
@ -1249,7 +1263,11 @@ const calcExpectedStableDebtTokenBalance = (
stableRateLastUpdated, stableRateLastUpdated,
} = userDataBeforeAction; } = userDataBeforeAction;
if (stableBorrowRate.eq(0) || currentTimestamp.eq(stableRateLastUpdated) || stableRateLastUpdated.eq(0)) { if (
stableBorrowRate.eq(0) ||
currentTimestamp.eq(stableRateLastUpdated) ||
stableRateLastUpdated.eq(0)
) {
return principalStableBorrowBalance; return principalStableBorrowBalance;
} }
@ -1427,6 +1445,18 @@ const calcExpectedReserveNormalizedDebt = (
return debt; return debt;
}; };
const calcExpectedUserStableRate = (
balanceBefore: BigNumber,
rateBefore: BigNumber,
amount: BigNumber,
rateNew: BigNumber
) => {
return balanceBefore
.times(rateBefore)
.plus(amount.times(rateNew))
.div(balanceBefore.plus(amount));
};
const calcExpectedLiquidityIndex = (reserveData: ReserveData, timestamp: BigNumber) => { const calcExpectedLiquidityIndex = (reserveData: ReserveData, timestamp: BigNumber) => {
//if utilization rate is 0, nothing to compound //if utilization rate is 0, nothing to compound
if (reserveData.utilizationRate.eq('0')) { if (reserveData.utilizationRate.eq('0')) {

View File

@ -12,7 +12,7 @@ BigNumber.config({DECIMAL_PLACES: 0, ROUNDING_MODE: BigNumber.ROUND_DOWN});
const scenarioFolder = './test/helpers/scenarios/'; const scenarioFolder = './test/helpers/scenarios/';
const selectedScenarios: string[] = ['rebalance-stable-rate.json']; const selectedScenarios: string[] = ['swap-rate-mode.json'];
fs.readdirSync(scenarioFolder).forEach((file) => { fs.readdirSync(scenarioFolder).forEach((file) => {
if (selectedScenarios.length > 0 && !selectedScenarios.includes(file)) return; if (selectedScenarios.length > 0 && !selectedScenarios.includes(file)) return;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -187,7 +187,7 @@ interface LendingPoolInterface extends Interface {
}>; }>;
swapBorrowRateMode: TypedFunctionDescription<{ swapBorrowRateMode: TypedFunctionDescription<{
encode([_reserve]: [string]): string; encode([_reserve, _rateMode]: [string, BigNumberish]): string;
}>; }>;
}; };
@ -276,13 +276,11 @@ interface LendingPoolInterface extends Interface {
}>; }>;
RebalanceStableBorrowRate: TypedEventDescription<{ RebalanceStableBorrowRate: TypedEventDescription<{
encodeTopics([ encodeTopics([_reserve, _user, _timestamp]: [
_reserve, string | null,
_user, string | null,
_newStableRate, null
_borrowBalanceIncrease, ]): string[];
_timestamp
]: [string | null, string | null, null, null, null]): string[];
}>; }>;
RedeemUnderlying: TypedEventDescription<{ RedeemUnderlying: TypedEventDescription<{
@ -313,11 +311,9 @@ interface LendingPoolInterface extends Interface {
}>; }>;
Swap: TypedEventDescription<{ Swap: TypedEventDescription<{
encodeTopics([_reserve, _user, _newRateMode, _newRate, _timestamp]: [ encodeTopics([_reserve, _user, _timestamp]: [
string | null, string | null,
string | null, string | null,
null,
null,
null null
]): string[]; ]): string[];
}>; }>;
@ -598,6 +594,7 @@ export class LendingPool extends Contract {
swapBorrowRateMode( swapBorrowRateMode(
_reserve: string, _reserve: string,
_rateMode: BigNumberish,
overrides?: TransactionOverrides overrides?: TransactionOverrides
): Promise<ContractTransaction>; ): Promise<ContractTransaction>;
}; };
@ -862,6 +859,7 @@ export class LendingPool extends Contract {
swapBorrowRateMode( swapBorrowRateMode(
_reserve: string, _reserve: string,
_rateMode: BigNumberish,
overrides?: TransactionOverrides overrides?: TransactionOverrides
): Promise<ContractTransaction>; ): Promise<ContractTransaction>;
@ -917,8 +915,6 @@ export class LendingPool extends Contract {
RebalanceStableBorrowRate( RebalanceStableBorrowRate(
_reserve: string | null, _reserve: string | null,
_user: string | null, _user: string | null,
_newStableRate: null,
_borrowBalanceIncrease: null,
_timestamp: null _timestamp: null
): EventFilter; ): EventFilter;
@ -950,8 +946,6 @@ export class LendingPool extends Contract {
Swap( Swap(
_reserve: string | null, _reserve: string | null,
_user: string | null, _user: string | null,
_newRateMode: null,
_newRate: null,
_timestamp: null _timestamp: null
): EventFilter; ): EventFilter;
}; };
@ -1097,6 +1091,9 @@ export class LendingPool extends Contract {
_useAsCollateral: boolean _useAsCollateral: boolean
): Promise<BigNumber>; ): Promise<BigNumber>;
swapBorrowRateMode(_reserve: string): Promise<BigNumber>; swapBorrowRateMode(
_reserve: string,
_rateMode: BigNumberish
): Promise<BigNumber>;
}; };
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -134,4 +134,4 @@ const _abi = [
]; ];
const _bytecode = const _bytecode =
"0x608060405234801561001057600080fd5b5060405161099e38038061099e8339818101604052602081101561003357600080fd5b5051600080546001600160a01b039092166001600160a01b0319909216919091179055610939806100656000396000f3fe6080604052600436106100385760003560e01c80639e3c930914610083578063b59b28ef1461014f578063f7888aec146102d35761007e565b3661007e5761004633610320565b61007c576040805162461bcd60e51b8152602060048201526002602482015261191960f11b604482015290519081900360640190fd5b005b600080fd5b34801561008f57600080fd5b506100b6600480360360208110156100a657600080fd5b50356001600160a01b031661035c565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156100fa5781810151838201526020016100e2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015610139578181015183820152602001610121565b5050505090500194505050505060405180910390f35b34801561015b57600080fd5b506102836004803603604081101561017257600080fd5b81019060208101813564010000000081111561018d57600080fd5b82018360208201111561019f57600080fd5b803590602001918460208302840111640100000000831117156101c157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561021157600080fd5b82018360208201111561022357600080fd5b8035906020019184602083028401116401000000008311171561024557600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506106a9945050505050565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156102bf5781810151838201526020016102a7565b505050509050019250505060405180910390f35b3480156102df57600080fd5b5061030e600480360360408110156102f657600080fd5b506001600160a01b0381358116916020013516610841565b60408051918252519081900360200190f35b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061035457508115155b949350505050565b60608060008060009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156103ae57600080fd5b505afa1580156103c2573d6000803e3d6000fd5b505050506040513d60208110156103d857600080fd5b505160408051630240bc6b60e21b815290519192506060916001600160a01b03841691630902f1ac916004808301926000929190829003018186803b15801561042057600080fd5b505afa158015610434573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561045d57600080fd5b810190808051604051939291908464010000000082111561047d57600080fd5b90830190602082018581111561049257600080fd5b82518660208202830111640100000000821117156104af57600080fd5b82525081516020918201928201910280838360005b838110156104dc5781810151838201526020016104c4565b5050505090500160405250505090506060815167ffffffffffffffff8111801561050557600080fd5b5060405190808252806020026020018201604052801561052f578160200160208202803683370190505b50905060005b825181101561069d576000846001600160a01b0316633e15014185848151811061055b57fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b031681526020019150506101406040518083038186803b1580156105aa57600080fd5b505afa1580156105be573d6000803e3d6000fd5b505050506040513d6101408110156105d557600080fd5b5061010001519050806106025760008383815181106105f057fe5b60200260200101818152505050610695565b61060a6108eb565b6001600160a01b031684838151811061061f57fe5b60200260200101516001600160a01b03161461066f576106528885848151811061064557fe5b6020026020010151610841565b83838151811061065e57fe5b602002602001018181525050610693565b876001600160a01b03163183838151811061068657fe5b6020026020010181815250505b505b600101610535565b50909350915050915091565b606080825184510267ffffffffffffffff811180156106c757600080fd5b506040519080825280602002602001820160405280156106f1578160200160208202803683370190505b50905060005b84518110156108375760005b845181101561082e57845182026107186108eb565b6001600160a01b031686838151811061072d57fe5b60200260200101516001600160a01b031614156107815786838151811061075057fe5b60200260200101516001600160a01b031631848383018151811061077057fe5b602002602001018181525050610825565b6107a686838151811061079057fe5b60200260200101516001600160a01b0316610320565b6107e7576040805162461bcd60e51b815260206004820152600d60248201526c24a72b20a624a22faa27a5a2a760991b604482015290519081900360640190fd5b61080a8784815181106107f657fe5b602002602001015187848151811061064557fe5b848383018151811061081857fe5b6020026020010181815250505b50600101610703565b506001016106f7565b5090505b92915050565b6000610855826001600160a01b0316610320565b156108e357816001600160a01b03166370a08231846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156108b057600080fd5b505afa1580156108c4573d6000803e3d6000fd5b505050506040513d60208110156108da57600080fd5b5051905061083b565b50600061083b565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9056fea2646970667358221220a16f16f49f57c03b454cd00ccd40b73de3ab4b7744715128843b1ab47bc4873664736f6c63430006080033"; "0x608060405234801561001057600080fd5b5060405161099e38038061099e8339818101604052602081101561003357600080fd5b5051600080546001600160a01b039092166001600160a01b0319909216919091179055610939806100656000396000f3fe6080604052600436106100385760003560e01c80639e3c930914610083578063b59b28ef1461014f578063f7888aec146102d35761007e565b3661007e5761004633610320565b61007c576040805162461bcd60e51b8152602060048201526002602482015261191960f11b604482015290519081900360640190fd5b005b600080fd5b34801561008f57600080fd5b506100b6600480360360208110156100a657600080fd5b50356001600160a01b031661035c565b604051808060200180602001838103835285818151815260200191508051906020019060200280838360005b838110156100fa5781810151838201526020016100e2565b50505050905001838103825284818151815260200191508051906020019060200280838360005b83811015610139578181015183820152602001610121565b5050505090500194505050505060405180910390f35b34801561015b57600080fd5b506102836004803603604081101561017257600080fd5b81019060208101813564010000000081111561018d57600080fd5b82018360208201111561019f57600080fd5b803590602001918460208302840111640100000000831117156101c157600080fd5b919080806020026020016040519081016040528093929190818152602001838360200280828437600092019190915250929594936020810193503591505064010000000081111561021157600080fd5b82018360208201111561022357600080fd5b8035906020019184602083028401116401000000008311171561024557600080fd5b9190808060200260200160405190810160405280939291908181526020018383602002808284376000920191909152509295506106a9945050505050565b60408051602080825283518183015283519192839290830191858101910280838360005b838110156102bf5781810151838201526020016102a7565b505050509050019250505060405180910390f35b3480156102df57600080fd5b5061030e600480360360408110156102f657600080fd5b506001600160a01b0381358116916020013516610841565b60408051918252519081900360200190f35b6000813f7fc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a47081811480159061035457508115155b949350505050565b60608060008060009054906101000a90046001600160a01b03166001600160a01b0316630261bf8b6040518163ffffffff1660e01b815260040160206040518083038186803b1580156103ae57600080fd5b505afa1580156103c2573d6000803e3d6000fd5b505050506040513d60208110156103d857600080fd5b505160408051630240bc6b60e21b815290519192506060916001600160a01b03841691630902f1ac916004808301926000929190829003018186803b15801561042057600080fd5b505afa158015610434573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052602081101561045d57600080fd5b810190808051604051939291908464010000000082111561047d57600080fd5b90830190602082018581111561049257600080fd5b82518660208202830111640100000000821117156104af57600080fd5b82525081516020918201928201910280838360005b838110156104dc5781810151838201526020016104c4565b5050505090500160405250505090506060815167ffffffffffffffff8111801561050557600080fd5b5060405190808252806020026020018201604052801561052f578160200160208202803683370190505b50905060005b825181101561069d576000846001600160a01b0316633e15014185848151811061055b57fe5b60200260200101516040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b031681526020019150506101406040518083038186803b1580156105aa57600080fd5b505afa1580156105be573d6000803e3d6000fd5b505050506040513d6101408110156105d557600080fd5b5061010001519050806106025760008383815181106105f057fe5b60200260200101818152505050610695565b61060a6108eb565b6001600160a01b031684838151811061061f57fe5b60200260200101516001600160a01b03161461066f576106528885848151811061064557fe5b6020026020010151610841565b83838151811061065e57fe5b602002602001018181525050610693565b876001600160a01b03163183838151811061068657fe5b6020026020010181815250505b505b600101610535565b50909350915050915091565b606080825184510267ffffffffffffffff811180156106c757600080fd5b506040519080825280602002602001820160405280156106f1578160200160208202803683370190505b50905060005b84518110156108375760005b845181101561082e57845182026107186108eb565b6001600160a01b031686838151811061072d57fe5b60200260200101516001600160a01b031614156107815786838151811061075057fe5b60200260200101516001600160a01b031631848383018151811061077057fe5b602002602001018181525050610825565b6107a686838151811061079057fe5b60200260200101516001600160a01b0316610320565b6107e7576040805162461bcd60e51b815260206004820152600d60248201526c24a72b20a624a22faa27a5a2a760991b604482015290519081900360640190fd5b61080a8784815181106107f657fe5b602002602001015187848151811061064557fe5b848383018151811061081857fe5b6020026020010181815250505b50600101610703565b506001016106f7565b5090505b92915050565b6000610855826001600160a01b0316610320565b156108e357816001600160a01b03166370a08231846040518263ffffffff1660e01b815260040180826001600160a01b03166001600160a01b0316815260200191505060206040518083038186803b1580156108b057600080fd5b505afa1580156108c4573d6000803e3d6000fd5b505050506040513d60208110156108da57600080fd5b5051905061083b565b50600061083b565b73eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee9056fea2646970667358221220690f7ecb9ab912f052e8d44a9a4f27007b3b6f0119cdc6270033c06dbc83a4e664736f6c63430006080033";