Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

✨under-the-radar hack prevention #28

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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/cache
/node_modules
/out
/out
package-lock.json
/broadcast
.env
76 changes: 76 additions & 0 deletions src/CypherEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,62 @@ contract CypherEscrow is ReentrancyGuard {
address dst;
address asset;
uint256 amount;
uint256 blockNumber;
}

/*//////////////////////////////////////////////////////////////
EXPERIMENT
//////////////////////////////////////////////////////////////*/
/*
Limits: 10,000 tokens per tx
1. hacker withdraws 2000 tokens in 5 transactions
2. hacker withdraws 5000 tokens in 2 transactions
*/
/// @notice Number of blocks to allow repeat transactions
uint256 acceptableBlockLimts = 5;

/// @notice Transaction history of hacker, specified by their address
mapping(address => UserTransactions) public transactionHistory;

/// @notice User transaction struct with information on total transactions
struct UserTransactions {
address sender;
uint256 totalAmount;
uint256 prevBlockNumber;
uint256 prevAmount;
}

/// @notice We want a sliding scale for the amount of tokens that can be withdrawn. Newer users can withdraw less than older users. Maybe they make it custom? 3 tiers?
uint256 tier1TokenLimit = 1000;
uint256 tier2TokenLimit = 5000;
uint256 tier3TokenLimit = 10000;

uint256 tier1TimeLimit = 10 minutes;
uint256 tier2TimeLimit = 20 minutes;
uint256 tier3TimeLimit = 30 minutes;

/// @dev Tiers mapping: 1 => {tier1TokenLimit, tier1TimeLimit}, etc
mapping(uint256 => Tier) public tiers;

/// @dev Tier struct
struct Tier {
uint256 tokenLimit;
uint256 timeLimit;
}

/*//////////////////////////////////////////////////////////////
EXPERIMENT END
//////////////////////////////////////////////////////////////*/

/// @dev utility function to store the specific user
/// @param _sender The address of the user
/// @param _amount The amount of tokens being withdrawn
function storeUser(address _sender, uint256 _amount) internal {
UserTransactions storage user = transactionHistory[_sender];
user.sender = _sender;
user.totalAmount += _amount;
user.prevBlockNumber = block.number;
user.prevAmount = _amount;
}

