-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
274 additions
and
89 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
use super::state::{Contributor, BOUNTY_STATE}; | ||
|
||
pub fn accept_impl(contributor: Contributor) -> () { | ||
BOUNTY_STATE.with(|state| { | ||
if let Some(ref mut bounty_canister) = *state.borrow_mut() { | ||
// Add the contributor to the interested contributors list | ||
bounty_canister.interested_contributors.push(contributor); | ||
} | ||
}); | ||
} | ||
|
||
#[cfg(test)] | ||
mod test_accept { | ||
use super::*; | ||
use candid::Principal; | ||
use crate::api::init::init_impl; | ||
|
||
#[test] | ||
fn test_accept() { | ||
let authority = | ||
Principal::from_text("t2y5w-qp34w-qixaj-s67wp-syrei-5yqse-xbed6-z5nsd-fszmf-izgt2-lqe") | ||
.unwrap(); | ||
init_impl(authority, 123); | ||
BOUNTY_STATE.with(|state| { | ||
let bounty_canister = state.borrow(); | ||
if let Some(ref bounty_canister) = *bounty_canister { | ||
assert_eq!(bounty_canister.interested_contributors.len(), 0); | ||
} else { | ||
panic!("Bounty canister state not initialized"); | ||
} | ||
}); | ||
let contributor = | ||
Principal::from_text("t2y5w-qp34w-qixaj-s67wp-syrei-5yqse-xbed6-z5nsd-fszmf-izgt2-lqe") | ||
.unwrap(); | ||
accept_impl(Contributor { | ||
address: contributor, | ||
crypto_address: "contributor_address".to_string(), | ||
}); | ||
BOUNTY_STATE.with(|state| { | ||
let bounty_canister = state.borrow(); | ||
if let Some(ref bounty_canister) = *bounty_canister { | ||
assert_eq!(bounty_canister.interested_contributors.len(), 1); | ||
} else { | ||
panic!("Bounty canister state not initialized"); | ||
} | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
use ic_cdk::api::{caller, id}; | ||
|
||
use super::*; | ||
|
||
use icrc1::{ICRC1, MAINNET_ICRC1_LEDGER_CANISTER_ID}; | ||
|
||
use candid::{CandidType, Nat, Principal}; | ||
|
||
#[derive(CandidType)] | ||
pub enum DepositErr { | ||
TransferFailure, | ||
} | ||
|
||
pub type DepositReceipt = Result<Nat, DepositErr>; | ||
|
||
pub async fn deposit_impl() -> DepositReceipt { | ||
// FIXME check caller equals the owner who initialized the bounty. | ||
let caller = caller(); | ||
let icrc1_ledger_canister_id = | ||
Principal::from_text(MAINNET_ICRC1_LEDGER_CANISTER_ID).unwrap(); | ||
|
||
let amount = deposit_icrc1(caller, icrc1_ledger_canister_id).await?; | ||
return DepositReceipt::Ok(amount); | ||
} | ||
|
||
async fn deposit_icrc1( | ||
caller: Principal, | ||
icrc1_token_canister_id: Principal | ||
) -> Result<Nat, DepositErr> { | ||
let icrc1_token = ICRC1::new(icrc1_token_canister_id); | ||
let icrc1_token_fee = icrc1_token.get_metadata().await.fee; | ||
|
||
// depends on: | ||
// dfx canister call icrc1_ledger_canister icrc2_approve "(record { amount = 100_000; spender = record{owner = principal \"SPENDER_PRINCIPAL\";} })" | ||
let allowance = icrc1_token.allowance(caller, id()).await; | ||
|
||
let available = allowance - icrc1_token_fee; | ||
|
||
icrc1_token | ||
.transfer_from(caller, id(), available.to_owned()) | ||
.await | ||
.map_err(|_| DepositErr::TransferFailure)?; | ||
|
||
Ok(available) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
use candid::{CandidType, Deserialize, Nat, Principal}; | ||
use ic_cdk::api::call::call; | ||
|
||
pub struct ICRC1 { | ||
principal: Principal, | ||
} | ||
|
||
#[derive(CandidType, Debug, PartialEq, Deserialize)] | ||
pub enum TxError { | ||
InsufficientBalance, | ||
InsufficientAllowance, | ||
Unauthorized, | ||
LedgerTrap, | ||
AmountTooSmall, | ||
BlockUsed, | ||
ErrorOperationStyle, | ||
ErrorTo, | ||
Other, | ||
} | ||
pub type TxReceipt = Result<Nat, TxError>; | ||
|
||
#[allow(non_snake_case)] | ||
#[derive(CandidType, Clone, Debug, Deserialize)] | ||
pub struct Metadata { | ||
pub logo: String, | ||
pub name: String, | ||
pub symbol: String, | ||
pub decimals: u8, | ||
pub totalSupply: Nat, | ||
pub owner: Principal, | ||
pub fee: Nat, | ||
} | ||
|
||
// pub const ICRC1_FEE: u64 = 10_000; | ||
pub const MAINNET_ICRC1_LEDGER_CANISTER_ID: &str = "mxzaz-hqaaa-aaaar-qaada-cai"; | ||
|
||
impl ICRC1 { | ||
pub fn new(principal: Principal) -> Self { | ||
ICRC1 { principal } | ||
} | ||
|
||
// pub async fn transfer(&self, target: Principal, amount: Nat) -> TxReceipt { | ||
// let call_result: Result<(TxReceipt,), _> = | ||
// call(self.principal, "icrc1_transfer", (target, amount)).await; | ||
|
||
// call_result.unwrap().0 | ||
// } | ||
|
||
pub async fn transfer_from( | ||
&self, | ||
source: Principal, | ||
target: Principal, | ||
amount: Nat, | ||
) -> TxReceipt { | ||
let call_result: Result<(TxReceipt,), _> = | ||
call(self.principal, "icrc2_transfer_from", (source, target, amount)).await; | ||
|
||
call_result.unwrap().0 | ||
} | ||
|
||
pub async fn allowance(&self, owner: Principal, spender: Principal) -> Nat { | ||
let call_result: Result<(Nat,), _> = | ||
call(self.principal, "icrc2_allowance", (owner, spender)).await; | ||
|
||
call_result.unwrap().0 | ||
} | ||
|
||
pub async fn get_metadata(&self) -> Metadata { | ||
let call_result: Result<(Metadata,), _> = | ||
call(self.principal, "icrc1_metadata", ()).await; | ||
|
||
call_result.unwrap().0 | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
use candid::Principal; | ||
use super::state::{BountyState, BOUNTY_STATE}; | ||
|
||
pub fn init_impl(authority: Principal, github_issue_id: i32) -> () { | ||
BOUNTY_STATE.with(|state| { | ||
*state.borrow_mut() = Some(BountyState { | ||
authority, | ||
github_issue_id, | ||
interested_contributors: Vec::new(), | ||
claimed: false | ||
}); | ||
}); | ||
} | ||
|
||
#[cfg(test)] | ||
mod test_init { | ||
use super::*; | ||
|
||
#[test] | ||
fn test_init() { | ||
BOUNTY_STATE.with(|state| { | ||
let bounty_canister = state.borrow(); | ||
assert!(bounty_canister.is_none()); | ||
}); | ||
|
||
let authority = | ||
Principal::from_text("t2y5w-qp34w-qixaj-s67wp-syrei-5yqse-xbed6-z5nsd-fszmf-izgt2-lqe") | ||
.unwrap(); | ||
|
||
init_impl(authority, 123); | ||
BOUNTY_STATE.with(|state| { | ||
let bounty_canister = state.borrow(); | ||
assert!(bounty_canister.is_some()); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
|
||
use candid::{CandidType, Principal}; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Debug, Serialize, Deserialize, CandidType)] | ||
pub struct BountyState { | ||
pub authority: Principal, | ||
pub github_issue_id: i32, | ||
pub interested_contributors: Vec<Contributor>, | ||
pub claimed: bool | ||
} | ||
|
||
#[derive(Debug, Serialize, Deserialize, CandidType)] | ||
pub struct Contributor { | ||
pub address: Principal, | ||
pub crypto_address: String, | ||
} | ||
|
||
// Define thread-local storage for the bounty canister state | ||
thread_local! { | ||
pub static BOUNTY_STATE: std::cell::RefCell<Option<BountyState>> = std::cell::RefCell::new(None); | ||
} |
Oops, something went wrong.