Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions .git-hooks/local-pre-push

This file was deleted.

6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
target/
.anchor/
node_modules/
test-ledger/
*.so
.DS_Store
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,7 @@ Configuration is primarily handled via `Anchor.toml` and environment variables.

* **`Anchor.toml`**: Specifies program IDs for different clusters (`localnet`, `devnet`), default provider settings (cluster URL, wallet), and script commands.
* **Environment Variables**:
* `SOLANA_CLI_VERSION`: Not directly used, but `flake.nix` pins specific versions.
* `SOLANA_CLI_VERSION`: Not directly used, but `bootstrap.sh` and `flake.nix` pin specific versions.
* `ANCHOR_VERSION`: Managed by `avm` for cross-version compatibility.

## Development
Expand Down
23 changes: 16 additions & 7 deletions bootstrap.sh
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
#!/usr/bin/env sh
#!/usr/bin/env bash

# Copyright 2026 ResQ
# SPDX-License-Identifier: Apache-2.0
#
# Canonical onboarding — delegates to resq-software/dev.
# See https://github.com/resq-software/dev for the full installer.
set -eu
export REPO=programs
exec sh -c "$(curl -fsSL https://raw.githubusercontent.com/resq-software/dev/main/install.sh)"
# 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.

set -euo pipefail
exec "$(dirname "$0")/scripts/setup.sh" "$@"
96 changes: 0 additions & 96 deletions flake.lock

This file was deleted.

2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
description = "ResQ Programs — Solana Anchor on-chain programs (airspace, delivery)";

inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
nixpkgs.url = "github:nixos/nixpkgs/nixos-24.11";
flake-utils.url = "github:numtide/flake-utils";
rust-overlay.url = "github:oxalica/rust-overlay";
};
Expand Down
2 changes: 1 addition & 1 deletion resq-airspace/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,4 @@ pub enum AirspaceError {
/// drone_pda is the zero address; no key can sign as the default pubkey.
#[msg("Drone PDA must not be the zero address")]
InvalidDronePda,
}
}
7 changes: 5 additions & 2 deletions resq-airspace/src/instructions/grant_permit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ pub struct GrantPermit<'info> {
/// * `drone_pda` – the drone's Program-Derived Address
/// * `expires_at` – Unix timestamp when the permit expires (0 = never)
pub fn handler(ctx: Context<GrantPermit>, drone_pda: Pubkey, expires_at: i64) -> Result<()> {
require!(drone_pda != Pubkey::default(), AirspaceError::InvalidDronePda);
require!(
drone_pda != Pubkey::default(),
AirspaceError::InvalidDronePda
);
let clock = Clock::get()?;
require!(
expires_at == 0 || expires_at > clock.unix_timestamp,
Expand Down Expand Up @@ -87,4 +90,4 @@ pub struct PermitGranted {
pub airspace_pda: Pubkey,
pub drone_pda: Pubkey,
pub expires_at: i64,
}
}
10 changes: 7 additions & 3 deletions resq-airspace/src/instructions/initialize_property.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ pub struct InitializeProperty<'info> {
/// * `policy` – `AccessPolicy` enum value
/// * `fee_lamports` – per-crossing fee (0 = free)
/// * `treasury` – SOL account that receives crossing fees
#[allow(clippy::too_many_arguments)]
pub fn handler(
ctx: Context<InitializeProperty>,
property_id: [u8; 32],
Expand All @@ -66,10 +67,13 @@ pub fn handler(
require!(property_id != [0u8; 32], AirspaceError::EmptyPropertyId);
require!(min_alt_m < max_alt_m, AirspaceError::InvalidAltitudeBounds);
require!(
vertex_count >= 1 && vertex_count <= 8,
(1..=8).contains(&vertex_count),
AirspaceError::InvalidVertexCount
);
require!(treasury != Pubkey::default(), AirspaceError::InvalidTreasury);
require!(
treasury != Pubkey::default(),
AirspaceError::InvalidTreasury
);

let airspace_pda = ctx.accounts.airspace.key();
let owner_key = ctx.accounts.owner.key();
Expand Down Expand Up @@ -101,4 +105,4 @@ pub struct PropertyInitialized {
pub airspace_pda: Pubkey,
pub owner: Pubkey,
pub property_id: [u8; 32],
}
}
15 changes: 9 additions & 6 deletions resq-airspace/src/instructions/record_crossing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,11 @@ pub struct RecordCrossing<'info> {
/// - `Deny` – always rejected.
///
/// # Arguments
/// * `lat` – latitude × 1e7 (range 900_000_000 to +900_000_000)
/// * `lon` – longitude × 1e7 (range 1_800_000_000 to +1_800_000_000)
/// * `lat` – latitude × 1e7 (range -900_000_000 to +900_000_000)
/// * `lon` – longitude × 1e7 (range -1_800_000_000 to +1_800_000_000)
/// * `alt_m` – altitude in metres (enforced against airspace altitude bounds)
/// * `crossed_at` – Unix timestamp (seconds) of the crossing; must be within the
/// 5-minute look-back window and no more than 60 seconds ahead
/// 5-minute look-back window and no more than 60 seconds ahead
pub fn handler(
ctx: Context<RecordCrossing>,
lat: i64,
Expand Down Expand Up @@ -95,11 +95,11 @@ pub fn handler(

// Coordinate range validation (mirrors record_delivery).
require!(
lat >= -900_000_000 && lat <= 900_000_000,
(-900_000_000..=900_000_000).contains(&lat),
AirspaceError::LatitudeOutOfRange
);
require!(
lon >= -1_800_000_000 && lon <= 1_800_000_000,
(-1_800_000_000..=1_800_000_000).contains(&lon),
AirspaceError::LongitudeOutOfRange
);

Expand All @@ -123,7 +123,10 @@ pub fn handler(
.permit
.as_ref()
.ok_or(AirspaceError::NoValidPermit)?;
require!(permit.is_active(clock.unix_timestamp), AirspaceError::PermitExpired);
require!(
permit.is_active(clock.unix_timestamp),
AirspaceError::PermitExpired
);

// Collect per-crossing fee when configured.
if airspace.fee_lamports > 0 {
Expand Down
8 changes: 2 additions & 6 deletions resq-airspace/src/instructions/update_policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@ pub struct UpdatePolicy<'info> {
/// Update the access policy and/or per-crossing fee for an airspace.
///
/// Only the registered owner may call this instruction.
pub fn handler(
ctx: Context<UpdatePolicy>,
policy: AccessPolicy,
fee_lamports: u64,
) -> Result<()> {
pub fn handler(ctx: Context<UpdatePolicy>, policy: AccessPolicy, fee_lamports: u64) -> Result<()> {
let airspace = &mut ctx.accounts.airspace;
airspace.policy = policy;
airspace.fee_lamports = fee_lamports;
Expand All @@ -61,4 +57,4 @@ pub struct PolicyUpdated {
pub airspace_pda: Pubkey,
pub policy: AccessPolicy,
pub fee_lamports: u64,
}
}
5 changes: 4 additions & 1 deletion resq-airspace/src/instructions/update_treasury.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ pub struct UpdateTreasury<'info> {
/// # Arguments
/// * `treasury` – new SOL account that will receive crossing fees
pub fn handler(ctx: Context<UpdateTreasury>, treasury: Pubkey) -> Result<()> {
require!(treasury != Pubkey::default(), AirspaceError::InvalidTreasury);
require!(
treasury != Pubkey::default(),
AirspaceError::InvalidTreasury
);
ctx.accounts.airspace.treasury = treasury;

emit!(TreasuryUpdated {
Expand Down
11 changes: 6 additions & 5 deletions resq-airspace/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
#![allow(unexpected_cfgs)]
#![allow(
unexpected_cfgs,
clippy::too_many_arguments,
clippy::diverging_sub_expression
)]

/*
* Copyright 2026 ResQ
Expand Down Expand Up @@ -102,10 +106,7 @@ pub mod resq_airspace {
///
/// This is the only recovery path when the owner key is compromised or
/// needs to be rotated. After this call the old owner has no authority.
pub fn transfer_ownership(
ctx: Context<TransferOwnership>,
new_owner: Pubkey,
) -> Result<()> {
pub fn transfer_ownership(ctx: Context<TransferOwnership>, new_owner: Pubkey) -> Result<()> {
instructions::transfer_ownership::handler(ctx, new_owner)
}
}
11 changes: 3 additions & 8 deletions resq-airspace/src/state/airspace_account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
use anchor_lang::prelude::*;

/// Access policy for an airspace envelope.
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, PartialEq, Eq, Debug)]
#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, PartialEq, Eq, Debug, Default)]
pub enum AccessPolicy {
/// Any drone may transit without a permit or fee.
#[default]
Open = 0,
/// A drone must hold a valid `Permit` account to transit.
Permit = 1,
Expand All @@ -29,12 +30,6 @@ pub enum AccessPolicy {
Auction = 3,
}

impl Default for AccessPolicy {
fn default() -> Self {
AccessPolicy::Open
}
}

/// Per-property 3D airspace envelope registered on-chain.
///
/// PDA seeds: `["airspace", property_id_bytes]`
Expand Down Expand Up @@ -82,4 +77,4 @@ pub struct AirspaceAccount {
impl AirspaceAccount {
/// Account size in bytes (discriminator + fields).
pub const LEN: usize = 8 + 32 + 32 + 4 + 4 + 128 + 1 + 1 + 8 + 32 + 1;
}
}
2 changes: 1 addition & 1 deletion resq-airspace/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
*/

pub mod airspace_account;
pub mod permit;
pub mod permit;
2 changes: 1 addition & 1 deletion resq-airspace/src/state/permit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,4 +53,4 @@ impl Permit {
pub fn is_active(&self, now: i64) -> bool {
self.expires_at == 0 || self.expires_at > now
}
}
}
Loading
Loading