#!/usr/bin/env bash

############################################
# Skills are what matters. Not cheap talk. #
############################################

# @license GNU Affero General Public License v3.0 only
# @author pcaversaccio

# Enable strict error handling:
# -E: Inherit `ERR` traps in functions and subshells.
# -e: Exit immediately if a command exits with a non-zero status.
# -u: Treat unset variables as an error and exit.
# -o pipefail: Return the exit status of the first failed command in a pipeline.
set -Eeuo pipefail

# Enable debug mode if the environment variable `DEBUG` is set to `true`.
if [[ "${DEBUG:-false}" == "true" ]]; then
	# Print each command before executing it.
	set -x
fi

# Load environment variables from `.env` file.
if [[ -f .env ]]; then
	set -a
	. ./.env
	set +a
else
	echo ".env file not found"
	exit 1
fi

# Utility function to check if a variable is set without exposing its value.
check_var() {
	if [[ -z "${!1}" ]]; then
		echo "Error: $1 is not set in the .env file"
		exit 1
	else
		echo "$1 is set"
	fi
}

vars=(
	RPC_URL
	VICTIM_PK
	PAYMASTER_PK
)

# Check if the required environment variables are set.
for var in "${vars[@]}"; do
	check_var "$var"
done

echo "Private keys and RPC URL loaded successfully!"

