Compare commits

..

20 Commits

Author SHA1 Message Date
Gui Heise
fe6cd4dcdb Added type changes to tests 2021-09-09 14:18:27 -04:00
Luke Van Seters
014b80312c Set secrets via Tiltfile 2021-09-09 09:01:36 -06:00
Luke Van Seters
947d2a0064 Add inspect many blocks 2021-09-09 08:00:53 -06:00
Luke Van Seters
0ae93db617 Fix alembic migrations for kube 2021-09-09 07:52:33 -06:00
Luke Van Seters
144ed63381 Get local postgres working on kube 2021-09-09 07:49:29 -06:00
Luke Van Seters
bc25cf1eba Get container running on kubernetes / tilt 2021-09-03 09:55:21 -04:00
Robert Miller
a77e2d7671 Merge pull request #61 from flashbots/0x-contracts
Add 0x contracts
2021-09-02 23:31:48 +00:00
Luke Van Seters
fbd84fddd0 Move ABIs to the right spot 2021-09-02 18:08:02 -04:00
Luke Van Seters
3e90b94e50 Add UniswapV3 callbacks 2021-09-02 18:06:17 -04:00
Luke Van Seters
2e97193efd Add 0x feature ABIs 2021-09-02 17:46:43 -04:00
Luke Van Seters
f9ecea9d86 Add zerox to classifier specs list. Load all specs from trace classifier 2021-09-02 10:53:38 -04:00
Luke Van Seters
70d0502ac4 Add them to the final list 2021-09-02 10:41:02 -04:00
Luke Van Seters
f5f4e75f7d Add ABIs for 0x 2021-09-02 10:40:22 -04:00
Robert Miller
0f3070a08a Merge pull request #60 from flashbots/miner-db
Write miner payments to the DB
2021-08-31 17:13:32 +00:00
Luke Van Seters
9846b9f16c Add to and from addresses 2021-08-30 20:09:01 -04:00
Luke Van Seters
1aa5c5b465 Write miner payments to the DB in script run 2021-08-30 18:02:36 -04:00
Luke Van Seters
9769498c9d Add crud for miner payments 2021-08-30 13:49:40 -04:00
Luke Van Seters
f5222c1902 Swap => MinerPayment 2021-08-30 13:48:35 -04:00
Luke Van Seters
c22cab0b68 Add miner_payments model 2021-08-30 13:47:37 -04:00
Luke Van Seters
acb68dfcff Add miner_payments table 2021-08-30 13:45:34 -04:00
77 changed files with 1459 additions and 55 deletions

3
.gitignore vendored
View File

@@ -16,3 +16,6 @@ htmlcov
# don't commit cache
cache
# k8s
.helm

View File

@@ -6,14 +6,16 @@ RUN pip install -U pip \
ENV PATH="${PATH}:/root/.poetry/bin"
COPY . /app
COPY ./pyproject.toml /app/pyproject.toml
COPY ./poetry.lock /app/poetry.lock
WORKDIR /app/
# poetry uses virtual env by default, turn this off inside container
RUN poetry config virtualenvs.create false && \
poetry install
COPY . /app
# easter eggs 😝
RUN echo "PS1='🕵️:\[\033[1;36m\]\h \[\033[1;34m\]\W\[\033[0;35m\]\[\033[1;36m\]$ \[\033[0m\]'" >> ~/.bashrc
CMD /bin/bash
CMD ["/bin/bash"]

22
Tiltfile Normal file
View File

@@ -0,0 +1,22 @@
load('ext://helm_remote', 'helm_remote')
helm_remote("postgresql",
repo_name='bitnami',
repo_url='https://charts.bitnami.com/bitnami',
set=["postgresqlPassword=password", "postgresqlDatabase=mev_inspect"],
)
load('ext://secret', 'secret_from_dict')
k8s_yaml(secret_from_dict("mev-inspect-db-credentials", inputs = {
"username" : "postgres",
"password": "password",
}))
docker_build('mev-inspect', '.',
live_update=[
sync('.', '/app'),
run('cd /app && poetry install',
trigger='./pyproject.toml'),
],
)
k8s_yaml("k8s/app.yaml")

View File

@@ -1,5 +1,3 @@
import os
from logging.config import fileConfig
from sqlalchemy import engine_from_config
@@ -7,10 +5,12 @@ from sqlalchemy import pool
from alembic import context
from mev_inspect.db import get_sqlalchemy_database_uri
# this is the Alembic Config object, which provides
# access to the values within the .ini file in use.
config = context.config
config.set_main_option("sqlalchemy.url", os.environ["SQLALCHEMY_DATABASE_URI"])
config.set_main_option("sqlalchemy.url", get_sqlalchemy_database_uri())
# Interpret the config file for Python logging.
# This line sets up loggers basically.

View File

