Elrond Smart Contract
Overview
The smart contract in Rust represents the multi-bridge on the Elrond blockchain.
Executing transactions on Elrond
#[elrond_wasm_derive::contract]
pub trait Multisig { ... }
Available transactions
1. Freezing eGLD in Elrond & sending it to a target account on a target blockchain
#[payable("EGLD")]
#[endpoint(freezeSend)]
fn freeze_send(
&self,
#[payment] value: Self::BigUint,
chain_nonce: u64,
to: String
) -> SCResult<Self::BigUint> {
require!(value > 0, "Value must be > 0");
let ident = self.insert_event(EventInfo::new(Event::Transfer {
chain_nonce, to, value }));
Ok(ident)
}
2. Freezing NFT minted in Elrond & sending it to a target account in a target blockchain
#[payable("*")]
#[endpoint(freezeSendNft)]
fn freeze_send_nft(
&self,
#[payment_token] token: TokenIdentifier,
#[payment] value: Self::BigUint,
#[payment_nonce] nonce: u64,
chain_nonce: u64, to: String
) -> SCResult<Self::BigUint> {
require!(nonce > 0, "Not an NFT!");
require!(value == 1, "SFTs not supported!");
let ident = self.insert_event(EventInfo::new(Event::TransferNft {
chain_nonce, to, token, nonce }));
Ok(ident)
}
3. Sending wrapped NFTs to another blockchain
#[payable("*")]
#[endpoint(withdrawNft)]
fn withdraw_nft(
&self,
#[payment_token] token: TokenIdentifier,
#[payment_nonce] nonce: u64,
to: String
) -> SCResult<Self::BigUint> {
require!(token == self.nft_token().get(), "Invalid token!");
require!(nonce > 0, "Not an NFT!");
let sc_addr = self.blockchain().get_sc_address();
let mut dat = self.blockchain().get_esdt_token_data(
&sc_addr,
&token, nonce);
let id = dat.uris.remove(0);
let chain_nonce = u64::top_decode(dat.attributes.into_box()).unwrap();
self.send().esdt_local_burn(&token, nonce, &1u32.into());
let ident = self.insert_event(EventInfo::new(Event::UnfreezeNft {
chain_nonce, to, id }));
Ok(ident)
}
4. Sending wrapped fungible tokens to another blockchain
#[payable("*")]
#[endpoint(withdraw)]
fn withdraw(
&self,
#[payment] value: Self::BigUint,
#[payment_token] token: TokenIdentifier,
#[payment_nonce] chain_nonce: u64, to: String
) -> SCResult<Self::BigUint> {
require!(value > 0, "Value must be > 0");
require!(token == self.token().get(), "Invalid token!");
self.send().esdt_local_burn(&token, chain_nonce, &value);
let ident = self.insert_event(EventInfo::new(Event::Unfreeze {
chain_nonce, to, value }));
Ok(ident)
}
5. Helper function: checks whether a user is a validator
#[view(userRole)]
fn user_role(&self, user: Address) -> UserRole {
let user_id = self.user_mapper().get_user_id(&user);
if user_id == 0 {
UserRole::None
} else {
self.get_user_id_to_role(user_id)
}
}
Validation related actions reside in the validate_action function
fn validate_action(&self, id: Self::BigUint, action: Action<Self::BigUint>) ->
SCResult<PerformActionResult<Self::SendApi>> { ... }
1. The smart contract validates whether a signer has the right to sign & returns an error otherwise.
let caller_address = self.blockchain().get_caller();
let caller_id = self.user_mapper().get_user_id(&caller_address);
let caller_role = self.get_user_id_to_role(caller_id);
require!(
caller_role.can_sign(),
"only board members and proposers can propose"
);
2. Checks that the BFT threshold is reached
if valid_signers_count == min_valid {
let res = self.perform_action(action);
action_mapper.remove(&id).unwrap();
}
3. Subscribes a new validator
#[endpoint(proposeAddValidator)]
fn propose_add_validator(
&self,
uuid: Self::BigUint,
board_member_address: Address
) -> SCResult<PerformActionResult<Self::SendApi>> {
self.validate_action(uuid, Action::AddValidator(board_member_address))
}
4. Unsubscribes a validator
#[endpoint(proposeRemoveUser)]
fn propose_remove_user(
&self, uuid: Self::BigUint,
user_address: Address
) -> SCResult<PerformActionResult<Self::SendApi>> {
self.validate_action(uuid, Action::RemoveUser(user_address))
}
5. Updates the BFT threshold
#[endpoint(proposeChangeMinValid)]
fn propose_change_min_valid(
&self,
uuid: Self::BigUint,
new_quorum: usize
) -> SCResult<PerformActionResult<Self::SendApi>> {
self.validate_action(uuid, Action::ChangeMinValid(new_quorum))
}
6. Provides transaction information for the validator upon request
#[endpoint(eventRead)]
fn event_read(&self, id: Self::BigUint) -> SCResult<EventInfo<Self::BigUint>> {
//... if all checks passed
let info = event_mapper.get(&id);
//... clean & return the info
}
Last updated
Was this helpful?