/*//////////////////////////////////////////////////////////////
Expand All @@ -63,6 +119,7 @@ contract CypherEscrow is ReentrancyGuard {
event OracleAdded(address indexed user, address oracle);
event TimeLimitSet(uint256 timeLimit);
event AddressAddedToWhitelist(address indexed user, address whitelist);
event TiersAndLimitsSet(uint256[], uint256[]);

/*//////////////////////////////////////////////////////////////
ERRORS
Expand Down Expand Up @@ -111,6 +168,9 @@ contract CypherEscrow is ReentrancyGuard {
/// @param origin The address of the user who initiated the withdraw
/// @param dst The address of the user who will receive the ETH
function escrowETH(address origin, address dst) external payable nonReentrant {
// prevent multi-hack under the radar
// check if it is in the same block && the sum of all recent tx's is greater than the specified amount

// check if the stop has been overwritten by protocol owner on the frontend
// if (msg.sender != sourceContract) revert NotSourceContract();
if (origin == address(0) || dst == address(0)) revert NotValidAddress();
Expand All @@ -122,6 +182,7 @@ contract CypherEscrow is ReentrancyGuard {

// if they are whitelisted or amount is less than threshold, just transfer the tokens
if (amount < tokenThreshold || isWhitelisted[dst]) {
// need to check if they have gone through before
(bool success, ) = address(dst).call{value: amount}("");
if (!success) revert TransferFailed();
} else if (getTransactionInfo[key].origin == address(0)) {
Expand Down Expand Up @@ -259,6 +320,21 @@ contract CypherEscrow is ReentrancyGuard {
emit OracleAdded(msg.sender, _oracle);
}

/// @dev Set limits for the different tiers
/// @param _tiers The array of tiers
/// @param _limits The array of limits associated with the tiers
function setTiersAndLimits(uint256[] memory _tiers, uint256[] memory _limits) external onlyOracle {
require(_tiers.length == _limits.length, "Tiers and limits must be the same length");

for (uint256 i = 0; i < _tiers.length; i++) {
/// @notice Start at 1 because 0 is the default
Tier memory tier;
tiers[i + 1] = new Tier(_tiers[i], _limits[i]);
}

emit TiersAndLimitsSet(_tiers, _limits);
}

/*//////////////////////////////////////////////////////////////
GETTERS
//////////////////////////////////////////////////////////////*/
Expand Down
162 changes: 81 additions & 81 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,95 +3,95 @@


"@solidity-parser/parser@^0.14.3":
version "0.14.3"
resolved "https://registry.yarnpkg.com/@solidity-parser/parser/-/parser-0.14.3.tgz#0d627427b35a40d8521aaa933cc3df7d07bfa36f"
integrity sha512-29g2SZ29HtsqA58pLCtopI1P/cPy5/UAzlcAXO6T/CNJimG6yA8kx4NaseMyJULiC+TEs02Y9/yeHzClqoA0hw==
"integrity" "sha512-29g2SZ29HtsqA58pLCtopI1P/cPy5/UAzlcAXO6T/CNJimG6yA8kx4NaseMyJULiC+TEs02Y9/yeHzClqoA0hw=="
"resolved" "https://registry.npmjs.org/@solidity-parser/parser/-/parser-0.14.3.tgz"
"version" "0.14.3"
dependencies:
antlr4ts "^0.5.0-alpha.4"

ansi-regex@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==

antlr4ts@^0.5.0-alpha.4:
version "0.5.0-alpha.4"
resolved "https://registry.yarnpkg.com/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz#71702865a87478ed0b40c0709f422cf14d51652a"
integrity sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ==

emoji-regex@^10.1.0:
version "10.2.1"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.2.1.tgz#a41c330d957191efd3d9dfe6e1e8e1e9ab048b3f"
integrity sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA==

emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==

escape-string-regexp@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==

is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==

lru-cache@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
"antlr4ts" "^0.5.0-alpha.4"

"ansi-regex@^5.0.1":
"integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
"resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
"version" "5.0.1"

"antlr4ts@^0.5.0-alpha.4":
"integrity" "sha512-WPQDt1B74OfPv/IMS2ekXAKkTZIHl88uMetg6q3OTqgFxZ/dxDXI0EWLyZid/1Pe6hTftyg5N7gel5wNAGxXyQ=="
"resolved" "https://registry.npmjs.org/antlr4ts/-/antlr4ts-0.5.0-alpha.4.tgz"
"version" "0.5.0-alpha.4"

"emoji-regex@^10.1.0":
"integrity" "sha512-97g6QgOk8zlDRdgq1WxwgTMgEWGVAQvB5Fdpgc1MkNy56la5SKP9GsMXKDOdqwn90/41a8yPwIGk1Y6WVbeMQA=="
"resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.2.1.tgz"
"version" "10.2.1"

"emoji-regex@^8.0.0":
"integrity" "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
"resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
"version" "8.0.0"

"escape-string-regexp@^4.0.0":
"integrity" "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
"resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
"version" "4.0.0"

"is-fullwidth-code-point@^3.0.0":
"integrity" "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
"resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
"version" "3.0.0"

"lru-cache@^6.0.0":
"integrity" "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="
"resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
"version" "6.0.0"
dependencies:
yallist "^4.0.0"
"yallist" "^4.0.0"

prettier-plugin-solidity@^1.0.0-beta.24:
version "1.0.0-beta.24"
resolved "https://registry.yarnpkg.com/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.24.tgz#67573ca87098c14f7ccff3639ddd8a4cab2a87eb"
integrity sha512-6JlV5BBTWzmDSq4kZ9PTXc3eLOX7DF5HpbqmmaF+kloyUwOZbJ12hIYsUaZh2fVgZdV2t0vWcvY6qhILhlzgqg==
"prettier-plugin-solidity@^1.0.0-beta.24":
"integrity" "sha512-6JlV5BBTWzmDSq4kZ9PTXc3eLOX7DF5HpbqmmaF+kloyUwOZbJ12hIYsUaZh2fVgZdV2t0vWcvY6qhILhlzgqg=="
"resolved" "https://registry.npmjs.org/prettier-plugin-solidity/-/prettier-plugin-solidity-1.0.0-beta.24.tgz"
"version" "1.0.0-beta.24"
dependencies:
"@solidity-parser/parser" "^0.14.3"
emoji-regex "^10.1.0"
escape-string-regexp "^4.0.0"
semver "^7.3.7"
solidity-comments-extractor "^0.0.7"
string-width "^4.2.3"

prettier@^2.7.1:
version "2.7.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==

semver@^7.3.7:
version "7.3.8"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.8.tgz#07a78feafb3f7b32347d725e33de7e2a2df67798"
integrity sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==
"emoji-regex" "^10.1.0"
"escape-string-regexp" "^4.0.0"
"semver" "^7.3.7"
"solidity-comments-extractor" "^0.0.7"
"string-width" "^4.2.3"

"prettier@^2.3.0", "prettier@^2.7.1":
"integrity" "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g=="
"resolved" "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz"
"version" "2.7.1"

"semver@^7.3.7":
"integrity" "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A=="
"resolved" "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz"
"version" "7.3.8"
dependencies:
lru-cache "^6.0.0"
"lru-cache" "^6.0.0"

solidity-comments-extractor@^0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz#99d8f1361438f84019795d928b931f4e5c39ca19"
integrity sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw==
"solidity-comments-extractor@^0.0.7":
"integrity" "sha512-wciNMLg/Irp8OKGrh3S2tfvZiZ0NEyILfcRCXCD4mp7SgK/i9gzLfhY2hY7VMCQJ3kH9UB9BzNdibIVMchzyYw=="
"resolved" "https://registry.npmjs.org/solidity-comments-extractor/-/solidity-comments-extractor-0.0.7.tgz"
"version" "0.0.7"

string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
"string-width@^4.2.3":
"integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="
"resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
"version" "4.2.3"
dependencies:
emoji-regex "^8.0.0"
is-fullwidth-code-point "^3.0.0"
strip-ansi "^6.0.1"

strip-ansi@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==
"emoji-regex" "^8.0.0"
"is-fullwidth-code-point" "^3.0.0"
"strip-ansi" "^6.0.1"

"strip-ansi@^6.0.1":
"integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="
"resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
"version" "6.0.1"
dependencies:
ansi-regex "^5.0.1"
"ansi-regex" "^5.0.1"

yallist@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
"yallist@^4.0.0":
"integrity" "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
"resolved" "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
"version" "4.0.0"