-
Notifications
You must be signed in to change notification settings - Fork 62
Implement submit_proof endpoint #132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
33143be
164c91b
5bf6e24
2e40147
b6e12f7
4a03a9a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| use soroban_sdk::contracterror; | ||
|
|
||
| #[contracterror] | ||
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||
| pub enum ContractError { | ||
| AlreadyInitialized = 1, | ||
| NotInitialized = 2, | ||
| RootMismatch = 3, | ||
| InvalidProof = 4, | ||
| DuplicateCommitment = 5, | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,5 +1,9 @@ | ||||||||||||||||||||||||||||||||||
| #![no_std] | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| mod errors; | ||||||||||||||||||||||||||||||||||
| mod events; | ||||||||||||||||||||||||||||||||||
| mod storage; | ||||||||||||||||||||||||||||||||||
| mod types; | ||||||||||||||||||||||||||||||||||
| pub mod events; | ||||||||||||||||||||||||||||||||||
| pub mod types; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
@@ -8,30 +12,56 @@ use soroban_sdk::{ | |||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||
| use types::ResolveData; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| #[contract] | ||||||||||||||||||||||||||||||||||
| pub struct Contract; | ||||||||||||||||||||||||||||||||||
| #[cfg(test)] | ||||||||||||||||||||||||||||||||||
| mod test; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| #[contracttype] | ||||||||||||||||||||||||||||||||||
| #[derive(Clone)] | ||||||||||||||||||||||||||||||||||
| pub enum DataKey { | ||||||||||||||||||||||||||||||||||
| Resolver(BytesN<32>), | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| use soroban_sdk::{contract, contractclient, contractimpl, panic_with_error, Address, BytesN, Env}; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| pub use crate::errors::ContractError; | ||||||||||||||||||||||||||||||||||
| pub use crate::events::UsernameRegistered; | ||||||||||||||||||||||||||||||||||
| pub use crate::types::{Proof, PublicSignals}; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| #[contract] | ||||||||||||||||||||||||||||||||||
| pub struct CoreContract; | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| #[contractclient(name = "VerifierContractClient")] | ||||||||||||||||||||||||||||||||||
| pub trait VerifierContract { | ||||||||||||||||||||||||||||||||||
| fn verify_proof(env: Env, proof: Proof, public_signals: PublicSignals) -> bool; | ||||||||||||||||||||||||||||||||||
| #[contracterror] | ||||||||||||||||||||||||||||||||||
| #[derive(Copy, Clone, Debug, Eq, PartialEq)] | ||||||||||||||||||||||||||||||||||
| pub enum ResolverError { | ||||||||||||||||||||||||||||||||||
| NotFound = 1, | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| #[contractimpl] | ||||||||||||||||||||||||||||||||||
| impl Contract { | ||||||||||||||||||||||||||||||||||
| pub fn register_resolver(env: Env, commitment: BytesN<32>, wallet: Address, memo: Option<u64>) { | ||||||||||||||||||||||||||||||||||
| let key = DataKey::Resolver(commitment); | ||||||||||||||||||||||||||||||||||
| let data = ResolveData { wallet, memo }; | ||||||||||||||||||||||||||||||||||
| impl CoreContract { | ||||||||||||||||||||||||||||||||||
| pub fn init(env: Env, verifier: Address, root: BytesN<32>) { | ||||||||||||||||||||||||||||||||||
| if storage::is_initialized(&env) { | ||||||||||||||||||||||||||||||||||
| panic_with_error!(&env, ContractError::AlreadyInitialized); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| env.storage().persistent().set(&key, &data); | ||||||||||||||||||||||||||||||||||
| storage::set_verifier(&env, &verifier); | ||||||||||||||||||||||||||||||||||
| storage::set_root(&env, &root); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+27
to
+33
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Gate The first caller permanently chooses 🔐 Possible fix- pub fn init(env: Env, verifier: Address, root: BytesN<32>) {
+ pub fn init(env: Env, admin: Address, verifier: Address, root: BytesN<32>) {
+ admin.require_auth();
if storage::is_initialized(&env) {
panic_with_error!(&env, ContractError::AlreadyInitialized);
}📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| pub fn submit_proof(env: Env, proof: Proof, public_signals: PublicSignals) { | ||||||||||||||||||||||||||||||||||
| let current_root = storage::get_root(&env) | ||||||||||||||||||||||||||||||||||
| .unwrap_or_else(|| panic_with_error!(&env, ContractError::NotInitialized)); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if current_root != public_signals.old_root.clone() { | ||||||||||||||||||||||||||||||||||
| panic_with_error!(&env, ContractError::RootMismatch); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| if storage::has_commitment(&env, &public_signals.commitment) { | ||||||||||||||||||||||||||||||||||
| panic_with_error!(&env, ContractError::DuplicateCommitment); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+40
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Once the first submission updates the root, replaying the same proof fails at 🔁 If duplicate should win, swap the checks- if current_root != public_signals.old_root.clone() {
- panic_with_error!(&env, ContractError::RootMismatch);
- }
-
if storage::has_commitment(&env, &public_signals.commitment) {
panic_with_error!(&env, ContractError::DuplicateCommitment);
}
+
+ if current_root != public_signals.old_root.clone() {
+ panic_with_error!(&env, ContractError::RootMismatch);
+ }🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| let verifier = storage::get_verifier(&env) | ||||||||||||||||||||||||||||||||||
| .unwrap_or_else(|| panic_with_error!(&env, ContractError::NotInitialized)); | ||||||||||||||||||||||||||||||||||
| let verifier_client = VerifierContractClient::new(&env, &verifier); | ||||||||||||||||||||||||||||||||||
| let is_valid = verifier_client.verify_proof(&proof, &public_signals); | ||||||||||||||||||||||||||||||||||
| if !is_valid { | ||||||||||||||||||||||||||||||||||
| panic_with_error!(&env, ContractError::InvalidProof); | ||||||||||||||||||||||||||||||||||
|
Comment on lines
+48
to
+53
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: fd -t f "lib.rs" gateway-contractRepository: Alien-Protocol/Alien-Gateway Length of output: 287 🏁 Script executed: wc -l gateway-contract/contracts/core_contract/src/lib.rsRepository: Alien-Protocol/Alien-Gateway Length of output: 126 🏁 Script executed: head -80 gateway-contract/contracts/core_contract/src/lib.rs | cat -nRepository: Alien-Protocol/Alien-Gateway Length of output: 3082 🏁 Script executed: rg "ContractError" gateway-contract/contracts/core_contract/src/lib.rs -A 2 -B 2Repository: Alien-Protocol/Alien-Gateway Length of output: 1402 🏁 Script executed: rg "enum ContractError" gateway-contract -A 20Repository: Alien-Protocol/Alien-Gateway Length of output: 608 🏁 Script executed: rg "verify_proof" gateway-contract -B 5 -A 5Repository: Alien-Protocol/Alien-Gateway Length of output: 2986 🏁 Script executed: rg "VerifierContractClient" gateway-contract -B 2 -A 2Repository: Alien-Protocol/Alien-Gateway Length of output: 2096 🌐 Web query:
💡 Result: In Soroban Rust, generated What
|
||||||||||||||||||||||||||||||||||
| pub fn set_memo(env: Env, commitment: BytesN<32>, memo_id: u64) { | ||||||||||||||||||||||||||||||||||
| let key = DataKey::Resolver(commitment); | ||||||||||||||||||||||||||||||||||
| let mut data = env | ||||||||||||||||||||||||||||||||||
|
|
@@ -51,6 +81,26 @@ impl Contract { | |||||||||||||||||||||||||||||||||
| Some(data) => (data.wallet, data.memo), | ||||||||||||||||||||||||||||||||||
| None => panic_with_error!(&env, ResolverError::NotFound), | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| storage::store_commitment(&env, &public_signals.commitment); | ||||||||||||||||||||||||||||||||||
| storage::set_root(&env, &public_signals.new_root); | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| UsernameRegistered { | ||||||||||||||||||||||||||||||||||
| commitment: public_signals.commitment, | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| .publish(&env); | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| pub fn get_root(env: Env) -> Option<BytesN<32>> { | ||||||||||||||||||||||||||||||||||
| storage::get_root(&env) | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| pub fn get_verifier(env: Env) -> Option<Address> { | ||||||||||||||||||||||||||||||||||
| storage::get_verifier(&env) | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| pub fn has_commitment(env: Env, commitment: BytesN<32>) -> bool { | ||||||||||||||||||||||||||||||||||
| storage::has_commitment(&env, &commitment) | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| use soroban_sdk::{contracttype, Address, BytesN, Env}; | ||
|
|
||
| #[contracttype] | ||
| #[derive(Clone)] | ||
| pub enum DataKey { | ||
| Root, | ||
| Verifier, | ||
| Commitment(BytesN<32>), | ||
| } | ||
|
|
||
| pub fn is_initialized(env: &Env) -> bool { | ||
| env.storage().instance().has(&DataKey::Root) && env.storage().instance().has(&DataKey::Verifier) | ||
| } | ||
|
|
||
| pub fn get_root(env: &Env) -> Option<BytesN<32>> { | ||
| env.storage().instance().get(&DataKey::Root) | ||
| } | ||
|
|
||
| pub fn set_root(env: &Env, root: &BytesN<32>) { | ||
| env.storage().instance().set(&DataKey::Root, root); | ||
| } | ||
|
|
||
| pub fn get_verifier(env: &Env) -> Option<Address> { | ||
| env.storage().instance().get(&DataKey::Verifier) | ||
| } | ||
|
|
||
| pub fn set_verifier(env: &Env, verifier: &Address) { | ||
| env.storage().instance().set(&DataKey::Verifier, verifier); | ||
| } | ||
|
|
||
| pub fn has_commitment(env: &Env, commitment: &BytesN<32>) -> bool { | ||
| env.storage() | ||
| .persistent() | ||
| .has(&DataKey::Commitment(commitment.clone())) | ||
| } | ||
|
|
||
| pub fn store_commitment(env: &Env, commitment: &BytesN<32>) { | ||
| env.storage() | ||
| .persistent() | ||
| .set(&DataKey::Commitment(commitment.clone()), &true); | ||
|
Comment on lines
+15
to
+40
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n gateway-contract/contracts/core_contract/src/storage.rsRepository: Alien-Protocol/Alien-Gateway Length of output: 1439 🏁 Script executed: rg "extend_ttl|TTL|ttl" gateway-contract/contracts/core_contract/src/ -iRepository: Alien-Protocol/Alien-Gateway Length of output: 54 🏁 Script executed: find gateway-contract/contracts/core_contract/src -name "*.rs" -type fRepository: Alien-Protocol/Alien-Gateway Length of output: 514 🏁 Script executed: cat -n gateway-contract/contracts/core_contract/src/lib.rsRepository: Alien-Protocol/Alien-Gateway Length of output: 3091 🌐 Web query:
💡 Result: Instance storage TTL extension (contract instance)
Persistent storage TTL extension (per key)
Extending TTL from outside the contract (transaction operation)
Sources: [1] Stellar Docs – Smart contract state archival; [2] Extend TTL for long-lived storage entries to prevent state expiry. Instance storage (Root and Verifier) and persistent storage (Commitments) require explicit TTL extension on Soroban—without it, these entries will expire and be archived. This breaks contract initialization state (Root and Verifier queries will fail) and disables duplicate protection (commitments can be replayed after archival). Add 🤖 Prompt for AI Agents |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicate imports causing compile errors.
Line 16 re-imports symbols already imported in lines 9-11. The pipeline reports E0252 for each duplicate. Consolidate into a single import statement and add only the missing
contractclient.🐛 Proposed fix — single consolidated import
Combined with the earlier fix (removing lines 9-11), this becomes the sole import.
🧰 Tools
🪛 GitHub Actions: Smart Contracts CI
[error] 16-16: Rust compile error E0252: the macro name
contractis defined/imported multiple times. Compiler suggests removing the unnecessary import.[error] 16-16: Rust compile error E0252: the macro name
contractimplis defined/imported multiple times. Compiler suggests removing the unnecessary import.[error] 16-16: Rust compile error E0252: the macro name
panic_with_erroris defined/imported multiple times. Compiler suggests removing the unnecessary import.[error] 16-16: Rust compile error E0252: the type name
Addressis defined/imported multiple times. Compiler suggests removing the unnecessary import.[error] 16-16: Rust compile error E0252: the type name
BytesNis defined/imported multiple times. Compiler suggests removing the unnecessary import.[error] 16-16: Rust compile error E0252: the type name
Envis defined/imported multiple times. Compiler suggests removing the unnecessary import.[warning] 16-16: Rust warning: unused imports
contract,contractimpl,panic_with_error,Address,BytesN, andEnv(#[warn(unused_imports)]).🤖 Prompt for AI Agents