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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 8 additions & 0 deletions .deployment.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[INFO] Deployment script started
[INFO] Network: testnet
[INFO] Validate after deploy: true
[INFO] Continuous validation: true
[INFO] Validating environment...
[✗] Invalid validation interval: abc
[INFO] Interval must be a positive integer (seconds).
[✗] Environment validation failed
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@

.env.local
.env
node_modulessanc/
**/node_modules/
30 changes: 30 additions & 0 deletions .validation.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[✗] Required tool not found: soroban
[INFO] Please install soroban to proceed.
[✗] Required tool not found: soroban
[INFO] Please install soroban to proceed.
[✗] Required tool not found: soroban
[INFO] Please install soroban to proceed.
[✗] Required tool not found: soroban
[INFO] Please install soroban to proceed.
[✗] Required tool not found: soroban
[INFO] Please install soroban to proceed.
[✗] Required tool not found: soroban
[INFO] Please install soroban to proceed.
[✗] Contract ID is required
[INFO] Specify with --contract-id C...
[✗] Invalid Contract ID format: invalid
[INFO] Contract IDs should start with 'C' and be 56 characters long.
[✗] Invalid Contract ID format: CAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
[INFO] Contract IDs should start with 'C' and be 56 characters long.
[✗] Contract ID is required
[INFO] Specify with --contract-id C...
[✗] Invalid Contract ID format: invalid
[INFO] Contract IDs should start with 'C' and be 56 characters long.
[✗] Invalid SOROBAN_SECRET_KEY format
[INFO] Secret keys should start with 'S' and be 56 characters long.
[✗] Contract ID is required
[INFO] Specify with --contract-id C...
[✗] Invalid Contract ID format: invalid
[INFO] Contract IDs should start with 'C' and be 56 characters long.
[✗] Invalid SOROBAN_SECRET_KEY format
[INFO] Secret keys should start with 'S' and be 56 characters long.
28 changes: 28 additions & 0 deletions Cargo.lock

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

26 changes: 13 additions & 13 deletions contracts/benchmark/src/budgets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,19 @@
///
/// Limits are intentionally conservative; tighten them as contracts mature.
pub const WASM_SIZE_BUDGETS: &[(&str, u64)] = &[
("amm-pool", 65_536), // 64 KiB — complex AMM logic
("flashloan-token", 32_768), // 32 KiB
("governance-contract", 65_536), // 64 KiB — proposal + voting state
("kani-poc-contract", 16_384), // 16 KiB — minimal proof-of-concept
("multisig-wallet", 65_536), // 64 KiB
("my-contract", 32_768), // 32 KiB — SEP-41 token
("uups-proxy", 32_768), // 32 KiB
("reentrancy-guard", 16_384), // 16 KiB — guard only
("runtime-guard-wrapper", 65_536), // 64 KiB
("timelock", 32_768), // 32 KiB
("token-with-bugs", 32_768), // 32 KiB
("vesting-contract", 32_768), // 32 KiB
("vulnerable-contract", 32_768), // 32 KiB
("amm-pool", 65_536), // 64 KiB — complex AMM logic
("flashloan-token", 32_768), // 32 KiB
("governance-contract", 65_536), // 64 KiB — proposal + voting state
("kani-poc-contract", 16_384), // 16 KiB — minimal proof-of-concept
("multisig-wallet", 65_536), // 64 KiB
("my-contract", 32_768), // 32 KiB — SEP-41 token
("uups-proxy", 32_768), // 32 KiB
("reentrancy-guard", 16_384), // 16 KiB — guard only
("runtime-guard-wrapper", 65_536), // 64 KiB
("timelock", 32_768), // 32 KiB
("token-with-bugs", 32_768), // 32 KiB
("vesting-contract", 32_768), // 32 KiB
("vulnerable-contract", 32_768), // 32 KiB
];

