194 lines
9.0 KiB
SQL
194 lines
9.0 KiB
SQL
create table if not exists root_key_history (
|
|
id INTEGER not null PRIMARY KEY,
|
|
-- root key stored as aead encrypted artifact, with only difference that it's decrypted by unseal key (derived from user password)
|
|
root_key_encryption_nonce blob not null default(1), -- if re-encrypted, this should be incremented. Used for encrypting root key
|
|
data_encryption_nonce blob not null default(1), -- nonce used for encrypting with key itself
|
|
ciphertext blob not null,
|
|
tag blob not null,
|
|
schema_version integer not null default(1), -- server would need to reencrypt, because this means that we have changed algorithm
|
|
salt blob not null -- for key deriviation
|
|
) STRICT;
|
|
|
|
create table if not exists aead_encrypted (
|
|
id INTEGER not null PRIMARY KEY,
|
|
current_nonce blob not null default(1), -- if re-encrypted, this should be incremented
|
|
ciphertext blob not null,
|
|
tag blob not null,
|
|
schema_version integer not null default(1), -- server would need to reencrypt, because this means that we have changed algorithm
|
|
associated_root_key_id integer not null references root_key_history (id) on delete RESTRICT,
|
|
created_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
|
|
create unique index if not exists uniq_nonce_per_root_key on aead_encrypted (
|
|
current_nonce,
|
|
associated_root_key_id
|
|
);
|
|
|
|
create table if not exists tls_history (
|
|
id INTEGER not null PRIMARY KEY,
|
|
cert text not null,
|
|
cert_key text not null, -- PEM Encoded private key
|
|
ca_cert text not null,
|
|
ca_key text not null, -- PEM Encoded private key
|
|
created_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
|
|
-- This is a singleton
|
|
create table if not exists arbiter_settings (
|
|
id INTEGER not null PRIMARY KEY CHECK (id = 1), -- singleton row, id must be 1
|
|
root_key_id integer references root_key_history (id) on delete RESTRICT, -- if null, means wasn't bootstrapped yet
|
|
tls_id integer references tls_history (id) on delete RESTRICT
|
|
) STRICT;
|
|
|
|
insert into arbiter_settings (id) values (1) on conflict do nothing;
|
|
-- ensure singleton row exists
|
|
|
|
create table if not exists useragent_client (
|
|
id integer not null primary key,
|
|
nonce integer not null default(1), -- used for auth challenge
|
|
public_key blob not null,
|
|
key_type integer not null default(1), -- 1=Ed25519, 2=ECDSA(secp256k1)
|
|
created_at integer not null default(unixepoch ('now')),
|
|
updated_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
create unique index if not exists uniq_useragent_client_public_key on useragent_client (public_key, key_type);
|
|
|
|
create table if not exists client_metadata (
|
|
id integer not null primary key,
|
|
name text not null, -- human-readable name for the client
|
|
description text, -- optional description for the client
|
|
version text, -- client version for tracking and debugging
|
|
created_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
|
|
-- created to track history of changes
|
|
create table if not exists client_metadata_history (
|
|
id integer not null primary key,
|
|
metadata_id integer not null references client_metadata (id) on delete cascade,
|
|
client_id integer not null references program_client (id) on delete cascade,
|
|
created_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
|
|
create unique index if not exists uniq_metadata_binding_client on client_metadata_history (client_id);
|
|
|
|
create table if not exists program_client (
|
|
id integer not null primary key,
|
|
nonce integer not null default(1), -- used for auth challenge
|
|
public_key blob not null,
|
|
metadata_id integer not null references client_metadata (id) on delete cascade,
|
|
created_at integer not null default(unixepoch ('now')),
|
|
updated_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
|
|
create unique index if not exists program_client_public_key_unique
|
|
on program_client (public_key);
|
|
|
|
create unique index if not exists uniq_program_client_public_key on program_client (public_key);
|
|
|
|
create table if not exists evm_wallet (
|
|
id integer not null primary key,
|
|
address blob not null, -- 20-byte Ethereum address
|
|
aead_encrypted_id integer not null references aead_encrypted (id) on delete RESTRICT,
|
|
created_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
|
|
create unique index if not exists uniq_evm_wallet_address on evm_wallet (address);
|
|
|
|
create unique index if not exists uniq_evm_wallet_aead on evm_wallet (aead_encrypted_id);
|
|
|
|
create table if not exists evm_wallet_access (
|
|
id integer not null primary key,
|
|
wallet_id integer not null references evm_wallet (id) on delete cascade,
|
|
client_id integer not null references program_client (id) on delete cascade,
|
|
created_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
|
|
create unique index if not exists uniq_wallet_access on evm_wallet_access (wallet_id, client_id);
|
|
|
|
create table if not exists evm_ether_transfer_limit (
|
|
id integer not null primary key,
|
|
window_secs integer not null, -- window duration in seconds
|
|
max_volume blob not null -- big-endian 32-byte U256
|
|
) STRICT;
|
|
|
|
-- Shared grant properties: client scope, timeframe, fee caps, and rate limit
|
|
create table if not exists evm_basic_grant (
|
|
id integer not null primary key,
|
|
wallet_access_id integer not null references evm_wallet_access (id) on delete restrict,
|
|
chain_id integer not null, -- EIP-155 chain ID
|
|
valid_from integer, -- unix timestamp (seconds), null = no lower bound
|
|
valid_until integer, -- unix timestamp (seconds), null = no upper bound
|
|
max_gas_fee_per_gas blob, -- big-endian 32-byte U256, null = unlimited
|
|
max_priority_fee_per_gas blob, -- big-endian 32-byte U256, null = unlimited
|
|
rate_limit_count integer, -- max transactions in window, null = unlimited
|
|
rate_limit_window_secs integer, -- window duration in seconds, null = unlimited
|
|
revoked_at integer, -- unix timestamp when revoked, null = still active
|
|
created_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
|
|
-- Shared transaction log for all EVM grants, used for rate limit tracking and auditing
|
|
create table if not exists evm_transaction_log (
|
|
id integer not null primary key,
|
|
wallet_access_id integer not null references evm_wallet_access (id) on delete restrict,
|
|
grant_id integer not null references evm_basic_grant (id) on delete restrict,
|
|
chain_id integer not null,
|
|
eth_value blob not null, -- always present on any EVM tx
|
|
signed_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
|
|
create index if not exists idx_evm_basic_grant_access_chain on evm_basic_grant (wallet_access_id, chain_id);
|
|
|
|
-- ===============================
|
|
-- ERC20 token transfer grant
|
|
-- ===============================
|
|
create table if not exists evm_token_transfer_grant (
|
|
id integer not null primary key,
|
|
basic_grant_id integer not null unique references evm_basic_grant (id) on delete cascade,
|
|
token_contract blob not null, -- 20-byte ERC20 contract address
|
|
receiver blob -- 20-byte recipient address or null if every recipient allowed
|
|
) STRICT;
|
|
|
|
-- Per-window volume limits for token transfer grants
|
|
create table if not exists evm_token_transfer_volume_limit (
|
|
id integer not null primary key,
|
|
grant_id integer not null references evm_token_transfer_grant (id) on delete cascade,
|
|
window_secs integer not null, -- window duration in seconds
|
|
max_volume blob not null -- big-endian 32-byte U256
|
|
) STRICT;
|
|
|
|
-- Log table for token transfer grant usage
|
|
create table if not exists evm_token_transfer_log (
|
|
id integer not null primary key,
|
|
grant_id integer not null references evm_token_transfer_grant (id) on delete restrict,
|
|
log_id integer not null references evm_transaction_log (id) on delete restrict,
|
|
chain_id integer not null, -- EIP-155 chain ID
|
|
token_contract blob not null, -- 20-byte ERC20 contract address
|
|
recipient_address blob not null, -- 20-byte recipient address
|
|
value blob not null, -- big-endian 32-byte U256
|
|
created_at integer not null default(unixepoch ('now'))
|
|
) STRICT;
|
|
|
|
create index if not exists idx_token_transfer_log_grant on evm_token_transfer_log (grant_id);
|
|
|
|
create index if not exists idx_token_transfer_log_log_id on evm_token_transfer_log (log_id);
|
|
|
|
create index if not exists idx_token_transfer_log_chain on evm_token_transfer_log (chain_id);
|
|
|
|
-- ===============================
|
|
-- Ether transfer grant (uses base log)
|
|
-- ===============================
|
|
create table if not exists evm_ether_transfer_grant (
|
|
id integer not null primary key,
|
|
basic_grant_id integer not null unique references evm_basic_grant (id) on delete cascade,
|
|
limit_id integer not null references evm_ether_transfer_limit (id) on delete restrict
|
|
) STRICT;
|
|
|
|
-- Specific recipient addresses for an ether transfer grant
|
|
create table if not exists evm_ether_transfer_grant_target (
|
|
id integer not null primary key,
|
|
grant_id integer not null references evm_ether_transfer_grant (id) on delete cascade,
|
|
address blob not null -- 20-byte recipient address
|
|
) STRICT;
|
|
|
|
create unique index if not exists uniq_ether_transfer_target on evm_ether_transfer_grant_target (grant_id, address);
|