Blockchain interaction with Proxy Contract
Overview​
The Calimero proxy contract enables cross-chain interactions through a proposal-based system. The integration consists of:
- Backend Application (Rust)
- Frontend Application (TypeScript/React)
tip
More info on blockchain integrations can be found in the Blockchains Integration section.
Backend Implementation​
The backend contract handles proposal creation and management. Here's the core functionality:
#[app::logic]
impl AppState {
pub fn create_new_proposal(&mut self, request: CreateProposalRequest) -> Result<ProposalId, Error> {
// Implementation handles different types of proposals:
// 1. ExternalFunctionCall
// 2. Transfer
// 3. SetContextValue
// 4. SetNumApprovals
// 5. SetActiveProposalsLimit
}
pub fn approve_proposal(&self, proposal_id: ProposalId) -> Result<(), Error> {
Self::external().approve(proposal_id);
env::emit(&Event::ApprovedProposal { id: proposal_id });
Ok(())
}
}
API Types​
Define your types for the integration:
// types.ts
export enum ProposalActionType {
ExternalFunctionCall = 'ExternalFunctionCall',
Transfer = 'Transfer',
SetNumApprovals = 'SetNumApprovals',
SetActiveProposalsLimit = 'SetActiveProposalsLimit',
SetContextValue = 'SetContextValue',
}
export interface CreateProposalRequest {
action_type: ProposalActionType;
params: {
receiver_id?: string;
method_name?: string;
args?: string;
deposit?: string;
gas?: string;
amount?: string;
num_approvals?: number;
active_proposals_limit?: number;
key?: string;
value?: string;
};
}
API Implementation​
Create a data source to handle API calls:
// LogicApiDataSource.ts
export class LogicApiDataSource implements ClientApi {
async createProposal(
request: CreateProposalRequest,
): ApiResponse<CreateProposalResponse> {
const params: RpcQueryParams<typeof request> = {
contextId: getContextId(),
method: ClientMethod.CREATE_PROPOSAL,
argsJson: { request },
executorPublicKey: jwtObject.executor_public_key,
};
return await getJsonRpcClient().execute(params, config);
}
async approveProposal(
request: ApproveProposalRequest,
): ApiResponse<ApproveProposalResponse> {
// Implementation
}
}
Creating Proposals​
Here are examples of creating different types of proposals:
1. External Function Call​
const request: CreateProposalRequest = {
action_type: 'ExternalFunctionCall',
params: {
receiver_id: 'contract.near',
method_name: 'transfer',
args: JSON.stringify({ amount: '100' }),
deposit: '1000000000000000000000', // 1 NEAR
gas: '30000000000000', // 30 TGas
},
};
2. Token Transfer​
const request: CreateProposalRequest = {
action_type: 'Transfer',
params: {
receiver_id: 'recipient.near',
amount: '1000000000000000000000', // 1 NEAR
},
};
3. Set Context Value​
const request: CreateProposalRequest = {
action_type: 'SetContextValue',
params: {
key: 'my_key',
value: 'my_value',
},
};
4. Set Number of Approvals​
const request: CreateProposalRequest = {
action_type: 'SetNumApprovals',
params: {
num_approvals: 3,
},
};
5. Set Active Proposals Limit​
const request: CreateProposalRequest = {
action_type: 'SetActiveProposalsLimit',
params: {
active_proposals_limit: 10,
},
};
Approving Proposals​
To approve a proposal:
const approvalRequest: ApproveProposalRequest = {
proposal_id: 'proposal-id-here',
};
await logicApiDataSource.approveProposal(approvalRequest);
Error Handling​
The implementation includes comprehensive error handling:
try {
const result = await logicApiDataSource.createProposal(request);
if (result?.error) {
console.error('Error:', result.error);
// Handle error appropriately
}
} catch (error) {
console.error('Unexpected error:', error);
// Handle unexpected errors
}
Best Practices​
-
Input Validation
- Validate all parameters before sending
- Use appropriate types for amounts (strings for large numbers)
- Format JSON strings properly
-
Error Handling
- Implement proper error handling
- Log important operations
- Handle all possible error cases
-
Gas Management
- Use appropriate gas limits
- Default to 30 TGas for NEAR
- Monitor gas usage
Was this page helpful?