# Set the contract creation code for the `recoverooor` as a global constant.
# To generate the same bytecode, install the necessary dependencies via
# `pip install vyper==0.4.2 snekmate==0.1.2rc1` and compile the contract using
# `vyper recoverooor.vy`.
readonly INIT_CODE_RECOVEROOOR="0x610f27515034610036576020610f985f395f518060a01c61003657604052604051610f2752610f2761003a61000039610f47610000f35b5f80fd5f3560e01c60026007820660011b610f1901601e395f51565b633db132b18118610bda5734610f1557610030610bde565b6020610f275f395f51ff005b6358525fea8118610bda57602436103417610f15576004356004016080813511610f155780355f8160808111610f1557801561009a57905b8060051b6020850101358060a01c610f15578160051b6101600152600101818118610074575b5050806101405250506100ab610bde565b5f6101405160808111610f1557801561022d57905b8060051b6101600151611160526111605163a9059cbb6111c0526020610f276111e039611160516370a0823161118052306111a0526020611180602461119c845afa61010e573d5f5f3e3d5ffd5b60203d10610f15576111809050516112005260206111c060446111dc5f855af161013a573d5f5f3e3d5ffd5b3d61015157803b15610f155760016112205261017b565b3d602081183d6020100218806111c0016111e011610f15576111c0518060011c610f155761122052505b611220905051610222576020806112c0526036611240527f7265636f7665726f6f6f723a206572632d3230207472616e73666572206f7065611260527f726174696f6e20646964206e6f7420737563636565640000000000000000000061128052611240816112c001605682825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06112a052806004016112bcfd5b6001018181186100c0575b5050005b63e05cd5268118610bda57604436103417610f15576004356004016080813511610f155780355f8160808111610f1557801561028f57905b8060051b6020850101358060a01c610f15578160051b6101600152600101818118610269575b5050806101405250506024356004016080813511610f155780355f8160808111610f155780156102f857905b8060051b60208501013560208501016080813511610f1557803560208160051b0161102084026111800181848237505050506001018181186102bb575b505080611160525050610309610bde565b611160516101405118156103bc576020806208220052603562082180527f7265636f7665726f6f6f723a2060746f6b656e736020616e642060746f6b656e620821a0527f5f69647360206c656e677468206d69736d617463680000000000000000000000620821c05262082180816208220001605582825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a0620821e05280600401620821fcfd5b5f62082180525f6101405160808111610f155780156104a657905b8060051b6101600151620821a052611020620821805161116051811015610f15570261118001805160208160051b018083620821c05e5050505f620821c05160808111610f1557801561048c57905b8060051b620821e00151620831e052620821a0516323b872dd62083200523062083220526020610f276208324039620831e0516208326052803b15610f15575f6208320060646208321c5f855af1610480573d5f5f3e3d5ffd5b50600101818118610426575b5050600162082180510162082180526001018181186103d7575b5050005b630cab397581186109d557606436103417610f15576004356004016080813511610f155780355f8160808111610f1557801561050857905b8060051b6020850101358060a01c610f15578160051b61016001526001018181186104e2575b5050806101405250506024356004016080813511610f155780355f8160808111610f1557801561057157905b8060051b60208501013560208501016080813511610f1557803560208160051b016110208402611180018184823750505050600101818118610534575b5050806111605250506044356004016080813511610f155780355f8160808111610f155780156105db57905b8060051b60208501013560208501016080813511610f1557803560208160051b016110208402620821a001818482375050505060010181811861059d575b505080620821805250506105ed610bde565b611160516101405118156106a0576020806210322052602f621031a0527f7265636f7665726f6f6f723a2060746f6b656e736020616e6420606964736020621031c0527f6c656e677468206d69736d617463680000000000000000000000000000000000621031e052621031a0816210322001604f82825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06210320052806004016210321cfd5b62082180516101405118156107545760208062103220526033621031a0527f7265636f7665726f6f6f723a2060746f6b656e736020616e642060616d6f756e621031c0527f747360206c656e677468206d69736d6174636800000000000000000000000000621031e052621031a0816210322001605382825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06210320052806004016210321cfd5b5f621031a0525f6101405160808111610f155780156109d157905b8060051b6101600151621031c052611020621031a0516208218051811015610f155702620821a00151611020621031a05161116051811015610f1557026111800151181561085c5760208062103260526030621031e0527f7265636f7665726f6f6f723a20606964736020616e642060616d6f756e74736062103200527f206c656e677468206d69736d61746368000000000000000000000000000000006210322052621031e0816210326001605082825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06210324052806004016210325cfd5b621031c051632eb2c2d6621032005260a03062103220526020610f276210324039806210326052611020621031a05161116051811015610f155702611180018162103220015f82518083528060051b5f8260808111610f155780156108dc57905b8060051b6020880101518160051b6020880101526001018181186108bd575b505082016020019150509050905081019050806210328052611020621031a0516208218051811015610f155702620821a0018162103220015f82518083528060051b5f8260808111610f1557801561094f57905b8060051b6020880101518160051b602088010152600101818118610930575b50508201602001915050905090508101905080621032a0528062103220015f81528051806020830101601f825f03163682375050601f19601f82516020010116905081015050803b15610f15575f621032006121046210321c5f855af16109b8573d5f5f3e3d5ffd5b506001621031a05101621031a05260010181811861076f575b5050005b63117803e38118610bda5734610f15576020610f2760403960206040f35b63352312598118610bda576023361115610f155760043560040160ff813511610f155780355f8160ff8111610f15578015610a9b57905b8060051b602085010135602085010161048082026205c3400181358060a01c610f1557815260208201358060011c610f15576020820152604082013560408201526060820135820180356104008111610f155750602081350160608301818382375050505050600101818118610a2a575b5050806205c320525050610aad610bde565b602080620b7da0526205c320515f8160ff8111610f15578015610b1757905b61048081026205c340016104808202606001815181526020820151602082015260408201516040820152606082016020815101606083018183825e5050505050600101818118610acc575b50508060405250610b2a620a3ec0610c85565b620a3ec081620b7da0015f82518083528060051b5f8260ff8111610f15578015610bc257905b828160051b602088010152610140810260208801018360208801016040825182528060208301526020830181830160208251018083835e508051806020830101601f825f03163682375050601f19601f8251602001011690509050810190509050905083019250600101818118610b50575b505082016020019150509050905081019050620b7da0f35b5f5ffd5b6020610f275f395f51331815610c835760208060c05260246040527f7265636f7665726f6f6f723a2063616c6c6572206973206e6f7420746865206f6060527f776e65720000000000000000000000000000000000000000000000000000000060805260408160c001604482825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a060a0528060040160bcfd5b565b60403662047be0375f6205bae0525f6205bb00525f60405160ff8111610f15578015610e2f57905b610480810260600180516205bc205260208101516205bc405260408101516205bc605260608101602081510180826205bc805e5050506205bc60516205c0a0526205c0a05162047be0510162047be0526205bc4051610d7a5760016205bae0526205bc20516205c0a0515a6205bc8060ff6205c0e0825160208401868887f19050905090509050610d40573d5f5f3e3d5ffd5b3d60ff81183d60ff1002186205c0c0526205c0c0602081510180826205c1e05e505060206205c1e05101806205c1e06205bb005e50610de6565b6205bc20516205c0a0515a6205bc8060ff6205c0e0825160208401868887f190509050905090506205c1e0523d60ff81183d60ff1002186205c0c0526205c0c0602081510180826205c2005e50506205c1e0516205bae05260206205c2005101806205c2006205bb005e505b62047c005160fe8111610f1557610140810262047c20016205bae051815260206205bb00510160208201816205bb00825e5050506001810162047c005250600101818118610cad575b505062047be051341815610ebc576020806205bc805260196205bc20527f6d756c746963616c6c3a2076616c7565206d69736d61746368000000000000006205bc40526205bc20816205bc8001603982825e8051806020830101601f825f03163682375050601f19601f8251602001011690509050810190506308c379a06205bc6052806004016205bc7cfd5b62047c00515f8160ff8111610f15578015610f0c57905b610140810262047c20016101408202602086010181518152602082016020815101602083018183825e5050505050600101818118610ed3575b50508082525050565b5f80fd0bda00180bda023109f3003c04aa855820af71d809a9eabbed8515c90d13066261f47a89b9fc0264b203ee21d64753cc41190f27810e1820a1657679706572830004020037"