@@ -0,0 +1,36 @@
"""Create miner_payments table
Revision ID: 083978d6e455
Revises: 92f28a2b4f52
Create Date: 2021-08-30 17:42:25.548130
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "083978d6e455"
down_revision = "92f28a2b4f52"
branch_labels = None
depends_on = None
def upgrade():
op.create_table(
"miner_payments",
sa.Column("created_at", sa.TIMESTAMP, server_default=sa.func.now()),
sa.Column("block_number", sa.Numeric, nullable=False),
sa.Column("transaction_hash", sa.String(66), primary_key=True),
sa.Column("transaction_index", sa.Numeric, nullable=False),
sa.Column("miner_address", sa.String(256), nullable=False),
sa.Column("coinbase_transfer", sa.Numeric, nullable=False),
sa.Column("base_fee_per_gas", sa.Numeric, nullable=False),
sa.Column("gas_price", sa.Numeric, nullable=False),
sa.Column("gas_price_with_coinbase_transfer", sa.Numeric, nullable=False),
sa.Column("gas_used", sa.Numeric, nullable=False),
)
def downgrade():
op.drop_table("miner_payments")

View File

@@ -0,0 +1,32 @@
"""Add to_address and from_address to miner_payments table
Revision ID: d70c08b4db6f
Revises: 083978d6e455
Create Date: 2021-08-30 22:10:04.186251
"""
import sqlalchemy as sa
from alembic import op
# revision identifiers, used by Alembic.
revision = "d70c08b4db6f"
down_revision = "083978d6e455"
branch_labels = None
depends_on = None
def upgrade():
op.add_column(
"miner_payments",
sa.Column("transaction_to_address", sa.String(256), nullable=True),
)
op.add_column(
"miner_payments",
sa.Column("transaction_from_address", sa.String(256), nullable=True),
)
def downgrade():
op.drop_column("miner_payments", "transaction_to_address")
op.drop_column("miner_payments", "transaction_from_address")

326
get_helm.sh Executable file
View File

@@ -0,0 +1,326 @@
#!/usr/bin/env bash
# Copyright The Helm Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# The install script is based off of the MIT-licensed script from glide,
# the package manager for Go: https://github.com/Masterminds/glide.sh/blob/master/get
: ${BINARY_NAME:="helm"}
: ${USE_SUDO:="true"}
: ${DEBUG:="false"}
: ${VERIFY_CHECKSUM:="true"}
: ${VERIFY_SIGNATURES:="false"}
: ${HELM_INSTALL_DIR:="/usr/local/bin"}
: ${GPG_PUBRING:="pubring.kbx"}
HAS_CURL="$(type "curl" &> /dev/null && echo true || echo false)"
HAS_WGET="$(type "wget" &> /dev/null && echo true || echo false)"
HAS_OPENSSL="$(type "openssl" &> /dev/null && echo true || echo false)"
HAS_GPG="$(type "gpg" &> /dev/null && echo true || echo false)"
# initArch discovers the architecture for this system.
initArch() {
ARCH=$(uname -m)
case $ARCH in
armv5*) ARCH="armv5";;
armv6*) ARCH="armv6";;
armv7*) ARCH="arm";;
aarch64) ARCH="arm64";;
x86) ARCH="386";;
x86_64) ARCH="amd64";;
i686) ARCH="386";;
i386) ARCH="386";;
esac
}
# initOS discovers the operating system for this system.
initOS() {
OS=$(echo `uname`|tr '[:upper:]' '[:lower:]')
case "$OS" in
# Minimalist GNU for Windows
mingw*) OS='windows';;
esac
}
# runs the given command as root (detects if we are root already)
runAsRoot() {
if [ $EUID -ne 0 -a "$USE_SUDO" = "true" ]; then
sudo "${@}"
else
"${@}"
fi
}
# verifySupported checks that the os/arch combination is supported for
# binary builds, as well whether or not necessary tools are present.
verifySupported() {
local supported="darwin-amd64\ndarwin-arm64\nlinux-386\nlinux-amd64\nlinux-arm\nlinux-arm64\nlinux-ppc64le\nlinux-s390x\nwindows-amd64"
if ! echo "${supported}" | grep -q "${OS}-${ARCH}"; then
echo "No prebuilt binary for ${OS}-${ARCH}."
echo "To build from source, go to https://github.com/helm/helm"
exit 1
fi
if [ "${HAS_CURL}" != "true" ] && [ "${HAS_WGET}" != "true" ]; then
echo "Either curl or wget is required"
exit 1
fi
if [ "${VERIFY_CHECKSUM}" == "true" ] && [ "${HAS_OPENSSL}" != "true" ]; then
echo "In order to verify checksum, openssl must first be installed."
echo "Please install openssl or set VERIFY_CHECKSUM=false in your environment."
exit 1
fi
if [ "${VERIFY_SIGNATURES}" == "true" ]; then
if [ "${HAS_GPG}" != "true" ]; then
echo "In order to verify signatures, gpg must first be installed."
echo "Please install gpg or set VERIFY_SIGNATURES=false in your environment."
exit 1
fi
if [ "${OS}" != "linux" ]; then
echo "Signature verification is currently only supported on Linux."
echo "Please set VERIFY_SIGNATURES=false or verify the signatures manually."
exit 1
fi
fi
}
# checkDesiredVersion checks if the desired version is available.
checkDesiredVersion() {
if [ "x$DESIRED_VERSION" == "x" ]; then
# Get tag from release URL
local latest_release_url="https://github.com/helm/helm/releases"
if [ "${HAS_CURL}" == "true" ]; then
TAG=$(curl -Ls $latest_release_url | grep 'href="/helm/helm/releases/tag/v3.[0-9]*.[0-9]*\"' | grep -v no-underline | head -n 1 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}')
elif [ "${HAS_WGET}" == "true" ]; then
TAG=$(wget $latest_release_url -O - 2>&1 | grep 'href="/helm/helm/releases/tag/v3.[0-9]*.[0-9]*\"' | grep -v no-underline | head -n 1 | cut -d '"' -f 2 | awk '{n=split($NF,a,"/");print a[n]}' | awk 'a !~ $0{print}; {a=$0}')
fi
else
TAG=$DESIRED_VERSION
fi
}
# checkHelmInstalledVersion checks which version of helm is installed and
# if it needs to be changed.
checkHelmInstalledVersion() {
if [[ -f "${HELM_INSTALL_DIR}/${BINARY_NAME}" ]]; then
local version=$("${HELM_INSTALL_DIR}/${BINARY_NAME}" version --template="{{ .Version }}")
if [[ "$version" == "$TAG" ]]; then
echo "Helm ${version} is already ${DESIRED_VERSION:-latest}"
return 0
else
echo "Helm ${TAG} is available. Changing from version ${version}."
return 1
fi
else
return 1
fi
}
# downloadFile downloads the latest binary package and also the checksum
# for that binary.
downloadFile() {
HELM_DIST="helm-$TAG-$OS-$ARCH.tar.gz"
DOWNLOAD_URL="https://get.helm.sh/$HELM_DIST"
CHECKSUM_URL="$DOWNLOAD_URL.sha256"
HELM_TMP_ROOT="$(mktemp -dt helm-installer-XXXXXX)"
HELM_TMP_FILE="$HELM_TMP_ROOT/$HELM_DIST"
HELM_SUM_FILE="$HELM_TMP_ROOT/$HELM_DIST.sha256"
echo "Downloading $DOWNLOAD_URL"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "$CHECKSUM_URL" -o "$HELM_SUM_FILE"
curl -SsL "$DOWNLOAD_URL" -o "$HELM_TMP_FILE"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "$HELM_SUM_FILE" "$CHECKSUM_URL"
wget -q -O "$HELM_TMP_FILE" "$DOWNLOAD_URL"
fi
}
# verifyFile verifies the SHA256 checksum of the binary package
# and the GPG signatures for both the package and checksum file
# (depending on settings in environment).
verifyFile() {
if [ "${VERIFY_CHECKSUM}" == "true" ]; then
verifyChecksum
fi
if [ "${VERIFY_SIGNATURES}" == "true" ]; then
verifySignatures
fi
}
# installFile installs the Helm binary.
installFile() {
HELM_TMP="$HELM_TMP_ROOT/$BINARY_NAME"
mkdir -p "$HELM_TMP"
tar xf "$HELM_TMP_FILE" -C "$HELM_TMP"
HELM_TMP_BIN="$HELM_TMP/$OS-$ARCH/helm"
echo "Preparing to install $BINARY_NAME into ${HELM_INSTALL_DIR}"
runAsRoot cp "$HELM_TMP_BIN" "$HELM_INSTALL_DIR/$BINARY_NAME"
echo "$BINARY_NAME installed into $HELM_INSTALL_DIR/$BINARY_NAME"
}
# verifyChecksum verifies the SHA256 checksum of the binary package.
verifyChecksum() {
printf "Verifying checksum... "
local sum=$(openssl sha1 -sha256 ${HELM_TMP_FILE} | awk '{print $2}')
local expected_sum=$(cat ${HELM_SUM_FILE})
if [ "$sum" != "$expected_sum" ]; then
echo "SHA sum of ${HELM_TMP_FILE} does not match. Aborting."
exit 1
fi
echo "Done."
}
# verifySignatures obtains the latest KEYS file from GitHub main branch
# as well as the signature .asc files from the specific GitHub release,
# then verifies that the release artifacts were signed by a maintainer's key.
verifySignatures() {
printf "Verifying signatures... "
local keys_filename="KEYS"
local github_keys_url="https://raw.githubusercontent.com/helm/helm/main/${keys_filename}"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "${github_keys_url}" -o "${HELM_TMP_ROOT}/${keys_filename}"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "${HELM_TMP_ROOT}/${keys_filename}" "${github_keys_url}"
fi
local gpg_keyring="${HELM_TMP_ROOT}/keyring.gpg"
local gpg_homedir="${HELM_TMP_ROOT}/gnupg"
mkdir -p -m 0700 "${gpg_homedir}"
local gpg_stderr_device="/dev/null"
if [ "${DEBUG}" == "true" ]; then
gpg_stderr_device="/dev/stderr"
fi
gpg --batch --quiet --homedir="${gpg_homedir}" --import "${HELM_TMP_ROOT}/${keys_filename}" 2> "${gpg_stderr_device}"
gpg --batch --no-default-keyring --keyring "${gpg_homedir}/${GPG_PUBRING}" --export > "${gpg_keyring}"
local github_release_url="https://github.com/helm/helm/releases/download/${TAG}"
if [ "${HAS_CURL}" == "true" ]; then
curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
curl -SsL "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" -o "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
elif [ "${HAS_WGET}" == "true" ]; then
wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc"
wget -q -O "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" "${github_release_url}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc"
fi
local error_text="If you think this might be a potential security issue,"
error_text="${error_text}\nplease see here: https://github.com/helm/community/blob/master/SECURITY.md"
local num_goodlines_sha=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
if [[ ${num_goodlines_sha} -lt 2 ]]; then
echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz.sha256!"
echo -e "${error_text}"
exit 1
fi
local num_goodlines_tar=$(gpg --verify --keyring="${gpg_keyring}" --status-fd=1 "${HELM_TMP_ROOT}/helm-${TAG}-${OS}-${ARCH}.tar.gz.asc" 2> "${gpg_stderr_device}" | grep -c -E '^\[GNUPG:\] (GOODSIG|VALIDSIG)')
if [[ ${num_goodlines_tar} -lt 2 ]]; then
echo "Unable to verify the signature of helm-${TAG}-${OS}-${ARCH}.tar.gz!"
echo -e "${error_text}"
exit 1
fi
echo "Done."
}
# fail_trap is executed if an error occurs.
fail_trap() {
result=$?
if [ "$result" != "0" ]; then
if [[ -n "$INPUT_ARGUMENTS" ]]; then
echo "Failed to install $BINARY_NAME with the arguments provided: $INPUT_ARGUMENTS"
help
else
echo "Failed to install $BINARY_NAME"
fi
echo -e "\tFor support, go to https://github.com/helm/helm."
fi
cleanup
exit $result
}
# testVersion tests the installed client to make sure it is working.
testVersion() {
set +e
HELM="$(command -v $BINARY_NAME)"
if [ "$?" = "1" ]; then
echo "$BINARY_NAME not found. Is $HELM_INSTALL_DIR on your "'$PATH?'
exit 1
fi
set -e
}
# help provides possible cli installation arguments
help () {
echo "Accepted cli arguments are:"
echo -e "\t[--help|-h ] ->> prints this help"
echo -e "\t[--version|-v <desired_version>] . When not defined it fetches the latest release from GitHub"
echo -e "\te.g. --version v3.0.0 or -v canary"
echo -e "\t[--no-sudo] ->> install without sudo"
}
# cleanup temporary files to avoid https://github.com/helm/helm/issues/2977
cleanup() {
if [[ -d "${HELM_TMP_ROOT:-}" ]]; then
rm -rf "$HELM_TMP_ROOT"
fi
}
# Execution
#Stop execution on any error
trap "fail_trap" EXIT
set -e
# Set debug if desired
if [ "${DEBUG}" == "true" ]; then
set -x
fi
# Parsing input arguments (if any)
export INPUT_ARGUMENTS="${@}"
set -u
while [[ $# -gt 0 ]]; do
case $1 in
'--version'|-v)
shift
if [[ $# -ne 0 ]]; then
export DESIRED_VERSION="${1}"
else
echo -e "Please provide the desired version. e.g. --version v3.0.0 or -v canary"
exit 0
fi
;;
'--no-sudo')
USE_SUDO="false"
;;
'--help'|-h)
help
exit 0
;;
*) exit 1
;;
esac
shift
done
set +u
initArch
initOS
verifySupported
checkDesiredVersion
if ! checkHelmInstalledVersion; then
downloadFile
verifyFile
installFile
fi
testVersion
cleanup

39
k8s/app.yaml Normal file
View File

@@ -0,0 +1,39 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: mev-inspect-deployment
labels:
app: mev-inspect
spec:
replicas: 1
selector:
matchLabels:
app: mev-inspect
template:
metadata:
labels:
app: mev-inspect
spec:
containers:
- name: mev-inspect
image: mev-inspect:latest
command: [ "/bin/bash", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
env:
- name: POSTGRES_USER
valueFrom:
secretKeyRef:
name: mev-inspect-db-credentials
key: username
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: mev-inspect-db-credentials
key: password
livenessProbe:
exec:
command:
- ls
- /
initialDelaySeconds: 20
periodSeconds: 5

View File

@@ -0,0 +1 @@
[{"inputs":[{"components":[{"internalType":"contract IERC20TokenV06","name":"makerToken","type":"address"},{"internalType":"contract IERC20TokenV06","name":"takerToken","type":"address"},{"internalType":"uint128","name":"makerAmount","type":"uint128"},{"internalType":"uint128","name":"takerAmount","type":"uint128"},{"internalType":"uint128","name":"takerTokenFeeAmount","type":"uint128"},{"internalType":"address","name":"maker","type":"address"},{"internalType":"address","name":"taker","type":"address"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"feeRecipient","type":"address"},{"internalType":"bytes32","name":"pool","type":"bytes32"},{"internalType":"uint64","name":"expiry","type":"uint64"},{"internalType":"uint256","name":"salt","type":"uint256"}],"internalType":"struct LibNativeOrder.LimitOrder[]","name":"orders","type":"tuple[]"},{"components":[{"internalType":"enum LibSignature.SignatureType","name":"signatureType","type":"uint8"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct LibSignature.Signature[]","name":"signatures","type":"tuple[]"},{"internalType":"uint128[]","name":"takerTokenFillAmounts","type":"uint128[]"},{"internalType":"bool","name":"revertIfIncomplete","type":"bool"}],"name":"batchFillLimitOrders","outputs":[{"internalType":"uint128[]","name":"takerTokenFilledAmounts","type":"uint128[]"},{"internalType":"uint128[]","name":"makerTokenFilledAmounts","type":"uint128[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IERC20TokenV06","name":"makerToken","type":"address"},{"internalType":"contract IERC20TokenV06","name":"takerToken","type":"address"},{"internalType":"uint128","name":"makerAmount","type":"uint128"},{"internalType":"uint128","name":"takerAmount","type":"uint128"},{"internalType":"address","name":"maker","type":"address"},{"internalType":"address","name":"taker","type":"address"},{"internalType":"address","name":"txOrigin","type":"address"},{"internalType":"bytes32","name":"pool","type":"bytes32"},{"internalType":"uint64","name":"expiry","type":"uint64"},{"internalType":"uint256","name":"salt","type":"uint256"}],"internalType":"struct LibNativeOrder.RfqOrder[]","name":"orders","type":"tuple[]"},{"components":[{"internalType":"enum LibSignature.SignatureType","name":"signatureType","type":"uint8"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"internalType":"struct LibSignature.Signature[]","name":"signatures","type":"tuple[]"},{"internalType":"uint128[]","name":"takerTokenFillAmounts","type":"uint128[]"},{"internalType":"bool","name":"revertIfIncomplete","type":"bool"}],"name":"batchFillRfqOrders","outputs":[{"internalType":"uint128[]","name":"takerTokenFilledAmounts","type":"uint128[]"},{"internalType":"uint128[]","name":"makerTokenFilledAmounts","type":"uint128[]"}],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"bootstrap","outputs":[],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[],"name":"FEATURE_NAME","outputs":[{"internalType":"string","name":"name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"FEATURE_VERSION","outputs":[{"internalType":"uint256","name":"version","type":"uint256"}],"stateMutability":"view","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"contract IERC20TokenV06","name":"erc20","type":"address"},{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address payable","name":"recipientWallet","type":"address"}],"name":"transferTrappedTokensTo","outputs":[],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"contract IERC20TokenV06","name":"inputToken","type":"address"},{"indexed":false,"internalType":"contract IERC20TokenV06","name":"outputToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"inputTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outputTokenAmount","type":"uint256"},{"indexed":false,"internalType":"contract ILiquidityProvider","name":"provider","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"}],"name":"LiquidityProviderSwap","type":"event"},{"inputs":[{"internalType":"contract IERC20TokenV06","name":"inputToken","type":"address"},{"internalType":"contract IERC20TokenV06","name":"outputToken","type":"address"},{"internalType":"contract ILiquidityProvider","name":"provider","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"},{"internalType":"bytes","name":"auxiliaryData","type":"bytes"}],"name":"sellToLiquidityProvider","outputs":[{"internalType":"uint256","name":"boughtAmount","type":"uint256"}],"stateMutability":"payable","type":"function"}]

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"contract IERC20TokenV06","name":"outputToken","type":"address"},{"components":[{"internalType":"enum IMultiplexFeature.MultiplexSubcall","name":"id","type":"uint8"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IMultiplexFeature.BatchSellSubcall[]","name":"calls","type":"tuple[]"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"}],"name":"multiplexBatchSellEthForToken","outputs":[{"internalType":"uint256","name":"boughtAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"contract IERC20TokenV06","name":"inputToken","type":"address"},{"components":[{"internalType":"enum IMultiplexFeature.MultiplexSubcall","name":"id","type":"uint8"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IMultiplexFeature.BatchSellSubcall[]","name":"calls","type":"tuple[]"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"}],"name":"multiplexBatchSellTokenForEth","outputs":[{"internalType":"uint256","name":"boughtAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20TokenV06","name":"inputToken","type":"address"},{"internalType":"contract IERC20TokenV06","name":"outputToken","type":"address"},{"components":[{"internalType":"enum IMultiplexFeature.MultiplexSubcall","name":"id","type":"uint8"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IMultiplexFeature.BatchSellSubcall[]","name":"calls","type":"tuple[]"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"}],"name":"multiplexBatchSellTokenForToken","outputs":[{"internalType":"uint256","name":"boughtAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"components":[{"internalType":"enum IMultiplexFeature.MultiplexSubcall","name":"id","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IMultiplexFeature.MultiHopSellSubcall[]","name":"calls","type":"tuple[]"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"}],"name":"multiplexMultiHopSellEthForToken","outputs":[{"internalType":"uint256","name":"boughtAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"components":[{"internalType":"enum IMultiplexFeature.MultiplexSubcall","name":"id","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IMultiplexFeature.MultiHopSellSubcall[]","name":"calls","type":"tuple[]"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"}],"name":"multiplexMultiHopSellTokenForEth","outputs":[{"internalType":"uint256","name":"boughtAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"tokens","type":"address[]"},{"components":[{"internalType":"enum IMultiplexFeature.MultiplexSubcall","name":"id","type":"uint8"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IMultiplexFeature.MultiHopSellSubcall[]","name":"calls","type":"tuple[]"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"}],"name":"multiplexMultiHopSellTokenForToken","outputs":[{"internalType":"uint256","name":"boughtAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"},{"indexed":false,"internalType":"address","name":"migrator","type":"address"},{"indexed":false,"internalType":"address","name":"newOwner","type":"address"}],"name":"Migrated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"newOwner","type":"address"}],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"ownerAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"contract IERC20TokenV06[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"},{"internalType":"enum IPancakeSwapFeature.ProtocolFork","name":"fork","type":"uint8"}],"name":"sellToPancakeSwap","outputs":[{"internalType":"uint256","name":"buyAmount","type":"uint256"}],"stateMutability":"payable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes4","name":"selector","type":"bytes4"},{"indexed":false,"internalType":"address","name":"oldImpl","type":"address"},{"indexed":false,"internalType":"address","name":"newImpl","type":"address"}],"name":"ProxyFunctionUpdated","type":"event"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"address","name":"impl","type":"address"}],"name":"extend","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"uint256","name":"idx","type":"uint256"}],"name":"getRollbackEntryAtIndex","outputs":[{"internalType":"address","name":"impl","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"getRollbackLength","outputs":[{"internalType":"uint256","name":"rollbackLength","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"},{"internalType":"address","name":"targetImpl","type":"address"}],"name":"rollback","outputs":[],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[],"name":"testFn","outputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"stateMutability":"view","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"contract IERC20TokenV06","name":"token","type":"address"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"_spendERC20Tokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllowanceTarget","outputs":[{"internalType":"address","name":"target","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IERC20TokenV06","name":"token","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"getSpendableERC20BalanceOf","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"}]

View File

@@ -0,0 +1 @@
[{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"quoteSigner","type":"address"}],"name":"QuoteSignerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"taker","type":"address"},{"indexed":false,"internalType":"address","name":"inputToken","type":"address"},{"indexed":false,"internalType":"address","name":"outputToken","type":"address"},{"indexed":false,"internalType":"uint256","name":"inputTokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"outputTokenAmount","type":"uint256"}],"name":"TransformedERC20","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"transformerDeployer","type":"address"}],"name":"TransformerDeployerUpdated","type":"event"},{"inputs":[{"components":[{"internalType":"address payable","name":"taker","type":"address"},{"internalType":"contract IERC20TokenV06","name":"inputToken","type":"address"},{"internalType":"contract IERC20TokenV06","name":"outputToken","type":"address"},{"internalType":"uint256","name":"inputTokenAmount","type":"uint256"},{"internalType":"uint256","name":"minOutputTokenAmount","type":"uint256"},{"components":[{"internalType":"uint32","name":"deploymentNonce","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ITransformERC20Feature.Transformation[]","name":"transformations","type":"tuple[]"},{"internalType":"bool","name":"useSelfBalance","type":"bool"},{"internalType":"address payable","name":"recipient","type":"address"}],"internalType":"struct ITransformERC20Feature.TransformERC20Args","name":"args","type":"tuple"}],"name":"_transformERC20","outputs":[{"internalType":"uint256","name":"outputTokenAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"createTransformWallet","outputs":[{"internalType":"contract IFlashWallet","name":"wallet","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getQuoteSigner","outputs":[{"internalType":"address","name":"signer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransformWallet","outputs":[{"internalType":"contract IFlashWallet","name":"wallet","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransformerDeployer","outputs":[{"internalType":"address","name":"deployer","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"quoteSigner","type":"address"}],"name":"setQuoteSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transformerDeployer","type":"address"}],"name":"setTransformerDeployer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20TokenV06","name":"inputToken","type":"address"},{"internalType":"contract IERC20TokenV06","name":"outputToken","type":"address"},{"internalType":"uint256","name":"inputTokenAmount","type":"uint256"},{"internalType":"uint256","name":"minOutputTokenAmount","type":"uint256"},{"components":[{"internalType":"uint32","name":"deploymentNonce","type":"uint32"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct ITransformERC20Feature.Transformation[]","name":"transformations","type":"tuple[]"}],"name":"transformERC20","outputs":[{"internalType":"uint256","name":"outputTokenAmount","type":"uint256"}],"stateMutability":"payable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"contract IERC20TokenV06[]","name":"tokens","type":"address[]"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"},{"internalType":"bool","name":"isSushi","type":"bool"}],"name":"sellToUniswap","outputs":[{"internalType":"uint256","name":"buyAmount","type":"uint256"}],"stateMutability":"payable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"bytes","name":"encodedPath","type":"bytes"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"_sellHeldTokenForTokenToUniswapV3","outputs":[{"internalType":"uint256","name":"buyAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedPath","type":"bytes"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sellEthForTokenToUniswapV3","outputs":[{"internalType":"uint256","name":"buyAmount","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedPath","type":"bytes"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"},{"internalType":"address payable","name":"recipient","type":"address"}],"name":"sellTokenForEthToUniswapV3","outputs":[{"internalType":"uint256","name":"buyAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedPath","type":"bytes"},{"internalType":"uint256","name":"sellAmount","type":"uint256"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"},{"internalType":"address","name":"recipient","type":"address"}],"name":"sellTokenForTokenToUniswapV3","outputs":[{"internalType":"uint256","name":"buyAmount","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"ethRecipient","type":"address"}],"name":"die","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"sender","type":"address"},{"internalType":"address payable","name":"taker","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IERC20Transformer.TransformContext","name":"context","type":"tuple"}],"name":"transform","outputs":[{"internalType":"bytes4","name":"success","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"guy","type":"address"},{"name":"wad","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"src","type":"address"},{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"wad","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"dst","type":"address"},{"name":"wad","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"deposit","outputs":[],"payable":true,"stateMutability":"payable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"},{"name":"","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"guy","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"dst","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Deposit","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"src","type":"address"},{"indexed":false,"name":"wad","type":"uint256"}],"name":"Withdrawal","type":"event"}]

View File

@@ -0,0 +1 @@
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"stateMutability":"payable","type":"fallback"},{"inputs":[{"internalType":"bytes4","name":"selector","type":"bytes4"}],"name":"getFunctionImplementation","outputs":[{"internalType":"address","name":"impl","type":"address"}],"stateMutability":"view","type":"function"},{"stateMutability":"payable","type":"receive"}]

View File

@@ -0,0 +1 @@
[{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"AuthorizedAddressAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"AuthorizedAddressRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"addAuthorizedAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"authorities","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authorized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"executeCall","outputs":[{"internalType":"bytes","name":"resultData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAuthorizedAddresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"removeAuthorizedAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"removeAuthorizedAddressAtIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address payable","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"executeCall","outputs":[{"internalType":"bytes","name":"resultData","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address payable","name":"target","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"executeDelegateCall","outputs":[{"internalType":"bytes","name":"resultData","type":"bytes"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155BatchReceived","outputs":[{"internalType":"bytes4","name":"success","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC1155Received","outputs":[{"internalType":"bytes4","name":"success","type":"bytes4"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceID","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"hasSupport","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"tokenFallback","outputs":[],"stateMutability":"pure","type":"function"},{"stateMutability":"payable","type":"receive"}]

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"address","name":"owner_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"provider","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"},{"internalType":"bytes","name":"auxiliaryData","type":"bytes"}],"name":"executeSellEthForToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"},{"internalType":"bytes","name":"auxiliaryData","type":"bytes"}],"name":"executeSellTokenForEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"provider","type":"address"},{"internalType":"address","name":"inputToken","type":"address"},{"internalType":"address","name":"outputToken","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"minBuyAmount","type":"uint256"},{"internalType":"bytes","name":"auxiliaryData","type":"bytes"}],"name":"executeSellTokenForToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"address[]","name":"initialAuthorities","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"AuthorizedAddressAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"target","type":"address"},{"indexed":true,"internalType":"address","name":"caller","type":"address"}],"name":"AuthorizedAddressRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"deployedAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"nonce","type":"uint256"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Deployed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"target","type":"address"},{"indexed":false,"internalType":"address","name":"sender","type":"address"}],"name":"Killed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"addAuthorizedAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"authorities","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"authorized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"bytecode","type":"bytes"}],"name":"deploy","outputs":[{"internalType":"address","name":"deployedAddress","type":"address"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getAuthorizedAddresses","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"contract IKillable","name":"target","type":"address"},{"internalType":"address payable","name":"ethRecipient","type":"address"}],"name":"kill","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"}],"name":"removeAuthorizedAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"removeAuthorizedAddressAtIndex","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"toDeploymentNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"contract IExchange","name":"exchange_","type":"address"},{"internalType":"contract IBridgeAdapter","name":"bridgeAdapter_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"orderHash","type":"bytes32"}],"name":"ProtocolFeeUnfunded","type":"event"},{"inputs":[],"name":"bridgeAdapter","outputs":[{"internalType":"contract IBridgeAdapter","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"ethRecipient","type":"address"}],"name":"die","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"erc20Proxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"exchange","outputs":[{"internalType":"contract IExchange","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"sender","type":"address"},{"internalType":"address payable","name":"taker","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IERC20Transformer.TransformContext","name":"context","type":"tuple"}],"name":"transform","outputs":[{"internalType":"bytes4","name":"success","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"ethRecipient","type":"address"}],"name":"die","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"sender","type":"address"},{"internalType":"address payable","name":"taker","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IERC20Transformer.TransformContext","name":"context","type":"tuple"}],"name":"transform","outputs":[{"internalType":"bytes4","name":"success","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"}]

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"contract IEtherTokenV06","name":"weth_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"deployer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address payable","name":"ethRecipient","type":"address"}],"name":"die","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address payable","name":"sender","type":"address"},{"internalType":"address payable","name":"taker","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"internalType":"struct IERC20Transformer.TransformContext","name":"context","type":"tuple"}],"name":"transform","outputs":[{"internalType":"bytes4","name":"success","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IEtherTokenV06","name":"","type":"address"}],"stateMutability":"view","type":"function"}]

View File

@@ -0,0 +1 @@
[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}]

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,25 @@
[
{
"inputs": [
{
"internalType": "uint256",
"name": "fee0",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "fee1",
"type": "uint256"
},
{
"internalType": "bytes",
"name": "data",
"type": "bytes"
}
],
"name": "uniswapV3FlashCallback",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
}
]

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"uint256","name":"amount0Owed","type":"uint256"},{"internalType":"uint256","name":"amount1Owed","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"uniswapV3MintCallback","outputs":[],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -0,0 +1 @@
[{"inputs":[{"internalType":"int256","name":"amount0Delta","type":"int256"},{"internalType":"int256","name":"amount1Delta","type":"int256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"uniswapV3SwapCallback","outputs":[],"stateMutability":"nonpayable","type":"function"}]

View File

@@ -3,11 +3,14 @@ from .curve import CURVE_CLASSIFIER_SPECS
from .erc20 import ERC20_CLASSIFIER_SPECS
from .uniswap import UNISWAP_CLASSIFIER_SPECS
from .weth import WETH_CLASSIFIER_SPECS
from .zerox import ZEROX_CLASSIFIER_SPECS
ALL_CLASSIFIER_SPECS = (
ERC20_CLASSIFIER_SPECS
+ WETH_CLASSIFIER_SPECS
+ CURVE_CLASSIFIER_SPECS
+ UNISWAP_CLASSIFIER_SPECS
+ WETH_CLASSIFIER_SPECS
+ AAVE_CLASSIFIER_SPECS
+ ZEROX_CLASSIFIER_SPECS
)

View File

@@ -63,12 +63,24 @@ UNISWAP_V3_CONTRACT_SPECS = [
),
]
UNISWAP_V3_POOL_SPEC = ClassifierSpec(
abi_name="UniswapV3Pool",
classifications={
"swap(address,bool,int256,uint160,bytes)": Classification.swap,
},
)
UNISWAP_V3_GENERAL_SPECS = [
ClassifierSpec(
abi_name="UniswapV3Pool",
classifications={
"swap(address,bool,int256,uint160,bytes)": Classification.swap,
},
),
ClassifierSpec(
abi_name="IUniswapV3SwapCallback",
),
ClassifierSpec(
abi_name="IUniswapV3MintCallback",
),
ClassifierSpec(
abi_name="IUniswapV3FlashCallback",
),
]
UNISWAPPY_V2_CONTRACT_SPECS = [
ClassifierSpec(
@@ -93,6 +105,6 @@ UNISWAPPY_V2_PAIR_SPEC = ClassifierSpec(
UNISWAP_CLASSIFIER_SPECS = [
*UNISWAP_V3_CONTRACT_SPECS,
*UNISWAPPY_V2_CONTRACT_SPECS,
UNISWAP_V3_POOL_SPEC,
*UNISWAP_V3_GENERAL_SPECS,
UNISWAPPY_V2_PAIR_SPEC,
]

View File

@@ -0,0 +1,166 @@
from mev_inspect.schemas.classified_traces import (
ClassifierSpec,
Protocol,
)
ZEROX_CONTRACT_SPECS = [
ClassifierSpec(
abi_name="exchangeProxy",
protocol=Protocol.zerox,
valid_contract_addresses=["0xDef1C0ded9bec7F1a1670819833240f027b25EfF"],
),
ClassifierSpec(
abi_name="exchangeProxyAllowanceTarget",
protocol=Protocol.zerox,
valid_contract_addresses=["0xf740b67da229f2f10bcbd38a7979992fcc71b8eb"],
),
ClassifierSpec(
abi_name="exchangeProxyFlashWallet",
protocol=Protocol.zerox,
valid_contract_addresses=["0x22f9dcf4647084d6c31b2765f6910cd85c178c18"],
),
ClassifierSpec(
abi_name="exchangeProxyGovernor",
protocol=Protocol.zerox,
valid_contract_addresses=["0x618f9c67ce7bf1a50afa1e7e0238422601b0ff6e"],
),
ClassifierSpec(
abi_name="exchangeProxyLiquidityProviderSandbox",
protocol=Protocol.zerox,
valid_contract_addresses=["0x407b4128e9ecad8769b2332312a9f655cb9f5f3a"],
),
ClassifierSpec(
abi_name="exchangeProxyTransformerDeployer",
protocol=Protocol.zerox,
valid_contract_addresses=["0x39dce47a67ad34344eab877eae3ef1fa2a1d50bb"],
),
ClassifierSpec(
abi_name="wethTransformer",
protocol=Protocol.zerox,
valid_contract_addresses=["0xb2bc06a4efb20fc6553a69dbfa49b7be938034a7"],
),
ClassifierSpec(
abi_name="payTakerTransformer",
protocol=Protocol.zerox,
valid_contract_addresses=["0x4638a7ebe75b911b995d0ec73a81e4f85f41f24e"],
),
ClassifierSpec(
abi_name="fillQuoteTransformer",
protocol=Protocol.zerox,
valid_contract_addresses=["0x5ce5174d7442061135ea849970ffc7763920e0fd"],
),
ClassifierSpec(
abi_name="affiliateFeeTransformer",
protocol=Protocol.zerox,
valid_contract_addresses=["0xda6d9fc5998f550a094585cf9171f0e8ee3ac59f"],
),
ClassifierSpec(
abi_name="staking",
protocol=Protocol.zerox,
valid_contract_addresses=["0x2a17c35ff147b32f13f19f2e311446eeb02503f3"],
),
ClassifierSpec(
abi_name="stakingProxy",
protocol=Protocol.zerox,
valid_contract_addresses=["0xa26e80e7dea86279c6d778d702cc413e6cffa777"],
),
ClassifierSpec(
abi_name="zrxToken",
protocol=Protocol.zerox,
valid_contract_addresses=["0xe41d2489571d322189246dafa5ebde1f4699f498"],
),
ClassifierSpec(
abi_name="zrxVault",
protocol=Protocol.zerox,
valid_contract_addresses=["0xba7f8b5fb1b19c1211c5d49550fcd149177a5eaf"],
),
ClassifierSpec(
abi_name="devUtils",
protocol=Protocol.zerox,
valid_contract_addresses=["0x74134cf88b21383713e096a5ecf59e297dc7f547"],
),
ClassifierSpec(
abi_name="etherToken",
protocol=Protocol.zerox,
valid_contract_addresses=["0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2"],
),
ClassifierSpec(
abi_name="erc20BridgeSampler",
protocol=Protocol.zerox,
valid_contract_addresses=["0xd8c38704c9937ea3312de29f824b4ad3450a5e61"],
),
]
ZEROX_GENERIC_SPECS = [
ClassifierSpec(
abi_name="IBatchFillNativeOrdersFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="IFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="IFundRecoveryFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="ILiquidityProviderFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="IMetaTransactionsFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="IMultiplexFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="INativeOrdersFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="IOtcOrdersFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="IOwnableFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="IPancakeSwapFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="ISimpleFunctionRegistryFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="ITestSimpleFunctionRegistryFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="ITokenSpenderFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="ITransformERC20Feature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="IUniswapFeature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="IUniswapV3Feature",
protocol=Protocol.zerox,
),
ClassifierSpec(
abi_name="IBootstrapFeature",
protocol=Protocol.zerox,
),
]
ZEROX_CLASSIFIER_SPECS = ZEROX_CONTRACT_SPECS + ZEROX_GENERIC_SPECS

View File

@@ -6,14 +6,16 @@ from mev_inspect.schemas.blocks import CallAction, CallResult, Trace, TraceType
from mev_inspect.schemas.classified_traces import (
Classification,
ClassifiedTrace,
ClassifierSpec,
CallTrace,
DecodedCallTrace,
)
from .specs import ALL_CLASSIFIER_SPECS
class TraceClassifier:
def __init__(self, classifier_specs: List[ClassifierSpec]) -> None:
# TODO - index by contract_addresses for speed
self._classifier_specs = classifier_specs
def __init__(self) -> None:
self._classifier_specs = ALL_CLASSIFIER_SPECS
self._decoders_by_abi_name: Dict[str, ABIDecoder] = {}
for spec in self._classifier_specs:
@@ -69,7 +71,7 @@ class TraceClassifier:
signature, Classification.unknown
)
return ClassifiedTrace(
return DecodedCallTrace(
**trace.dict(),
trace_type=trace.type,
classification=classification,
@@ -85,7 +87,7 @@ class TraceClassifier:
gas_used=result.gas_used if result is not None else None,
)
return ClassifiedTrace(
return CallTrace(
**trace.dict(),
trace_type=trace.type,
classification=Classification.unknown,

View File

@@ -0,0 +1,31 @@
import json
from typing import List
from mev_inspect.models.miner_payments import MinerPaymentModel
from mev_inspect.schemas.miner_payments import MinerPayment
def delete_miner_payments_for_block(
db_session,
block_number: int,
) -> None:
(
db_session.query(MinerPaymentModel)
.filter(MinerPaymentModel.block_number == block_number)
.delete()
)
db_session.commit()
def write_miner_payments(
db_session,
miner_payments: List[MinerPayment],
) -> None:
models = [
MinerPaymentModel(**json.loads(miner_payment.json()))
for miner_payment in miner_payments
]
db_session.bulk_save_objects(models)
db_session.commit()

View File

@@ -4,8 +4,16 @@ from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
def get_sqlalchemy_database_uri():
username = os.getenv("POSTGRES_USER")
password = os.getenv("POSTGRES_PASSWORD")
server = "postgresql"
db_name = "mev_inspect"
return f"postgresql://{username}:{password}@{server}/{db_name}"
def get_engine():
return create_engine(os.getenv("SQLALCHEMY_DATABASE_URI"))
return create_engine(get_sqlalchemy_database_uri())
def get_session():

View File

@@ -22,6 +22,12 @@ def get_miner_payments(
for receipt in receipts:
transaciton_traces = traces_by_transaction_hash[receipt.transaction_hash]
if len(transaciton_traces) == 0:
continue
first_trace = sorted(transaciton_traces, key=lambda t: t.trace_address)[0]
eth_transfers = get_eth_transfers(transaciton_traces)
miner_eth_transfers = filter_transfers(
eth_transfers, to_address=miner_address.lower()
@@ -46,6 +52,8 @@ def get_miner_payments(
base_fee_per_gas=base_fee_per_gas,
gas_used=receipt.gas_used,
coinbase_transfer=coinbase_transfer,
transaction_to_address=first_trace.to_address,
transaction_from_address=first_trace.from_address,
)
)

View File

@@ -0,0 +1,19 @@
from sqlalchemy import Column, Numeric, String
from .base import Base
class MinerPaymentModel(Base):
__tablename__ = "miner_payments"
block_number = Column(Numeric, nullable=False)
transaction_hash = Column(String, primary_key=True)
transaction_index = Column(Numeric, nullable=False)
miner_address = Column(String, nullable=False)
coinbase_transfer = Column(Numeric, nullable=False)
base_fee_per_gas = Column(Numeric, nullable=False)
gas_price = Column(Numeric, nullable=False)
gas_price_with_coinbase_transfer = Column(Numeric, nullable=False)
gas_used = Column(Numeric, nullable=False)
transaction_from_address = Column(String, nullable=True)
transaction_to_address = Column(String, nullable=True)

View File

@@ -3,7 +3,7 @@ from typing import Any, Dict, List, Optional
from pydantic import BaseModel
from .blocks import TraceType
from .blocks import Trace
class Classification(Enum):
@@ -21,27 +21,31 @@ class Protocol(Enum):
aave = "aave"
weth = "weth"
curve = "curve"
zerox = "0x"
class ClassifiedTrace(BaseModel):
class ClassifiedTrace(Trace):
transaction_hash: str
block_number: int
trace_type: TraceType
trace_address: List[int]
classification: Classification
protocol: Optional[Protocol]
abi_name: Optional[str]
function_name: Optional[str]
function_signature: Optional[str]
inputs: Optional[Dict[str, Any]]
# Optional
error: Optional[str]
to_address: Optional[str]
from_address: Optional[str]
gas: Optional[int]
value: Optional[int]
gas_used: Optional[int]
error: Optional[str]
protocol: Optional[Protocol]
function_name: Optional[str]
function_signature: Optional[str]
inputs: Optional[Dict[str, Any]]
abi_name: Optional[str]
class Config:
validate_assignment = True
json_encoders = {
# a little lazy but fine for now
# this is used for bytes value inputs
@@ -49,6 +53,24 @@ class ClassifiedTrace(BaseModel):
}
class CallTrace(ClassifiedTrace):
to_address: str
from_address: str
class DecodedCallTrace(CallTrace):
inputs: Dict[str, Any]
abi_name: str
# Optional
protocol: Optional[Protocol]
gas: Optional[int]
gas_used: Optional[int]
function_name: Optional[str]
function_signature: Optional[str]
class ClassifierSpec(BaseModel):
abi_name: str
protocol: Optional[Protocol] = None

View File

@@ -1,3 +1,5 @@
from typing import Optional
from pydantic import BaseModel
@@ -11,3 +13,5 @@ class MinerPayment(BaseModel):
gas_price: int
gas_price_with_coinbase_transfer: int
gas_used: int
transaction_to_address: Optional[str]
transaction_from_address: Optional[str]

View File

@@ -10,7 +10,6 @@ class Swap(BaseModel):
transaction_hash: str
block_number: int
trace_address: List[int]
protocol: Optional[Protocol]
pool_address: str
from_address: str
to_address: str
@@ -18,4 +17,7 @@ class Swap(BaseModel):
token_in_amount: int
token_out_address: str
token_out_amount: int
# Optional
protocol: Optional[Protocol]
error: Optional[str]

View File

@@ -42,6 +42,8 @@ attach = 'scripts.poetry.docker:attach'
exec = 'scripts.poetry.docker:exec'
inspect = 'scripts.poetry.inspect:inspect'
inspect-many = 'scripts.poetry.inspect:inspect_many'
inspect-block = 'scripts.inspect_block:inspect_block'
inspect-many-blocks = 'scripts.inspect_block:inspect_many_blocks'
[tool.black]
exclude = '''

View File

@@ -3,7 +3,9 @@ import json
import click
from web3 import Web3
from mev_inspect.arbitrages import get_arbitrages
from mev_inspect.block import create_from_block_number
from mev_inspect.classifiers.trace import TraceClassifier
from mev_inspect.crud.arbitrages import (
delete_arbitrages_for_block,
write_arbitrages,
@@ -12,10 +14,10 @@ from mev_inspect.crud.classified_traces import (
delete_classified_traces_for_block,
write_classified_traces,
)
from mev_inspect.arbitrages import get_arbitrages
from mev_inspect.classifiers.specs import ALL_CLASSIFIER_SPECS
from mev_inspect.classifiers.trace import TraceClassifier
from mev_inspect.crud.miner_payments import (
delete_miner_payments_for_block,
write_miner_payments,
)
from mev_inspect.crud.swaps import delete_swaps_for_block, write_swaps
from mev_inspect.db import get_session
from mev_inspect.miner_payments import get_miner_payments
@@ -78,10 +80,11 @@ def _inspect_block(
block_number: int,
should_cache: bool,
should_print_stats: bool = True,
should_print_miner_payments: bool = True,
should_write_classified_traces: bool = True,
should_write_swaps: bool = True,
should_write_arbitrages: bool = True,
should_print_miner_payments: bool = True,
should_write_miner_payments: bool = True,
):
block = create_from_block_number(base_provider, w3, block_number, should_cache)
@@ -92,7 +95,7 @@ def _inspect_block(
)
click.echo(f"Total transactions: {total_transactions}")
trace_clasifier = TraceClassifier(ALL_CLASSIFIER_SPECS)
trace_clasifier = TraceClassifier()
classified_traces = trace_clasifier.classify(block.traces)
click.echo(f"Returned {len(classified_traces)} classified traces")
@@ -127,6 +130,10 @@ def _inspect_block(
if should_print_miner_payments:
click.echo(json.dumps([p.dict() for p in miner_payments], indent=4))
if should_write_miner_payments:
delete_miner_payments_for_block(db_session, block_number)
write_miner_payments(db_session, miner_payments)
def get_stats(classified_traces) -> dict:
stats: dict = {}

View File

@@ -1,7 +1,12 @@
from typing import List
from mev_inspect.schemas.blocks import TraceType
from mev_inspect.schemas.classified_traces import Classification, ClassifiedTrace
from mev_inspect.schemas.classified_traces import (
Classification,
ClassifiedTrace,
CallTrace,
DecodedCallTrace,
)
def make_transfer_trace(
@@ -12,11 +17,13 @@ def make_transfer_trace(
to_address: str,
token_address: str,
amount: int,
action: dict = {},
subtraces: int = 0,
):
return ClassifiedTrace(
return CallTrace(
transaction_hash=transaction_hash,
block_number=block_number,
trace_type=TraceType.call,
type=TraceType.call,
trace_address=trace_address,
classification=Classification.transfer,
from_address=from_address,
@@ -25,6 +32,9 @@ def make_transfer_trace(
"recipient": to_address,
"amount": amount,
},
block_hash=str(block_number),
action=action,
subtraces=subtraces,
)
@@ -37,45 +47,55 @@ def make_swap_trace(
abi_name: str,
recipient_address: str,
recipient_input_key: str,
action: dict = {},
subtraces: int = 0,
):
return ClassifiedTrace(
return DecodedCallTrace(
transaction_hash=transaction_hash,
block_number=block_number,
trace_type=TraceType.call,
type=TraceType.call,
trace_address=trace_address,
action=action,
subtraces=subtraces,
classification=Classification.swap,
from_address=from_address,
to_address=pool_address,
inputs={recipient_input_key: recipient_address},
abi_name=abi_name,
block_hash=str(block_number),
)
def make_unknown_trace(
block_number,
transaction_hash,
trace_address,
block_number: int,
transaction_hash: str,
trace_address: List[int],
action={},
subtraces=0,
):
return ClassifiedTrace(
transaction_hash=transaction_hash,
block_number=block_number,
trace_type=TraceType.call,
transaction_hash=transaction_hash,
trace_address=trace_address,
action=action,
subtraces=subtraces,
block_hash=str(block_number),
type=TraceType.call,
classification=Classification.unknown,
)
def make_many_unknown_traces(
block_number,
transaction_hash,
trace_addresses,
block_number: int,
transaction_hash: str,
trace_addresses: List[List[int]],
action: dict = {},
subtraces: int = 0,
) -> List[ClassifiedTrace]:
return [
make_unknown_trace(
block_number,
transaction_hash,
trace_address,
block_number, transaction_hash, trace_address, action, subtraces
)
for trace_address in trace_addresses
]

View File

@@ -1,5 +1,4 @@
from mev_inspect.arbitrages import get_arbitrages
from mev_inspect.classifiers.specs import ALL_CLASSIFIER_SPECS
from mev_inspect.classifiers.trace import TraceClassifier
from mev_inspect.swaps import get_swaps
@@ -9,7 +8,7 @@ from .utils import load_test_block
def test_arbitrage_real_block():
block = load_test_block(12914944)
trace_clasifier = TraceClassifier(ALL_CLASSIFIER_SPECS)
trace_clasifier = TraceClassifier()
classified_traces = trace_clasifier.classify(block.traces)
swaps = get_swaps(classified_traces)

View File

@@ -0,0 +1,19 @@
{
"Extensions": [
{
"Name": "helm_remote",
"ExtensionRegistry": "https://github.com/tilt-dev/tilt-extensions",
"TimeFetched": "2021-09-03T08:56:46.938205-04:00"
},
{
"Name": "global_vars",
"ExtensionRegistry": "https://github.com/tilt-dev/tilt-extensions",
"TimeFetched": "2021-09-03T08:56:48.751933-04:00"
},
{
"Name": "secret",
"ExtensionRegistry": "https://github.com/tilt-dev/tilt-extensions",
"TimeFetched": "2021-09-09T08:57:26.199313-06:00"
}
]
}

View File

@@ -0,0 +1,13 @@
# Git Resource
Author: [Bob Jackman](https://github.com/kogi)
An extension for reading/writing global variable values
## Usage
```python
set_global('foo', some_value)
print(get_global('foo'))
unset_global('foo')
```

View File

@@ -0,0 +1,11 @@
def get_global(name):
return os.getenv(_get_env_name(name))
def set_global(name, value):
os.putenv(_get_env_name(name), value)
def unset_global(name):
os.unsetenv(_get_env_name(name))
def _get_env_name(name):
return 'TILT_GLOBAL_VAR_%s' % name.upper()

View File

@@ -0,0 +1,41 @@
# Helm Remote
Author: [Bob Jackman](https://github.com/kogi)
Install a remotely hosted Helm chart in a way that it will be properly uninstalled when running `tilt down`
## Usage
#### Install a Remote Chart
```py
load('ext://helm_remote', 'helm_remote')
helm_remote('myChartName')
```
##### Additional Parameters
```
helm_remote(chart, repo_url='', repo_name='', release_name='', namespace='', version='', username='', password='', values=[], set=[])
```
* `chart` ( str ) the name of the chart to install
* `repo_name` ( str ) the name of the repo within which to find the chart (assuming the repo is already added locally)
<br> if omitted, defaults to the same value as `chart_name`
* `repo_url` ( str ) the URL of the repo within which to find the chart (equivalent to `helm repo add <repo_name> <repo_url>`)
* `release_name` (str) - the name of the helm release
<br> if omitted, defaults to the same value as `chart_name`
* `namespace` ( str ) the namespace to deploy the chart to (equivalent to helm's `--namespace <namespace>` flags)
* `version` ( str ) the version of the chart to install. If omitted, defaults to latest version (equivalent to helm's `--version` flag)
* `username` ( str ) repository authentication username, if needed (equivalent to helm's `--username` flag)
* `password` ( str ) repository authentication password, if needed (equivalent to helm's `--password` flag)
* `values` ( Union [ str , List [ str ]]) Specify one or more values files (in addition to the values.yaml file in the chart). Equivalent to the helm's `--values` or `-f` flags
* `set` ( Union [ str , List [ str ]]) Directly specify one or more values (equivalent to helm's `--set` flag)
* `allow_duplicates` ( bool ) - Allow duplicate resources. Usually duplicate resources indicate a programmer error.
But some charts specify resources twice.
* `create_namespace` ( bool ) - Create the namespace specified in `namespace` ( equivalent to helm's `--create_namespace` flag)
#### Change the Cache Location
By default `helm_remote` will store retrieved helm charts in the `.helm` directory at your workspace's root.
This location can be customized by calling `os.putenv('TILT_HELM_REMOTE_CACHE_DIR', new_directory)` before loading the module.

View File

@@ -0,0 +1,214 @@
load('ext://global_vars', 'get_global', 'set_global')
def _get_skip():
return get_global(_get_skip_name())
def _set_skip(value):
set_global(_get_skip_name(), value)
def _get_skip_name():
return 'HELM_REMOTE_SKIP_UPDATES'
if _get_skip() == None:
_set_skip('False') # Gets set to true after the first update, preventing further updates within the same build/instance/up
def _find_root_tiltfile_dir():
# Find top-level Tilt path
current = os.path.abspath('./')
while current != '/':
if os.path.exists(os.path.join(current, 'tilt_modules')):
return current
current = os.path.dirname(current)
fail('Could not find root Tiltfile')
def _find_cache_dir():
from_env = os.getenv('TILT_HELM_REMOTE_CACHE_DIR', '')
if from_env != '':
return from_env
return os.path.join(_find_root_tiltfile_dir(), '.helm')
# this is the root directory into which remote helm charts will be pulled/cloned/untar'd
# use `os.putenv('TILT_HELM_REMOTE_CACHE_DIR', new_dir)` to change
helm_remote_cache_dir = _find_cache_dir()
watch_settings(ignore=helm_remote_cache_dir)
# TODO: =====================================
# if it ever becomes possible for loaded files to also load their own extensions
# this method can be replaced by `load('ext://namespace', 'namespace_create')
def namespace_create(name):
"""Returns YAML for a namespace
Args: name: The namespace name. Currently not validated.
"""
k8s_yaml(blob("""apiVersion: v1
kind: Namespace
metadata:
name: %s
""" % name))
# TODO: end TODO
# =====================================
def helm_remote(chart, repo_url='', repo_name='', release_name='', values=[], set=[], namespace='', version='', username='', password='', allow_duplicates=False, create_namespace=False):
# ======== Helper methods
def get_local_repo(repo_name, repo_url):
# if no repos are present, helm exit code is >0 and stderr output buffered
added_helm_repos = decode_yaml(local('helm repo list --output yaml 2>/dev/null || true', command_bat='helm repo list --output yaml 2> nul || ver>nul', quiet=True))
repo = [item for item in added_helm_repos if item['name'] == chart and item['url'] == repo_url] if added_helm_repos != None else []
return repo[0] if len(repo) > 0 else None
# Command string builder with common argument logic
def build_helm_command(command, auth=None, version=None):
command = 'helm ' + command
if auth != None:
username, password = auth
if username != '':
command += ' --username %s' % shlex.quote(username)
if password != '':
command += ' --password %s' % shlex.quote(password)
if version != None and version != 'latest':
command += ' --version %s' % shlex.quote(version)
return command
def fetch_chart_details(chart, repo_name, auth, version):
command = build_helm_command('search repo %s/%s --output yaml' % (shlex.quote(repo_name), shlex.quote(chart)), None, version)
results = decode_yaml(local(command, quiet=True))
return results[0] if len(results) > 0 else None
# ======== Condition Incoming Arguments
if repo_name == '':
repo_name = chart
if release_name == '':
release_name = chart
if namespace == '':
namespace = 'default'
if version == '':
version = 'latest'
# ======== Validate before we start trusting chart/repo names
# Based on helm chart conventions, and the fact we don't want anyone traversing directories
# validate is to essentially ensure there's no special characters aside from '-' being used
# str.isalnum accepts dots, which is only dangerous when slashes are allowed
# https://helm.sh/docs/chart_best_practices/conventions/#chart-names
if chart.replace('-', '').isalnum() == False or chart != chart.replace('.', ''):
# https://helm.sh/docs/chart_best_practices/conventions/#chart-names
fail('Chart name is not valid')
if repo_name != chart and repo_name.replace('-', '').isalnum() == False or repo_name != repo_name.replace('.', ''):
# https://helm.sh/docs/chart_best_practices/conventions/#chart-names
fail('Repo name is not valid')
if version != 'latest' and version != version.replace('/', '').replace('\\', ''):
fail('Version cannot contain a forward slash')
# ======== Determine state of existing helm repo
if repo_url != '':
local_helm_repo = get_local_repo(repo_name, repo_url)
if local_helm_repo == None:
# Unaware of repo, add it
repo_command = 'repo add %s %s' % (shlex.quote(repo_name), shlex.quote(repo_url))
# Add authentication for adding the repository if credentials are provided
output = str(local(build_helm_command(repo_command, (username, password)), quiet=True)).rstrip('\n')
if 'already exists' not in output: # repo was added
_set_skip('False')
else:
# Helm is already aware of the chart, update repo (unfortunately you cannot specify a single repo)
if _get_skip() != 'True':
repo_command = 'repo update'
local(build_helm_command(repo_command), quiet=True)
_set_skip('True')
# ======== Create Namespace
if create_namespace and namespace != '' and namespace != 'default':
# avoid a namespace not found error
namespace_create(namespace) # do this early so it manages to register before we attempt to install into it
# ======== Initialize
# -------- targets
pull_target = os.path.join(helm_remote_cache_dir, repo_name, version)
chart_target = os.path.join(pull_target, chart)
cached_chart_exists = os.path.exists(chart_target)
needs_pull = True
if cached_chart_exists:
# Helm chart structure is concrete, we can trust this YAML file to exist
cached_chart_details = read_yaml(os.path.join(chart_target, 'Chart.yaml'))
# check if our local cached chart matches latest remote
remote_chart_details = fetch_chart_details(chart, repo_name, (username, password), version)
# pull when version mismatch
needs_pull = cached_chart_details['version'] != remote_chart_details['version']
if needs_pull:
# -------- commands
pull_command = 'pull %s/%s --untar --destination %s' % (repo_name, chart, pull_target)
# ======== Perform Installation
if cached_chart_exists:
local('rm -rf %s' % chart_target, command_bat='if exist %s ( rd /s /q %s )' % (chart_target, chart_target), quiet=True)
local(build_helm_command(pull_command, (username, password), version), quiet=True)
install_crds(chart, chart_target)
# TODO: since neither `k8s_yaml()` nor `helm()` accept resource_deps,
# sometimes the crds haven't yet finished installing before the below tries
# to run
yaml = helm(chart_target, name=release_name, namespace=namespace, values=values, set=set)
# The allow_duplicates API is only available in 0.17.1+
if allow_duplicates and _version_tuple() >= [0, 17, 1]:
k8s_yaml(yaml, allow_duplicates=allow_duplicates)
else:
k8s_yaml(yaml)
return yaml
def _version_tuple():
ver_string = str(local('tilt version', quiet=True))
versions = ver_string.split(', ')
# pull first string and remove the `v` and `-dev`
version = versions[0].replace('-dev', '').replace('v', '')
return [int(str_num) for str_num in version.split(".")]
# install CRDs as a separate resource and wait for them to be ready
def install_crds(name, directory):
name += '-crds'
files = str(local(r"grep --include='*.yaml' --include='*.yml' -rEil '\bkind[^\w]+CustomResourceDefinition\s*$' %s || exit 0" % directory, quiet=True)).rstrip('\n')
if files == '':
files = []
else:
files = files.split("\n")
# we're applying CRDs directly and not using helm preprocessing
# this will cause errors!
# since installing CRDs in this function is a nice-to-have, just skip
# any that have preprocessing
files = [f for f in files if str(read_file(f)).find('{{') == -1]
if len(files) != 0:
local_resource(name+'-install', cmd='kubectl apply -f %s' % " -f ".join(files), deps=files) # we can wait/depend on this, but it won't cause a proper uninstall
k8s_yaml(files) # this will cause a proper uninstall, but we can't wait/depend on it
# TODO: Figure out how to avoid another named resource showing up in the tilt HUD for this waiter
local_resource(name+'-ready', resource_deps=[name+'-install'], cmd='kubectl wait --for=condition=Established crd --all') # now we can wait for those crds to finish establishing

View File

@@ -0,0 +1,7 @@
FROM alpine
RUN apk update && apk add expect busybox-extras
ADD ./verify.exp ./verify.exp
ENTRYPOINT expect < verify.exp

View File

@@ -0,0 +1,17 @@
os.putenv('TILT_HELM_REMOTE_CACHE_DIR', os.path.abspath('./.helm'))
load('../Tiltfile', 'helm_remote')
# Note that .helm is in the .tiltignore!
helm_remote('memcached', repo_url='https://charts.bitnami.com/bitnami')
if not os.path.exists('./.helm/memcached'):
fail('memcached failed to load in the right directory')
# This chart has a bunch of CRDs (including templated CRDs), so we can test the CRD init logic.
helm_remote('gloo', repo_url='https://storage.googleapis.com/solo-public-helm',
# The gloo chart has duplicate resources, see discussion here:
# https://github.com/tilt-dev/tilt/issues/3656
allow_duplicates=True)
docker_build('helm-remote-test-verify', '.')
k8s_yaml('job.yaml')
k8s_resource('helm-remote-test-verify', resource_deps=['memcached'])

View File

@@ -0,0 +1,12 @@
apiVersion: batch/v1
kind: Job
metadata:
name: helm-remote-test-verify
spec:
backoffLimit: 1
template:
spec:
containers:
- name: helm-remote-test-verify
image: helm-remote-test-verify
restartPolicy: Never

View File

@@ -0,0 +1,7 @@
#!/bin/bash
cd "$(dirname "$0")"
set -ex
tilt ci
tilt down --delete-namespaces

View File

@@ -0,0 +1,12 @@
#!/usr/bin/expect
spawn telnet memcached 11211
expect {
timeout {exit 1}
"Connected"
}
send "stats\r\n"
expect {
timeout {exit 1}
"STAT pid 1"
}

View File

@@ -0,0 +1,70 @@
# Secret
Author: [Nick Santos](https://github.com/nicks)
Helper functions for creating Kubernetes secrets.
## Functions
### secret_yaml_generic
```
secret_yaml_generic(name: str, namespace: str = "", from_file: Union[str, List] = None, secret_type: str = None): Blob
```
Returns YAML for a generic secret.
* `from_file` ( str ) equivalent to `kubectl create secret --from-file`
* `secret_type` ( str ) - equivalent to `kubectl create secret --type`
### secret_create_generic
```
secret_create_generic(name: str, namespace: str = "", from_file: Union[str, List] = None, secret_type: str = None)
```
Deploys a secret to the cluster. Equivalent to
```
load('ext://secret', 'secret_yaml_generic')
k8s_yaml(secret_yaml_generic('name', from_file=[...]))
```
### secret_from_dict
```
secret_from_dict(name: str, namespace: str = "", inputs = None): blob
```
Returns YAML for a secret from a dictionary.
* `inputs` ( dict) - A dict of keys and values to use. Nesting is not supported
## Example Usage
### For a Postgres password:
```
load('ext://secret', 'secret_create_generic')
secret_create_generic('pgpass', from_file='.pgpass=./.pgpass')
```
### For Google Cloud Platform Key:
```
load('ext://secret', 'secret_create_generic')
secret_create_generic('gcp-key', from_file='key.json=./gcp-creds.json')
```
### From a dict:
```
load('ext://secret', 'secret_from_dict')
k8s_yaml(secret_from_dict("secrets", inputs = {
'SOME_TOKEN' : os.getenv('SOME_TOKEN')
}))
```
## Caveats
- This extension doesn't do any validation to confirm that names or namespaces are valid.

View File

@@ -0,0 +1,105 @@
# -*- mode: Python -*-
def secret_yaml_generic(name, namespace="", from_file=None, secret_type=None, from_env_file=None):
"""Returns YAML for a generic secret
Args:
name: The secret name.
namespace: The namespace.
from_file: Use the from-file secret generator. May be a string or a list of strings.
Example: ["ssh--privatekey=path/to/id_rsa", "ssh-publickey=path/to/id_rsa.pub"]
from_env_file: Specify the path to a file to read lines of key=val pairs to create a secret
(i.e. a Docker .env file)
secret_type (optional): Specify the type of the secret
Example: 'kubernetes.io/dockerconfigjson'
Returns:
The secret YAML as a blob
"""
args = [
"kubectl",
"create",
"secret",
"generic",
name,
]
if namespace:
args.extend(["-n", namespace])
generator = False
if from_file:
if type(from_file) == "string":
args.extend(["--from-file", from_file])
generator = True
elif type(from_file) == "list":
for f in from_file:
args.extend(["--from-file", f])
generator = True
else:
fail("Bad from_file argument: %s" % from_file)
if from_env_file:
if type(from_env_file) != "string":
fail("from_env_file only accepts strings")
args.extend(["--from-env-file", from_env_file])
generator = True
if not generator:
fail("No secret generator specified")
if secret_type:
if type(secret_type) == "string":
args.extend(["--type", secret_type])
else:
fail("Bad secret_type argument: %s" % secret_type)
args.extend(["-o=yaml", "--dry-run=client"])
return local(args)
def secret_from_dict(name, namespace="", inputs={}):
"""Returns YAML for a generic secret
Args:
name: The configmap name.
namespace: The namespace.
inputs: A dict of keys and values to use. Nesting is not supported
Returns:
The secret YAML as a blob
"""
args = [
"kubectl",
"create",
"secret",
"generic",
name,
]
if namespace:
args.extend(["-n", namespace])
if type(inputs) != "dict":
fail("Bad argument to secret_from_dict, inputs was not dict typed")
for k,v in inputs.items():
args.extend(["--from-literal", "%s=%s" % (k,v)])
args.extend(["-o=yaml", "--dry-run=client"])
return local(args, quiet=True)
def secret_create_generic(name, namespace="", from_file=None, secret_type=None, from_env_file=None):
"""Creates a secret in the current Kubernetes cluster.
Args:
name: The secret name.
namespace: The namespace.
from_file: Use the from-file secret generator. May be a string or a list of strings.
Example: ["ssh--privatekey=path/to/id_rsa", "ssh-publickey=path/to/id_rsa.pub"]
from_env_file: Specify the path to a file to read lines of key=val pairs to create a secret
(i.e. a Docker .env file)
secret_type (optional): Specify the type of the secret
Example: 'kubernetes.io/dockerconfigjson'
"""
k8s_yaml(secret_yaml_generic(name, namespace, from_file, secret_type, from_env_file))

View File

@@ -0,0 +1 @@
hostname:5432:database:username:password

View File

@@ -0,0 +1,7 @@
load('../Tiltfile', 'secret_create_generic', 'secret_from_dict')
k8s_yaml(secret_from_dict("secrets", inputs = {
'SOME_TOKEN' : os.getenv('SOME_TOKEN')
}))
secret_create_generic('pgpass', namespace='default', from_file='.pgpass=./.pgpass')
k8s_yaml('job.yaml')

View File

@@ -0,0 +1,33 @@
apiVersion: batch/v1
kind: Job
metadata:
name: secret-verify
spec:
backoffLimit: 1
template:
spec:
containers:
- name: secret-verify-dict
image: alpine
command: [ "/bin/echo", "$(SOME_TOKEN)" ]
env:
- name: TEST_VAR
valueFrom:
secretKeyRef:
name: secrets
key: SOME_TOKEN
- name: secret-verify
image: alpine
command: ["grep", "password", "/var/secrets/pgpass/.pgpass"]
volumeMounts:
- name: pgpass
mountPath: /var/secrets/pgpass
env:
- name: PGPASSFILE
value: /var/secrets/pgpass/.pgpass
restartPolicy: Never
volumes:
- name: pgpass
secret:
secretName: pgpass
defaultMode: 0600

View File

@@ -0,0 +1,9 @@
#!/bin/bash
cd "$(dirname "$0")"
export SOME_TOKEN=abc123
set -ex
tilt ci
tilt down --delete-namespaces