Writing Contracts
Overview
To write a contract:
- Import aztec.nr and declare your contract
use dep::aztec::macros::aztec;
#[aztec]
pub contract EasyPrivateVoting {
- Define imports in your contract block
use dep::aztec::{
keys::getters::get_public_keys,
macros::{functions::{initializer, internal, private, public, utility}, storage::storage},
};
use dep::aztec::prelude::{AztecAddress, Map, PublicImmutable, PublicMutable};
use dep::aztec::protocol_types::traits::{Hash, ToField};
Source code: noir-projects/noir-contracts/contracts/app/easy_private_voting_contract/src/main.nr#L8-L16
- Declare your contract storage below your imports
#[storage]
struct Storage<Context> {
admin: PublicMutable<AztecAddress, Context>, // admin can end vote
tally: Map<Field, PublicMutable<Field, Context>, Context>, // we will store candidate as key and number of votes as value
vote_ended: PublicMutable<bool, Context>, // vote_ended is boolean
active_at_block: PublicImmutable<u32, Context>, // when people can start voting
}
Source code: noir-projects/noir-contracts/contracts/app/easy_private_voting_contract/src/main.nr#L17-L25
- Declare a constructor with
#[initializer]
. Constructors can be private or public functions.
#[public]
#[initializer]
// annotation to mark function as a constructor
fn constructor(admin: AztecAddress) {
storage.admin.write(admin);
storage.vote_ended.write(false);
storage.active_at_block.initialize(context.block_number());
}
Source code: noir-projects/noir-contracts/contracts/app/easy_private_voting_contract/src/main.nr#L27-L36
- Declare your contract functions
#[private]
// annotation to mark function as private and expose private context
fn cast_vote(candidate: Field) {
let msg_sender_npk_m_hash = get_public_keys(context.msg_sender()).npk_m.hash();
let secret = context.request_nsk_app(msg_sender_npk_m_hash); // get secret key of caller of function
let nullifier = std::hash::pedersen_hash([context.msg_sender().to_field(), secret]); // derive nullifier from sender and secret
context.push_nullifier(nullifier);
EasyPrivateVoting::at(context.this_address()).add_to_tally_public(candidate).enqueue(
&mut context,
);
}
Source code: noir-projects/noir-contracts/contracts/app/easy_private_voting_contract/src/main.nr#L38-L51
There is a lot more detail and nuance to writing contracts, but this should give you a good starting point. Read contents of this section for more details about authorizing contract to act on your behalf (authenticaion witnesses), emitting events, calling functions on other contracts and other common patterns.
Section Contents
📄️ Defining Initializer Functions
Learn how to write and use initializer functions in your Aztec smart contracts.
🗃️ Declaring Storage
2 items
🗃️ Notes
3 items
📄️ Calling Other Contracts
Learn how to call other contracts from your Aztec smart contracts.
📄️ Calling Other Contracts
Learn how to call functions within your Aztec smart contracts.
📄️ Emitting Events
Learn how to emit events from your Aztec smart contracts for off-chain applications to consume.
📄️ Using the Archive Tree
Learn how to prove historical state transitions in your Aztec smart contracts.
📄️ Using Capsules
Learn how to use capsules to add data to the private execution environment for use in your Aztec smart contracts.
📄️ Common Patterns
Explore common design patterns for writing secure and efficient Aztec smart contracts.
🗃️ Portals
1 item
📄️ Authentication Witness
Developer Documentation to use Authentication Witness for authentication actions on Aztec.