# Set the placeholder address for the `recoverooor` contract to be deployed.
RECOVEROOOR_ADDRESS="0x0000000000000000000000000000000000000000"

# Set the zero address as a global constant.
readonly ZERO_ADDRESS="0x0000000000000000000000000000000000000000"

################################################################################
# Specify here the rescue calldata to be passed to the `recoverooor` contract. #
################################################################################
# Example payload that calls `recover_erc20` with 2 ERC-20 contract addresses.
PAYLOAD="0x58525fea0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000200000000000000000000000008210f9170f89ab7658f0b5e3ff39b0e03c594d40000000000000000000000001c7d4b196cb0c7b01d743fbc6116a902379c7238"

# Utility function to derive a wallet address.
derive_wallet() {
	local pk="$1"
	cast wallet address --private-key "$pk"
}

# Derive the paymaster wallet.
PAYMASTER_WALLET=$(derive_wallet "$PAYMASTER_PK")

# Utility function to deploy the `recoverooor` contract with the `PAYMASTER_WALLET`
# account as `OWNER`.
deploy_recoverooor() {
	local deployer_pk="$1"
	local owner_encoded=$(cast abi-encode "fn(address)" "$PAYMASTER_WALLET" | sed "s/^0x//")
	RECOVEROOOR_ADDRESS=$(cast compute-address --rpc-url "$RPC_URL" \
		--nonce "$(cast nonce --rpc-url "$RPC_URL" "$PAYMASTER_WALLET")" \
		"$PAYMASTER_WALLET" | awk '{ print $3 }')
	readonly RECOVEROOOR_ADDRESS
	cast send --private-key "$deployer_pk" \
		--rpc-url "$RPC_URL" \
		--create "${INIT_CODE_RECOVEROOOR}${owner_encoded}"
	sleep 20
}

# Utility function to sign an EIP-7702 authorisation for a provided delegator contract.
sign_eip7702_authorisation() {
	local auth_pk="$1"
	local delegator="$2"
	local authorisation=$(cast wallet sign-auth --private-key "$auth_pk" \
		--rpc-url "$RPC_URL" \
		--nonce "$(cast nonce --rpc-url "$RPC_URL" "$(derive_wallet "$auth_pk")")" \
		"$delegator")
	echo "$authorisation"
}

# Utility function to recover all assets via the predefined calldata `PAYLOAD`.
recover() {
	local auth_pk="$1"
	local paymaster_pk="$2"
	local authorisation=$(sign_eip7702_authorisation "$auth_pk" "$RECOVEROOOR_ADDRESS")
	cast send --private-key "$paymaster_pk" --rpc-url "$RPC_URL" --auth "$authorisation" "$(derive_wallet "$auth_pk")" "$PAYLOAD"
	sleep 20
}

# Utility function to reset an EIP-7702 authorisation.
reset() {
	local auth_pk="$1"
	local paymaster_pk="$2"
	local authorisation=$(sign_eip7702_authorisation "$auth_pk" "$ZERO_ADDRESS")
	cast send --private-key "$paymaster_pk" --rpc-url "$RPC_URL" --auth "$authorisation" "$(derive_wallet "$auth_pk")"
}

echo -e "\n===================================="
echo "= Step 1: \`recoverooor\` Deployment ="
echo "===================================="
# Deploy the `recoverooor` contract with the `PAYMASTER_WALLET` account as `OWNER`.
deploy_recoverooor "$PAYMASTER_PK"

echo -e "\n=============================="
echo "= Step 2: Rescue Transaction ="
echo "=============================="
# Recover all assets via the predefined calldata `PAYLOAD`.
recover "$VICTIM_PK" "$PAYMASTER_PK"

echo -e "\n========================================"
echo "= Step 3: Reset EIP-7702 Authorisation ="
echo "========================================"
# Reset the EIP-7702 authorisation in case the `OWNER` can no longer be trusted in the future.
reset "$VICTIM_PK" "$PAYMASTER_PK"