// ---------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion contracts/benchmark/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ mod tests {
let env = Env::default();
let (client, _) = setup(&env);
let alice = Address::generate(&env);
client.mint(&alice, &i128::MAX / 2);
client.mint(&alice, &(i128::MAX / 2));
}

// -----------------------------------------------------------------------
Expand Down
11 changes: 10 additions & 1 deletion contracts/benchmark/src/vesting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,16 @@ mod tests {
let client = VestingContractClient::new(env, &id);

// start=100, cliff=200, duration=1000 (simple round numbers)
client.init(&admin, &beneficiary, &token_id, &100u64, &200u64, &1000u64, &total, &true);
client.init(
&admin,
&beneficiary,
&token_id,
&100u64,
&200u64,
&1000u64,
&total,
&true,
);
(client, admin, beneficiary)
}

Expand Down
2 changes: 2 additions & 0 deletions contracts/vesting/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@ crate-type = ["cdylib", "rlib"]
[dependencies]
soroban-sdk = { workspace = true }

[dev-dependencies]
soroban-sdk = { workspace = true, features = ["testutils"] }
146 changes: 135 additions & 11 deletions contracts/vesting/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,157 @@
#![no_std]

use soroban_sdk::{contract, contractimpl, Address, Env};
use soroban_sdk::{contract, contracterror, contractimpl, contracttype, token, Address, Env};

#[contracterror]
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum VestingError {
AlreadyInitialized = 1,
NotRevocable = 2,
AlreadyRevoked = 3,
NoVestedTokens = 4,
}

#[contract]
pub struct VestingContract;

#[contracttype]
#[derive(Clone)]
pub enum DataKey {
Admin,
Beneficiary,
Token,
Start,
Cliff,
Duration,
TotalAmount,
Released,
Revocable,
RevokedAt,
}

