Skip to content
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

Fix update proxy contracts with delete #1012

Merged
merged 7 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 3 additions & 3 deletions contracts/icp/context-config/.env
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# DFX CANISTER ENVIRONMENT VARIABLES
DFX_VERSION='0.24.2'
DFX_NETWORK='local'
CANISTER_ID_CONTEXT_CONTRACT='bw4dl-smaaa-aaaaa-qaacq-cai'
CANISTER_ID='bw4dl-smaaa-aaaaa-qaacq-cai'
CANISTER_CANDID_PATH='/Users/alen/www/calimero/core/contracts/icp/context-config/context_contract.did'
CANISTER_ID_CONTEXT_CONTRACT='bkyz2-fmaaa-aaaaa-qaaaq-cai'
CANISTER_ID='bkyz2-fmaaa-aaaaa-qaaaq-cai'
CANISTER_CANDID_PATH='/Users/alen/www/calimero/core/contracts/icp/context-config/./res/calimero_context_config_icp.did'
# END DFX CANISTER ENVIRONMENT VARIABLES
Empty file modified contracts/icp/context-config/deploy_devnet.sh
100644 → 100755
Empty file.
6 changes: 3 additions & 3 deletions contracts/icp/context-proxy/dfx.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
{
"canisters": {
"proxy_contract": {
"package": "calimero_context_proxy_icp",
"package": "calimero-context-proxy-icp",
"candid": "./res/calimero_context_proxy_icp.did",
"type": "rust"
},
"mock_ledger": {
"type": "rust",
"package": "mock_ledger",
"package": "calimero-mock-ledger-icp",
"candid": "./mock/ledger/res/calimero_mock_ledger_icp.did",
"path": "mock/ledger"
},
"mock_external": {
"type": "rust",
"package": "mock_external",
"package": "calimero-mock-external-icp",
"candid": "./mock/external/res/calimero_mock_external_icp.did",
"path": "mock/external"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ type ICProposalAction = variant {
SetNumApprovals : record { num_approvals : nat32 };
SetContextValue : record { key : blob; value : blob };
Transfer : record { receiver_id : principal; amount : nat };
DeleteProposal : record { proposal_id : blob };
SetActiveProposalsLimit : record { active_proposals_limit : nat32 };
ExternalFunctionCall : record {
receiver_id : principal;
Expand Down Expand Up @@ -35,8 +36,8 @@ service : (blob, principal) -> {
get_proposal_approvals_with_signer : (blob) -> (
vec ICProposalApprovalWithSigner,
) query;
get_proposal_approvers : (blob) -> (opt vec blob) query;
mutate : (ICSigned) -> (Result);
proposal : (blob) -> (opt ICProposal) query;
proposal_approvers : (blob) -> (opt vec blob) query;
proposals : (nat64, nat64) -> (vec ICProposal) query;
}
36 changes: 35 additions & 1 deletion contracts/icp/context-proxy/src/mutate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,32 @@ async fn execute_proposal(proposal_id: &ProposalId) -> Result<(), String> {
receiver_id,
method_name,
args,
deposit: _,
deposit,
} => {
// If there's a deposit, transfer it first
if deposit > 0 {
let ledger_id = with_state(|contract| contract.ledger_id.clone());

let transfer_args = TransferArgs {
memo: Memo(0),
amount: Tokens::from_e8s(
deposit
.try_into()
.map_err(|e| format!("Amount conversion error: {}", e))?,
),
fee: Tokens::from_e8s(10_000), // Standard fee is 0.0001 ICP
from_subaccount: None,
to: AccountIdentifier::new(&receiver_id, &Subaccount([0; 32])),
created_at_time: None,
};

let _: (Result<u64, TransferError>,) =
ic_cdk::call(Principal::from(ledger_id), "transfer", (transfer_args,))
.await
.map_err(|e| format!("Transfer failed: {:?}", e))?;
}

// Then make the actual cross-contract call
let args_bytes = candid::encode_one(args)
.map_err(|e| format!("Failed to encode args: {}", e))?;

Expand Down Expand Up @@ -137,6 +161,7 @@ async fn execute_proposal(proposal_id: &ProposalId) -> Result<(), String> {
contract.context_storage.insert(key, value);
});
}
ICProposalAction::DeleteProposal { proposal_id: _ } => {}
}
}

Expand All @@ -155,6 +180,14 @@ async fn internal_create_proposal(
return Err("proposal cannot have empty actions".to_string());
}

// Check if the proposal contains a delete action
for action in &proposal.actions {
if let ICProposalAction::DeleteProposal { proposal_id } = action {
remove_proposal(proposal_id);
return Ok(None);
}
}

with_state_mut(|contract| {
let num_proposals = contract
.num_proposals_pk
Expand Down Expand Up @@ -223,6 +256,7 @@ fn validate_proposal_action(action: &ICProposalAction) -> Result<(), String> {
}
}
ICProposalAction::SetContextValue { .. } => {}
ICProposalAction::DeleteProposal { .. } => {}
}
Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion contracts/icp/context-proxy/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub fn get_confirmations_count(proposal_id: ICRepr<ProposalId>) -> Option<ICProp
}

#[ic_cdk::query]
pub fn get_proposal_approvers(proposal_id: ICRepr<ProposalId>) -> Option<Vec<ICRepr<SignerId>>> {
pub fn proposal_approvers(proposal_id: ICRepr<ProposalId>) -> Option<Vec<ICRepr<SignerId>>> {
with_state(|contract| {
contract
.approvals
Expand Down
9 changes: 8 additions & 1 deletion contracts/near/context-proxy/src/mutate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,18 @@ impl ProxyContract {
}

impl ProxyContract {
fn propose(&self, proposal: Proposal) -> Promise {
fn propose(&mut self, proposal: Proposal) -> Promise {
require!(
!self.proposals.contains_key(&proposal.id),
"Proposal already exists"
);

// If this is a delete proposal, execute it immediately
if let Some(ProposalAction::DeleteProposal { proposal_id: _ }) = proposal.actions.first() {
self.remove_proposal(proposal.id);
return Promise::new(env::current_account_id());
}

let author_id = proposal.author_id;
let num_proposals = self.num_proposals_pk.get(&author_id).unwrap_or(&0) + 1;
assert!(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ impl Method<Icp> for ActiveProposalRequest {
}

fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
let value = Decode!(&response, Self::Returns)?;
Ok(value)
let value = Decode!(&response, u32)?;
alenmestrov marked this conversation as resolved.
Show resolved Hide resolved
Ok(value as u16)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,15 +104,17 @@ impl Method<Icp> for ProposalApproversRequest {
}

fn decode(response: Vec<u8>) -> eyre::Result<Self::Returns> {
let identities = Decode!(&response, Vec<ICRepr<ContextIdentity>>)?;
let identities = Decode!(&response, Option<Vec<ICRepr<ContextIdentity>>>)?;

// safety: `ICRepr<T>` is a transparent wrapper around `T`
#[expect(
clippy::transmute_undefined_repr,
reason = "ICRepr<T> is a transparent wrapper around T"
)]
let identities = unsafe {
mem::transmute::<Vec<ICRepr<ContextIdentity>>, Vec<ContextIdentity>>(identities)
mem::transmute::<Vec<ICRepr<ContextIdentity>>, Vec<ContextIdentity>>(
identities.expect("error unwrapping identities"),
alenmestrov marked this conversation as resolved.
Show resolved Hide resolved
)
};

Ok(identities)
Expand Down
9 changes: 9 additions & 0 deletions crates/context/config/src/client/env/proxy/types/starknet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ pub enum StarknetProposalActionWithArgs {
SetNumApprovals(Felt),
SetActiveProposalsLimit(Felt),
SetContextValue(Vec<Felt>, Vec<Felt>),
DeleteProposal(StarknetProposalId),
}

#[derive(Debug, Encode, Decode)]
Expand Down Expand Up @@ -278,6 +279,9 @@ impl From<Vec<ProposalAction>> for StarknetProposalActionWithArgs {
value.chunks(16).map(Felt::from_bytes_be_slice).collect(),
)
}
ProposalAction::DeleteProposal { proposal_id } => {
StarknetProposalActionWithArgs::DeleteProposal(proposal_id.into())
}
}
}
}
Expand Down Expand Up @@ -327,6 +331,11 @@ impl From<StarknetProposalActionWithArgs> for ProposalAction {
value: value.iter().flat_map(|felt| felt.to_bytes_be()).collect(),
}
}
StarknetProposalActionWithArgs::DeleteProposal(proposal_id) => {
ProposalAction::DeleteProposal {
proposal_id: Repr::new(proposal_id.into()),
}
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/context/config/src/client/protocol/starknet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -278,8 +278,8 @@ impl Network {
Ok(chain_id) => chain_id,
Err(e) => {
return Err(StarknetError::Custom {
operation: ErrorOperation::Query,
reason: e.to_string(),
operation: ErrorOperation::Mutate,
reason: format!("Failed to get chain ID: {:#}", e),
})
}
};
Expand Down
9 changes: 9 additions & 0 deletions crates/context/config/src/icp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ pub enum ICProposalAction {
key: Vec<u8>,
value: Vec<u8>,
},
DeleteProposal {
proposal_id: ICRepr<ProposalId>,
},
}

impl TryFrom<ProposalAction> for ICProposalAction {
Expand Down Expand Up @@ -74,6 +77,9 @@ impl TryFrom<ProposalAction> for ICProposalAction {
key: key.into(),
value: value.into(),
},
ProposalAction::DeleteProposal { proposal_id } => ICProposalAction::DeleteProposal {
proposal_id: proposal_id.rt().map_err(|e| e.to_string())?,
},
};

Ok(action)
Expand Down Expand Up @@ -114,6 +120,9 @@ impl From<ICProposalAction> for ProposalAction {
key: key.into_boxed_slice(),
value: value.into_boxed_slice(),
},
ICProposalAction::DeleteProposal { proposal_id } => ProposalAction::DeleteProposal {
proposal_id: proposal_id.rt().expect("infallible conversion"),
},
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/context/config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,9 @@ pub enum ProposalAction {
key: Box<[u8]>,
value: Box<[u8]>,
},
DeleteProposal {
proposal_id: Repr<ProposalId>,
},
}

// The proposal the user makes specifying the receiving account and actions they want to execute (1 tx)
Expand Down
14 changes: 14 additions & 0 deletions crates/sdk/src/env/ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ pub enum ProposalAction {
/// The value to set.
value: Box<[u8]>,
},

/// Delete a proposal.
DeleteProposal {
/// The ID of the proposal to delete.
proposal_id: ProposalId,
},
}

/// Unique identifier for an account.
Expand Down Expand Up @@ -147,6 +153,14 @@ impl DraftProposal {
self
}

/// Add an action to delete a proposal.
#[must_use]
pub fn delete_proposal(mut self, proposal_id: ProposalId) -> Self {
alenmestrov marked this conversation as resolved.
Show resolved Hide resolved
self.actions
.push(ProposalAction::DeleteProposal { proposal_id });
self
}

/// Finalise the proposal and send it to the blockchain.
#[must_use]
pub fn send(self) -> ProposalId {
Expand Down
Loading