Workshop big update based on feedback from day 1
parent
596e8dec08
commit
bca95b66e0
24
README.md
24
README.md
|
@ -5,9 +5,15 @@ Workshop for "web3" bridge hacking at Hacktivity 2022
|
||||||
|
|
||||||
#### Introduction
|
#### Introduction
|
||||||
- Web3 vs web2 hacking, concepts / workshop topology
|
- Web3 vs web2 hacking, concepts / workshop topology
|
||||||
|
- Who interacted with dApps/SCs before?
|
||||||
|
- Who codes Solidity?
|
||||||
|
- Who codes Rust?
|
||||||
|
- Who used a bridge before?
|
||||||
|
- Who is the cryptographer?
|
||||||
|
|
||||||
#### Environment setup, system requirements
|
#### Environment setup, system requirements
|
||||||
- Any browser for Ethereum, Remix
|
- Any browser for Ethereum, Remix
|
||||||
|
- Python3
|
||||||
- Substrate, Rust nightly
|
- Substrate, Rust nightly
|
||||||
|
|
||||||
#### Scenario 1: Token on two chains, mint using receipt
|
#### Scenario 1: Token on two chains, mint using receipt
|
||||||
|
@ -19,8 +25,9 @@ Workshop for "web3" bridge hacking at Hacktivity 2022
|
||||||
#### Scenario 2: Signature forgery (any chain)
|
#### Scenario 2: Signature forgery (any chain)
|
||||||
- Deploy SC on Ethereum chain
|
- Deploy SC on Ethereum chain
|
||||||
- Compile Substrate with EVM
|
- Compile Substrate with EVM
|
||||||
- Deploy SC
|
- Deploy SC on Substrate chain (so it is different from core)
|
||||||
- Test ECDSA signature forgery exploit from one to other
|
- Test ECDSA signature forgery exploit from one to other
|
||||||
|
- Test same issue with WASM/ink!
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
|
@ -32,6 +39,7 @@ https://ethereum.org/en/developers/docs/standards/tokens/erc-20/
|
||||||
https://git.hsbp.org/six/eth_keygen
|
https://git.hsbp.org/six/eth_keygen
|
||||||
|
|
||||||
#### Scenario 2
|
#### Scenario 2
|
||||||
|
https://cryptoctf.org/2022/09/11/writeup-of-flag-submission-forgery-by-si/
|
||||||
https://github.com/paritytech/substrate-contracts-node
|
https://github.com/paritytech/substrate-contracts-node
|
||||||
https://docs.substrate.io/quick-start/
|
https://docs.substrate.io/quick-start/
|
||||||
https://github.com/substrate-developer-hub/substrate-front-end-template
|
https://github.com/substrate-developer-hub/substrate-front-end-template
|
||||||
|
@ -39,4 +47,18 @@ https://github.com/paritytech/ink
|
||||||
https://github.com/paritytech/substrate/blob/master/primitives/core/src/ecdsa.rs
|
https://github.com/paritytech/substrate/blob/master/primitives/core/src/ecdsa.rs
|
||||||
https://use.ink/getting-started/setup
|
https://use.ink/getting-started/setup
|
||||||
https://medium.com/block-journal/introducing-substrate-smart-contracts-with-ink-d486289e2b59
|
https://medium.com/block-journal/introducing-substrate-smart-contracts-with-ink-d486289e2b59
|
||||||
|
https://github.com/paritytech/contracts-ui
|
||||||
|
https://contracts-ui.substrate.io/?rpc=wss://rpc.shibuya.astar.network
|
||||||
https://substrate.io/developers/playground/
|
https://substrate.io/developers/playground/
|
||||||
|
https://security.stackexchange.com/questions/200682/is-it-possible-to-fake-ecdsa-signatures
|
||||||
|
|
||||||
|
|
||||||
|
## Solidity Hacking Homework
|
||||||
|
|
||||||
|
1. Crypto Wojak - Who is the admin?
|
||||||
|
2. Sminem - Set the password
|
||||||
|
3. Crypto Wojak - Make your tries count 2 or more
|
||||||
|
4. Crypto Wojak - Make your tries count 2 and get the answer
|
||||||
|
5. HODLer - Deposit ether twice with the same address
|
||||||
|
6. Crypto Wojak - Execute selfdestruct()
|
||||||
|
+1 Sminem - Create a signature to prove you are Satoshi (see js folder)
|
||||||
|
|
Binary file not shown.
|
@ -0,0 +1 @@
|
||||||
|
<mxfile host="app.diagrams.net" modified="2022-10-06T20:00:39.755Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.5112.102 Safari/537.36" etag="bC8fl9ZiBndQcjIvywAN" version="20.4.0" type="device"><diagram id="fPFYDeu9YJaB2W5Fxku6" name="Page-1">7VfbcpswEP0aHp3hEhz7Mb6kyTSepnEmaZ4yMsigjkBUCF/69V2BBKiYNO4lk077YrNHq5W0e/YILG+a7N5xlMULFmJquXa4s7yZ5brj0xH8SmBfAb47roCIk7CCnAZYkq9YgbZCCxLi3HAUjFFBMhMMWJriQBgY4pxtTbc1o+aqGYpwB1gGiHbRBxKKuEJHvt3gl5hEsV7ZsdVIgrSzAvIYhWzbgry55U05Y6J6SnZTTGXudF6qeRc9o/XGOE7FSyZc5Veb2SD/8PgxDO5D7C0G2fvBqdqb2OsD4xDOr0zGRcwiliI6b9AJZ0UaYhnVBqvxuWYsA9AB8DMWYq+KiQrBAIpFQtUo3hHxSU4/8ZX12BqZ7VTk0thrIxV8X01yfW0/tgebeaWlJ+YCcXEumQBAQFGek0DDF4TqPVV5kIfvTa+CclbwAD+TU01TxCMsnvHzahJA82CWYNg2zOOYIkE25j6QonFU+6mpcDK0bzlkjKQib0W+kQA4qIZ0NXP3pn3R4++Nvef84aHagbZaR2mgkolHsNJRa24QLVQeLu/ubix3SCGhkxU3KDv8UsgemqxZKgZ5SbpzcHDcbFcWVo/DUyT/H5bLg6y/RivQLoOpiJIolbwBEmAOwAZzQUAdztVAQsKwagoMK6NVGU/STtUBgvsTy5+p7amWcNyacTIg3h2SMhWsEZA2F/ubuUsoFd0+8Ya2YxRz4FbmcZTrcGTgHQ6rI7D1OodOMGnze4jS4UnNEV3tuYgxx0UCbiuUg2xBgmNEUu0I69a+bYL1IfPbqSyIvUxAQOB/CmXlCG6ejucCkvT0QET8dIsDTDLRZR2lcI9J+mxjIvAyQ6WwbOEmNXnYy5WOPvWW3xmajX+mzG1zqzkjhcXtG+3U7ueDUc9ji+f/hXfP2Ru/e9xXunt+qfCO+1/ef0Le/R/Iu+MOR39C3h3ffAN4LXHvsqQj7stilYP6Ctyn7o0ab0GIYXR+v/jXlN/33pryd1/vOpWdwNcg6OGLSlUn2c4428D3In9JOS/hWHA2mQhEqaSwzVLJI1YSpaRRftKpXHMDOa9SPe/7F/bxgfKdHSqfc3z5wGw+SKs+br7qvfk3</diagram></mxfile>
|
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
|
@ -0,0 +1,72 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
// original: https://gist.github.com/indutny/8d0f5376ee643962a9f0
|
||||||
|
|
||||||
|
// npm install --save bn.js
|
||||||
|
// npm install elliptic
|
||||||
|
// npm install bcoin
|
||||||
|
// npm install secp256k1
|
||||||
|
|
||||||
|
const BN = require('bn.js');
|
||||||
|
const elliptic = require('elliptic');
|
||||||
|
const bcoin = require('bcoin');
|
||||||
|
|
||||||
|
const ecdsa = new elliptic.ec('secp256k1');
|
||||||
|
|
||||||
|
let message = new BN(
|
||||||
|
'7a05c6145f10101e9d6325494245adf1297d80f8f38d4d576d57cdba220bcb19', 'hex');
|
||||||
|
|
||||||
|
var key = new Buffer('0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3', 'hex');
|
||||||
|
var sig = '304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09';
|
||||||
|
// const signature = new bcoin.ecdsa.signature(new Buffer(sig, 'hex'));
|
||||||
|
// console.log(signature);
|
||||||
|
|
||||||
|
var signature = {
|
||||||
|
r: new BN('4e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd41', 'hex'),
|
||||||
|
s: new BN('181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d09', 'hex')
|
||||||
|
};
|
||||||
|
|
||||||
|
const point = ecdsa.curve.pointFromX(signature.r);
|
||||||
|
point.precompute(256);
|
||||||
|
|
||||||
|
function trick(message, signature, i) {
|
||||||
|
const n = new BN(
|
||||||
|
'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141', 16);
|
||||||
|
const p = new BN(
|
||||||
|
'fffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f', 16);
|
||||||
|
|
||||||
|
const nRed = BN.red(n);
|
||||||
|
const pRed = BN.red(p);
|
||||||
|
|
||||||
|
// NOTE: Could be using GLV values for speed
|
||||||
|
let lambda = new BN(i);
|
||||||
|
|
||||||
|
const point2 = point.mul(lambda);
|
||||||
|
let beta = point2.x.redMul(point.x.redInvm()).fromRed();
|
||||||
|
|
||||||
|
lambda = lambda.toRed(nRed);
|
||||||
|
beta = beta.toRed(pRed);
|
||||||
|
// NOTE end
|
||||||
|
|
||||||
|
const originalR = signature.r;
|
||||||
|
const r = originalR.toRed(pRed).redMul(beta).fromRed();
|
||||||
|
|
||||||
|
const nBeta = r.toRed(nRed).redMul(originalR.toRed(nRed).redInvm());
|
||||||
|
const common = lambda.redInvm().redMul(nBeta);
|
||||||
|
|
||||||
|
const s = signature.s.toRed(nRed).redMul(common).fromRed();
|
||||||
|
|
||||||
|
return {
|
||||||
|
signature: { r: r, s: s },
|
||||||
|
message: message.toRed(nRed).redMul(nBeta).fromRed()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 2; i < 100; i++) {
|
||||||
|
const item = trick(message, signature, i);
|
||||||
|
console.log(JSON.stringify([
|
||||||
|
new Buffer(item.message.toArray()).toString('hex'),
|
||||||
|
new Buffer(new bcoin.ecdsa.signature(item.signature).toDER()).toString('hex')
|
||||||
|
]) + ',');
|
||||||
|
// ecdsa.verify(item.message, item.signature, key)
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
# Author: six
|
# Author: six
|
||||||
# Made for: CCTF during BsidesBUD 2022
|
# Made for: CCTF during BsidesBUD 2022 -> Updated for Hacktivity 2022 web3 hacking Workshop
|
||||||
|
|
||||||
# require(owner() == ecrecover(keccak256(abi.encodePacked(this, tokenId)), v, r, s), "Should be signed correctly");
|
# require(owner() == ecrecover(keccak256(abi.encodePacked(this, tokenId)), v, r, s), "Should be signed correctly");
|
||||||
# https://privatekeys.pw/keys/ethereum/1
|
# https://privatekeys.pw/keys/ethereum/1
|
||||||
|
@ -10,20 +9,14 @@ from web3.auto import w3
|
||||||
from eth_account.messages import encode_defunct
|
from eth_account.messages import encode_defunct
|
||||||
from flask import Flask, request
|
from flask import Flask, request
|
||||||
|
|
||||||
from base64 import b64encode
|
|
||||||
|
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
|
|
||||||
b64 = '''<html><body><pre>Lets play a game... what is the private key if:
|
html = '''<html><body><pre>Use /get_a_receipt
|
||||||
|
|
||||||
SignedMessage(messageHash=HexBytes('0xd65fc3b188dd92cfcb2a193a50840c1b782030fb06c5eee3125dadc48b9042ee'), r=93061353422229139783272046072373682100846510432479107335894930000050943813187, s=18897300799783892124841480819482900155126442998358954848148962214377508383077, v=28, signature=HexBytes('0xcdbedc050cdf4e1a236535365e1563312905fc47aa8238a8ab06decfbb31e64329c77e43945949494800d0c432d037867ea10aad935abf98c63ae2befaf929651c'))
|
|
||||||
|
|
||||||
If you send the correct private key as argument to /verify?p=<ARG> in HEX format (without 0x), then you will get the CCTF flag which lets you in to the next yacht event + swag at BsidesBUD.
|
|
||||||
</pre></body></html>'''
|
</pre></body></html>'''
|
||||||
|
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
def hello():
|
def hello():
|
||||||
return b64
|
return html
|
||||||
|
|
||||||
@app.route('/verify', methods=['GET'])
|
@app.route('/verify', methods=['GET'])
|
||||||
def search():
|
def search():
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
# Eth ECDSA key generator, signer and arg recovery for web3 hacking
|
# Eth ECDSA key generator, signer and arg recovery for web3 hacking // Modified for Hacktivity workshop
|
||||||
# Author: six
|
# Author: six
|
||||||
# References: https://web3py.readthedocs.io/en/stable/web3.eth.account.html?highlight=sign#sign-a-message
|
# References: https://web3py.readthedocs.io/en/stable/web3.eth.account.html?highlight=sign#sign-a-message
|
||||||
# Ethereum Private Keys Directory -> https://privatekeys.pw/keys/ethereum/1
|
# Ethereum Private Keys Directory -> https://privatekeys.pw/keys/ethereum/1
|
||||||
|
@ -84,7 +84,7 @@ parser.add_argument("-s", "--sol", help="Print solidity code for ecrecover", act
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
if args.dgen:
|
if args.dgen:
|
||||||
forv = generate("Anything","0000000000000000000000000000000000000000000000000000000000000001") # hex|0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf
|
forv = generate("Anything","0000000000000000000000000000000000000000000000000000000000000006") # hex|0xE57bFE9F44b819898F47BF37E5AF72a0783e1141
|
||||||
gen_vrs(forv)
|
gen_vrs(forv)
|
||||||
sys.exit()
|
sys.exit()
|
||||||
if args.rgen:
|
if args.rgen:
|
||||||
|
@ -107,6 +107,6 @@ if args.sol:
|
||||||
print_sol_recovery()
|
print_sol_recovery()
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
forv = generate("Anything","0000000000000000000000000000000000000000000000000000000000000001") # hex|0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf
|
forv = generate("Anything","0000000000000000000000000000000000000000000000000000000000000006") # hex|0xE57bFE9F44b819898F47BF37E5AF72a0783e1141
|
||||||
gen_vrs(forv)
|
gen_vrs(forv)
|
||||||
print("\nNo arguments were provided. You can use --help.")
|
print("\nNo arguments were provided. You can use --help.")
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
# Author: SI
|
# Author: SI
|
||||||
|
# Reference 1: https://cryptoctf.org/2022/09/11/writeup-of-flag-submission-forgery-by-si/
|
||||||
|
# Reference 2: https://polygonscan.com/address/0x36a1424da63a50627863d8f65c0669da7347814a
|
||||||
|
# Reference 3: https://gist.github.com/chjj/4fe8f5b2b489e89e6ed4
|
||||||
|
|
||||||
from eth_account.account import to_standard_signature_bytes
|
from eth_account.account import to_standard_signature_bytes
|
||||||
from eth_keys import keys
|
from eth_keys import keys
|
||||||
|
@ -33,8 +36,10 @@ def forge(public_key, a = 0, b = 1):
|
||||||
|
|
||||||
return '0x' + to_bytes(z).rjust(32, b'\0').hex(), '0x' + eth_signature_bytes.hex()
|
return '0x' + to_bytes(z).rjust(32, b'\0').hex(), '0x' + eth_signature_bytes.hex()
|
||||||
|
|
||||||
hsh = '0xe50051a0af89748fe098cef3b163b6dc586a664e726791bb2a582ad364f42683'
|
#hsh = '0xe50051a0af89748fe098cef3b163b6dc586a664e726791bb2a582ad364f42683'
|
||||||
sig = '0x2bdbc1826efc039719a28a9f4dbab9f4a2692d83de478300261a0e49019b63ee67c202ecc4ebdf82693da47824ac4fcf21f793400d85696034c4de9537c6ce491b'
|
#sig = '0x2bdbc1826efc039719a28a9f4dbab9f4a2692d83de478300261a0e49019b63ee67c202ecc4ebdf82693da47824ac4fcf21f793400d85696034c4de9537c6ce491b'
|
||||||
|
hsh = '0xbb272d3dc886fccf69f92cd7cb622501c02627c045fb38053f78af2dca68e188'
|
||||||
|
sig = '0x30410a2d097af2b27ba3d789ce151c6aed0590f71b4c7b67d4ae91f56659f2297c3a2f8155d9fb9d30682e599b31012b51cb0928578e97f2f3f0c306597d2eec1c'
|
||||||
|
|
||||||
pub = recover_public_key(hsh, sig)
|
pub = recover_public_key(hsh, sig)
|
||||||
addr = pub.to_checksum_address()
|
addr = pub.to_checksum_address()
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// Challenges inspired by CCTF
|
// Challenges inspired by CCTF
|
||||||
pragma solidity ^0.8.17;
|
pragma solidity ^0.8.17;
|
||||||
import "@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol";
|
|
||||||
|
|
||||||
contract SafuDotERC20 is AccessControlUpgradeable {
|
contract SafuDotERC20 {
|
||||||
|
|
||||||
uint256 public max_supply;
|
uint256 public max_supply;
|
||||||
mapping (address => uint256) internal amountToAddress;
|
mapping (address => uint256) internal amountToAddress;
|
||||||
|
@ -18,7 +17,7 @@ contract SafuDotERC20 is AccessControlUpgradeable {
|
||||||
mapping(address => uint256) public calls;
|
mapping(address => uint256) public calls;
|
||||||
mapping(address => uint256) public tries;
|
mapping(address => uint256) public tries;
|
||||||
|
|
||||||
//bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
|
address public bridge;
|
||||||
mapping(address => bool) public minter;
|
mapping(address => bool) public minter;
|
||||||
|
|
||||||
// Homework 1
|
// Homework 1
|
||||||
|
@ -29,8 +28,10 @@ contract SafuDotERC20 is AccessControlUpgradeable {
|
||||||
|
|
||||||
max_supply = 1000000;
|
max_supply = 1000000;
|
||||||
amountToAddress[msg.sender] = max_supply - 100000;
|
amountToAddress[msg.sender] = max_supply - 100000;
|
||||||
amountOfBridge = max_supply - amountToAddress[msg.sender];
|
bridge = 0xE57bFE9F44b819898F47BF37E5AF72a0783e1141;
|
||||||
|
amountToAddress[bridge] = max_supply - amountToAddress[msg.sender];
|
||||||
mint_amount = 10000;
|
mint_amount = 10000;
|
||||||
|
|
||||||
minter[msg.sender] = true;
|
minter[msg.sender] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,33 +39,38 @@ contract SafuDotERC20 is AccessControlUpgradeable {
|
||||||
amountToAddress[msg.sender] = amountToAddress[msg.sender] + mint_amount;
|
amountToAddress[msg.sender] = amountToAddress[msg.sender] + mint_amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
function mintWithReceipt(
|
function mintWithReceipt(bytes32 _message, bytes memory _signature) public {
|
||||||
address recipient,
|
require(recoverSigner(_message, _signature) == bridge, "Not signed with the correct key.");
|
||||||
uint256 amount,
|
//require(minter[msg.sender] == true, "Not minter");
|
||||||
uint256 uuid,
|
|
||||||
uint8 v,
|
|
||||||
bytes32 r,
|
|
||||||
bytes32 s
|
|
||||||
) public {
|
|
||||||
|
|
||||||
bytes32 payloadHash = keccak256(abi.encode(recipient, amount, uuid));
|
|
||||||
bytes32 hash = keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", payloadHash));
|
|
||||||
//require(!_receipts[hash], "Receipt already used"); // Dumb without it.
|
//require(!_receipts[hash], "Receipt already used"); // Dumb without it.
|
||||||
_checkSignature(hash, v, r, s);
|
amountToAddress[bridge] = amountToAddress[bridge] - mint_amount;
|
||||||
|
require(amountToAddress[bridge] >= 0);
|
||||||
mint();
|
mint();
|
||||||
//_receipts[hash] = true;
|
//_receipts[hash] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _checkSignature(
|
function recoverSigner(bytes32 _ethSignedMessageHash, bytes memory _signature) public pure returns (address) {
|
||||||
bytes32 hash,
|
(bytes32 r, bytes32 s, uint8 v) = splitSignature(_signature);
|
||||||
uint8 v,
|
return ecrecover(_ethSignedMessageHash, v, r, s);
|
||||||
bytes32 r,
|
|
||||||
bytes32 s
|
|
||||||
) internal view {
|
|
||||||
address signer = ecrecover(hash, v, r, s);
|
|
||||||
require(minter[signer] == true, "Not minter");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function splitSignature(bytes memory sig) public pure returns (bytes32 r, bytes32 s, uint8 v){
|
||||||
|
require(sig.length == 65, "Invalid signature length");
|
||||||
|
assembly {
|
||||||
|
r := mload(add(sig, 32))
|
||||||
|
s := mload(add(sig, 64))
|
||||||
|
v := byte(0, mload(add(sig, 96)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function myBalance() external view returns (uint256) {
|
||||||
|
return amountToAddress[msg.sender];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function othersBalance(address _other) external view returns (uint256) {
|
||||||
|
return amountToAddress[_other];
|
||||||
|
}
|
||||||
|
|
||||||
function transfer(uint256 _value, address _toAddress) external {
|
function transfer(uint256 _value, address _toAddress) external {
|
||||||
require(amountToAddress[msg.sender] - _value >= 0, 'Oooops');
|
require(amountToAddress[msg.sender] - _value >= 0, 'Oooops');
|
||||||
|
@ -77,7 +83,6 @@ contract SafuDotERC20 is AccessControlUpgradeable {
|
||||||
return sent;
|
return sent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Easypeasy
|
// Easypeasy
|
||||||
function adminChange(address _newAdmin) external returns (bool) {
|
function adminChange(address _newAdmin) external returns (bool) {
|
||||||
admin = _newAdmin;
|
admin = _newAdmin;
|
||||||
|
@ -90,7 +95,7 @@ contract SafuDotERC20 is AccessControlUpgradeable {
|
||||||
correct_password = _password;
|
correct_password = _password;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Homework 5 - Final
|
// Homework 6 - Final
|
||||||
function su1c1d3(address payable _addr, string memory _password) external {
|
function su1c1d3(address payable _addr, string memory _password) external {
|
||||||
require(msg.sender == admin, 'You are not the central admin!');
|
require(msg.sender == admin, 'You are not the central admin!');
|
||||||
require(keccak256(abi.encodePacked(correct_password)) == keccak256(abi.encodePacked(_password)), 'Very sekur.');
|
require(keccak256(abi.encodePacked(correct_password)) == keccak256(abi.encodePacked(_password)), 'Very sekur.');
|
||||||
|
@ -113,7 +118,12 @@ contract SafuDotERC20 is AccessControlUpgradeable {
|
||||||
return answer;
|
return answer;
|
||||||
}
|
}
|
||||||
|
|
||||||
function deposit() public payable {}
|
// Homework 5
|
||||||
fallback() external payable {}
|
mapping(address => bool) address_contributed;
|
||||||
receive() external payable {}
|
function deposit() public payable {
|
||||||
|
require(address_contributed[msg.sender] != true, "Not working.");
|
||||||
|
address_contributed[msg.sender] = true;
|
||||||
|
}
|
||||||
|
fallback() external {}
|
||||||
|
//receive() external {}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue