Quay is an open source, high performance backend for the Seaport smart contracts. The project is implemented in Rust, using Postgres as a storage backend, with the aim of allowing a proliferation of signature based trading platforms for ERC-721s and ERC-1155s based on the Seaport smart contract interface.
main.rs
contains the main
function, which is called when the crate's
binary is executed. That in turn calls startup.rs
. That creates the
application, attaches the services, routes, database connection pool, and
rpc connection context used by the endpoints.
Routes and services are defined in /routes
using actix-web
macros.
telemetry.rs
and startup.rs
set up a tracing framework that provides rich
logs for runtime telemetry and development debugging. These tracing logs are
then extended via macros on routes.
Example:
#[post("/offers")]
#[tracing::instrument(
name = "Adding a new offer",
skip(offer, pool, seaport),
fields(
offerer = %offer.parameters.offerer,
)
)]
async fn create_offer(
offer: web::Json<Order>,
pool: web::Data<PgPool>,
seaport: web::Data<Seaport<Provider<ethers::providers::Http>>>,
) -> HttpResponse {
if insert_offer(&pool, &offer, &seaport).await.is_err() {
return HttpResponse::InternalServerError().finish();
}
HttpResponse::Ok().finish()
}
This project supports EIP-4361 (Sign in with Ethereum) authentication. See
src/routes/sessions.rs
for implementation details.
Redis is used for SIWE session storage.
The database schema and queries are written in SQL and managed with sqlx
. The
schemas live in migrations/
, and the database queries are inline where used
on the objects (SQL speaking objects). The database connection is handled in a
connection pool at application startup.
When new queries are added, run DATABASE_URL=postgres://postgres:password@localhost:5432/quay cargo sqlx prepare -- --lib
to generate new query definitions for the macro expansion used by sqlx.
Database schema migrations are performed out of band with sqlx-cli. All database migrations should be tested locally, and applied in a non-breaking fashion. What this means, ideally, is that there is a migration to add new functionality, then a rollout of the new backend version, then another migration to delete any legacy schema after roll out.
sqlx migrate add '<MIGRATION_NAME>'
;- Write all necesarry queries in
migrations/<MIGRATION_NAME>
; - Apply for local db (if it's required for testing):
sqlx migrate run
;
Blockchain interactions happen via RPC using the ethers-rs
library. This project
contains type safe bindings for the seaport (seaport.rs
) and conduit controller
(conduit_controller.rs
) contracts, which have been extended with other
functionality, and will eventually include functions for serializing to and
from postgres. The rpc connection is handled by a wrapped reference counter
at application startup.
Developers will need rust and docker to work on this project. Docker is used
to host a local instance of the postgres database to execute tests against.
To set up a local database, run: ./scripts/init_db.sh
and ./scripts/init_redis.sh
Run cargo build
to build the project. indexer.dockerfile
and api.dockerfile
are useful for generating docker images for use in production or testing.
Tests live in the /tests
folder.
Run cargo test
any time after setting up your development environment.
CI/CD is implemented using GitHub actions, the scripting is in
.github/workflows
. There are certain actions which run on open
pull requests, and deploy actions, which run only after passing
tests on master
.
This project uses clippy
, tarpaulin
, and a number of other crates
to provide end-to-end tests, unit tests, formatting, linting, and static
analysis to enforce code quality. These tests are then run in an automated
fashion using GitHub actions.
This project supports deployment to Digital Ocean via spec.yaml