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: 12 additions & 0 deletions .cargo/audit.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# cargo-audit configuration.
#
# Informational advisories that are accepted and documented. These crates are
# transitive dev-only dependencies of `soroban-sdk`'s `testutils` feature
# (via soroban-env-host), have no maintained successor available, and never
# ship in contract wasm artifacts.

[advisories]
ignore = [
"RUSTSEC-2024-0388", # derivative is unmaintained (test-only transitive dep)
"RUSTSEC-2024-0436", # paste is unmaintained (test-only transitive dep)
]
18 changes: 18 additions & 0 deletions .github/workflows/dependency-vulnerability-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,30 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Check Dependency graph availability
id: graph-check
run: |
set +e
code=$(curl -s -o /dev/null -w '%{http_code}' \
-H "Authorization: Bearer ${{ github.token }}" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${{ github.repository }}/dependency-graph/compare/${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}")
echo "http_code=$code" >> "$GITHUB_OUTPUT"
- name: Block vulnerable dependency changes
if: >
steps.graph-check.outputs.http_code != '403' &&
steps.graph-check.outputs.http_code != '404'
uses: actions/dependency-review-action@v4
with:
fail-on-severity: moderate
deny-licenses: GPL-2.0, GPL-3.0, AGPL-1.0, AGPL-3.0
comment-summary-in-pr: always
- name: Skip dependency review (Dependency graph disabled)
if: >
steps.graph-check.outputs.http_code == '403' ||
steps.graph-check.outputs.http_code == '404'
run: |
echo "::warning::Dependency graph is not enabled on this repository; skipping dependency review. Enable it in Settings -> Code security and analysis -> Dependency graph."

rust-audit:
name: Rust cargo audit
Expand Down
7 changes: 5 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,9 @@ rand = "0.8.6"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
chrono = { version = "0.4", features = ["serde"] }
clap = { version = "4.4", features = ["derive"] }
clap = { version = "4.4", features = ["derive"] }
getrandom = { version = "0.2", features = ["js"] }

[[bin]]
name = "iot-payload-generator"
path = "main.rs"
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Soroban smart contracts for a decentralized utility metering and streaming proto
- **ZK-SNARK Privacy** — Groth16 proofs let meters prove usage without revealing raw readings
- **Firmware Update Gate** — Time-limited, cryptographically signed update authorization
- **Multi-Sig Governance** — 3-of-5 finance wallet quorum for large withdrawals
- **Multi-Signature Treasury Wallet** — Standalone M-of-N wallet (`contracts/treasury-wallet`) for the protocol treasury with signer add/remove, transaction proposal & approval workflow, and time-locked execution for high-value transfers
- **Emergency Response** — Circuit breakers, legal freezes, velocity limits, protocol pauses
- **Dust Sweeper** — Prunes fractional remainders from depleted streams
- **Grant Stream** — Conservation goals trigger automatic grant matching
Expand All @@ -28,7 +29,8 @@ Utility-contracts/
│ │ ├── src/lib.rs # Core implementation
│ │ ├── src/test.rs # Test suite
│ │ └── Cargo.toml
│ └── price_oracle/ # Price oracle contract
│ ├── price_oracle/ # Price oracle contract
│ └── treasury-wallet/ # Multi-signature treasury wallet (M-of-N, timelock)
├── webhook-delivery-service/ # High-performance off-chain Webhook service with retry & SSRF shielding (TS)
├── meter-simulator/ # Device simulator (JS)
├── usage-dashboard/ # Real-time Next.js analytics & Webhook monitor dashboard
Expand Down
15 changes: 11 additions & 4 deletions contracts/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions contracts/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["utility_contracts", "price_oracle", "resource-token", "common", "settlement", "meter-aggregator", "fees", "oracle-aggregator"]
members = ["utility_contracts", "price_oracle", "resource-token", "common", "settlement", "meter-aggregator", "fees", "oracle-aggregator", "treasury-wallet"]

[workspace.dependencies]
soroban-sdk = "23.2.4"
soroban-sdk = { version = "23.2.4", features = ["alloc"] }
15 changes: 15 additions & 0 deletions contracts/treasury-wallet/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[package]
name = "treasury-wallet"
version = "0.0.0"
edition = "2021"
publish = false

[lib]
crate-type = ["lib", "cdylib"]
doctest = false

[dependencies]
soroban-sdk = { workspace = true }

[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
125 changes: 125 additions & 0 deletions contracts/treasury-wallet/src/events.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//! Typed contract events published by the treasury wallet.
//!
//! Defined with the modern `#[contractevent]` macro so the events are included
//! in the contract's interface specification and usable by indexers, SDKs, and
//! generated clients. Static topics are kept short (≤ 10 bytes) so they remain
//! inline "short" symbols.

use soroban_sdk::{contractevent, Address};

/// Emitted when the wallet is initialized.
#[contractevent(topics = ["init"])]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Initialized {
/// Address authorized to manage signers and thresholds.
pub owner: Address,
/// Number of approvals required to execute a transaction.
pub required_signatures: u32,
/// Amounts at or above this value are time-locked.
pub high_value_threshold: i128,
/// Delay applied to high-value transactions.
pub timelock_seconds: u64,
/// Proposal validity window.
pub expiry_seconds: u64,
}

/// Emitted when a signer is added.
#[contractevent(topics = ["signer_add"])]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SignerAdded {
/// The signer that was added (dynamic topic).
#[topic]
pub signer: Address,
}