#[contractimpl]
impl VestingContract {
/// Create a new vesting schedule.
#[allow(unused_variables)]
pub fn create_vesting(
pub fn init(
env: Env,
admin: Address,
beneficiary: Address,
token: Address,
start: u64,
cliff: u64,
duration: u64,
amount: i128,
start_time: u64,
end_time: u64,
revocable: bool,
) {
// Implementation here
if env.storage().instance().has(&DataKey::Admin) {
env.panic_with_error(VestingError::AlreadyInitialized);
}
env.storage().instance().set(&DataKey::Admin, &admin);
env.storage()
.instance()
.set(&DataKey::Beneficiary, &beneficiary);
env.storage().instance().set(&DataKey::Token, &token);
env.storage().instance().set(&DataKey::Start, &start);
env.storage().instance().set(&DataKey::Cliff, &cliff);
env.storage().instance().set(&DataKey::Duration, &duration);
env.storage().instance().set(&DataKey::TotalAmount, &amount);
env.storage().instance().set(&DataKey::Released, &0i128);
env.storage()
.instance()
.set(&DataKey::Revocable, &revocable);
}

/// Returns the total amount vested based on current time.
pub fn vested_amount(env: Env) -> i128 {
let start: u64 = env.storage().instance().get(&DataKey::Start).unwrap();
let cliff: u64 = env.storage().instance().get(&DataKey::Cliff).unwrap();
let duration: u64 = env.storage().instance().get(&DataKey::Duration).unwrap();
let total_amount: i128 = env.storage().instance().get(&DataKey::TotalAmount).unwrap();
let revoked_at: Option<u64> = env.storage().instance().get(&DataKey::RevokedAt);

let current_time = if let Some(revoked_at) = revoked_at {
revoked_at
} else {
env.ledger().timestamp()
};

if current_time < start + cliff {
return 0;
}

if current_time >= start + duration {
return total_amount;
}

total_amount * (current_time - start) as i128 / duration as i128
}

/// Returns the amount currently available to be claimed.
pub fn claimable_amount(env: Env) -> i128 {
let vested = Self::vested_amount(env.clone());
let released: i128 = env
.storage()
.instance()
.get(&DataKey::Released)
.unwrap_or(0);
vested - released
}

/// Claim tokens from vesting schedule.
#[allow(unused_variables)]
pub fn claim(env: Env) {
// Implementation here
pub fn claim(env: Env) -> i128 {
let beneficiary: Address = env.storage().instance().get(&DataKey::Beneficiary).unwrap();
beneficiary.require_auth();

let claimable = Self::claimable_amount(env.clone());
if claimable <= 0 {
env.panic_with_error(VestingError::NoVestedTokens);
}

let token_id: Address = env.storage().instance().get(&DataKey::Token).unwrap();
let released: i128 = env
.storage()
.instance()
.get(&DataKey::Released)
.unwrap_or(0);

env.storage()
.instance()
.set(&DataKey::Released, &(released + claimable));

let token_client = token::TokenClient::new(&env, &token_id);
token_client.transfer(&env.current_contract_address(), &beneficiary, &claimable);

claimable
}

/// Revoke the vesting schedule.
#[allow(unused_variables)]
pub fn revoke(env: Env) {
// Implementation here
let admin: Address = env.storage().instance().get(&DataKey::Admin).unwrap();
admin.require_auth();

let revocable: bool = env.storage().instance().get(&DataKey::Revocable).unwrap();
if !revocable {
env.panic_with_error(VestingError::NotRevocable);
}

if env.storage().instance().has(&DataKey::RevokedAt) {
env.panic_with_error(VestingError::AlreadyRevoked);
}

let current_time = env.ledger().timestamp();
env.storage()
.instance()
.set(&DataKey::RevokedAt, &current_time);

let token_id: Address = env.storage().instance().get(&DataKey::Token).unwrap();
let total_amount: i128 = env.storage().instance().get(&DataKey::TotalAmount).unwrap();
let vested = Self::vested_amount(env.clone());

let unvested = total_amount - vested;

if unvested > 0 {
let token_client = token::TokenClient::new(&env, &token_id);
token_client.transfer(&env.current_contract_address(), &admin, &unvested);
}
}
}
30 changes: 24 additions & 6 deletions docs/ci-cd-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,15 @@ Enable via GitHub Settings:

## Troubleshooting

### Issue: "Invalid SOROBAN_SECRET_KEY format"

**Solution:**
Secret keys must start with 'S' and be exactly 56 characters long.
```bash
# Correct format example
export SOROBAN_SECRET_KEY=SBXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

### Issue: "Secret SOROBAN_SECRET_KEY not available"

**Solution:**
Expand All @@ -368,14 +377,14 @@ gh secret set SOROBAN_SECRET_KEY --body "SBXXXXXXX..."
gh workflow run soroban-deploy.yml
```

### Issue: "Workflow failed: Soroban binary not found"
### Issue: "Workflow failed: Soroban binary not found" (or other tool missing)

**Solution:**
The workflow automatically installs Soroban. If it fails:

1. Check network connectivity in workflow logs
2. Try manual dispatch with retry
3. File an issue if persists
The scripts now validate that all required tools (`cargo`, `soroban`, `jq`, `curl`) are installed.
1. If running locally, install the missing tool.
2. In GitHub Actions, the workflow automatically installs Soroban. If it fails:
- Check network connectivity in workflow logs
- Try manual dispatch with retry

### Issue: "Deployment successful but validation failed"

Expand All @@ -395,6 +404,15 @@ soroban network info --network testnet

3. Wait for contract to finalize on network

### Issue: "Invalid Contract ID format"

**Solution:**
Contract IDs must start with 'C' and be exactly 56 characters long.
```bash
# Correct format example
./scripts/validate-runtime-guards.sh --contract-id CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

### Issue: "Cannot access secrets in local run"

**Solution:**
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/api/ai/explain/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub enum DataKey {
};

return NextResponse.json(result);
} catch (err) {
} catch (_err) {
return NextResponse.json({ error: "Internal server error" }, { status: 500 });
}
}
Loading
Loading