/// Emitted when a signer is removed.
#[contractevent(topics = ["signer_rm"])]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct SignerRemoved {
/// The signer that was removed (dynamic topic).
#[topic]
pub signer: Address,
}

/// Emitted when the wallet configuration is updated.
#[contractevent(topics = ["cfg_upd"])]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ConfigUpdated {
/// New number of approvals required to execute a transaction.
pub required_signatures: u32,
/// New high-value threshold.
pub high_value_threshold: i128,
/// New timelock duration.
pub timelock_seconds: u64,
/// New proposal expiry window.
pub expiry_seconds: u64,
}

/// Emitted when a transaction is proposed.
#[contractevent(topics = ["propose"])]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TransactionProposed {
/// The proposal id (dynamic topic).
#[topic]
pub proposal_id: u64,
/// Token to transfer.
pub token: Address,
/// Recipient of the transfer.
pub to: Address,
/// Amount to transfer.
pub amount: i128,
/// Signer that submitted the proposal.
pub proposer: Address,
}

/// Emitted when a transaction is approved.
#[contractevent(topics = ["approve"])]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TransactionApproved {
/// The proposal id (dynamic topic).
#[topic]
pub proposal_id: u64,
/// The signer that approved (dynamic topic).
#[topic]
pub approver: Address,
/// Current approval count.
pub approval_count: u32,
}

/// Emitted when an approval is revoked.
#[contractevent(topics = ["revoke"])]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ApprovalRevoked {
/// The proposal id (dynamic topic).
#[topic]
pub proposal_id: u64,
/// The signer that revoked (dynamic topic).
#[topic]
pub revoker: Address,
/// Current approval count after the revocation.
pub approval_count: u32,
}

/// Emitted when an approved transaction is executed.
#[contractevent(topics = ["execute"])]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TransactionExecuted {
/// The proposal id (dynamic topic).
#[topic]
pub proposal_id: u64,
/// Token that was transferred.
pub token: Address,
/// Recipient that received the funds.
pub to: Address,
/// Amount transferred.
pub amount: i128,
}

/// Emitted when a pending transaction is cancelled.
#[contractevent(topics = ["cancel"])]
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct TransactionCancelled {
/// The proposal id (dynamic topic).
#[topic]
pub proposal_id: u64,
}
Loading
Loading