From 49baf239b4c823235fc9f081ef6e0e7d57a296d5 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 23 Aug 2023 14:27:41 +0200 Subject: [PATCH 01/88] feat: update format and add api --- docs/antora.yml | 2 +- docs/modules/ROOT/nav.adoc | 8 +- docs/modules/ROOT/pages/accounts.adoc | 639 ++---------------- docs/modules/ROOT/pages/api/account.adoc | 53 ++ .../modules/ROOT/pages/guides/deployment.adoc | 0 5 files changed, 123 insertions(+), 579 deletions(-) create mode 100644 docs/modules/ROOT/pages/api/account.adoc create mode 100644 docs/modules/ROOT/pages/guides/deployment.adoc diff --git a/docs/antora.yml b/docs/antora.yml index f75680009..d2277a2b1 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,4 +2,4 @@ name: contracts-cairo title: Contracts for Cairo version: 0.6.1 nav: - - modules/ROOT/nav.adoc + - modules/ROOT/nav.adoc \ No newline at end of file diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 3c84b7d03..fb6f7c083 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -16,4 +16,10 @@ * xref:udc.adoc[Universal Deployer Contract] * xref:utilities.adoc[Utilities] -* xref:contracts::index.adoc[Contracts for Solidity] \ No newline at end of file +* xref:contracts::index.adoc[Contracts for Solidity] + +* Guides +** xref:/guides/deployment.adoc[Deploying contracts] + +* API +** xref:/api/account.adoc[Account] \ No newline at end of file diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 55cbbc5e4..fac21eb38 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -1,632 +1,117 @@ :test-signers: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/tests/signers.py +:snip-5: https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md +:snip-6: https://github.com/ericnordelo/SNIPs/blob/feat/standard-account/SNIPS/snip-6.md = Accounts -Unlike Ethereum where accounts are directly derived from a private key, there's no native account concept on StarkNet. +Unlike Ethereum where accounts are directly derived from a private key, there's no native Externally Owned Account (EOA) concept on Starknet. -Instead, signature validation has to be done at the contract level. -To relieve smart contract applications such as ERC20 tokens or exchanges from this responsibility, we make use of Account contracts to deal with transaction authentication. +Instead, the L2 features native account abstraction, and signature validation has to be done at the contract level. To relieve smart contract applications such as ERC20 tokens or exchanges from this responsibility, we make use of Account contracts to deal with transaction authentication. For a general overview of the account abstraction, see StarkWare's https://medium.com/starkware/starknet-alpha-0-10-0-923007290470[StarkNet Alpha 0.10]. A more detailed discussion on the topic can be found in https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[StarkNet Account Abstraction Part 1]. +TIP: For detailed information on the usage and implementation check the xref:/api/account.adoc[API Reference] section. + == Table of Contents -* <> -* <> - ** <> -* <> -* <> -** <> - ** <> - ** <> - ** <> -* <> - ** <> - ** <> -* <> -* <> - ** <> - ** <> - ** <> - ** <> - ** <> - ** <> - ** <> - ** <> - ** <> -* <> - ** <> - ** <> -* <> -* <> -* <> -* <> - -== Quickstart - -The general workflow is: - -. Account contract is deployed to StarkNet. -. Signed transactions can now be sent to the Account contract which validates and executes them. - -In Python, this would look as follows: - -[,python] ----- -from starkware.starknet.testing.starknet import Starknet -from utils import get_contract_class -from signers import MockSigner +* <> +** <> +** <> +* <> +** <> +** <> +* <> -signer = MockSigner(123456789987654321) +== Basic Account -starknet = await Starknet.empty() +As we mentioned, Accounts in Starknet are smart contracts, and so they can be deployed and interacted with like any other contract, and can be extended to implement any custom logic. However, the Account is a special type of contract that is used to validate and execute transactions, and there are a set of entrypoints that must be implemented for enabling these features. -# 1. Deploy Account -account = await starknet.deploy( - get_contract_class("Account"), - constructor_calldata=[signer.public_key] -) -# 2. Send transaction through Account -await signer.send_transaction(account, some_contract_address, 'some_function', [some_parameter]) ----- +=== Account entrypoints -== Account entrypoints +The first two following methods are protocol-level enforced functions that must be implemented by any Account contract. The third one is optional and can be used for enabling declarations. -Account contracts have only three entry points for all user interactions: +1. `\\__validate__` verifies the validity of the transaction to be executed. Is usually used to validate signatures, but following the account abstraction design, the entrypoint implementation can be customized to feature any different validation mechanism. -1. <> validates the declaration signature prior to the declaration. -As of Cairo v0.10.0, contract classes should be declared from an Account contract. +2. `\\__execute__` executes the transaction if the validation is successful. -2. <> verifies the transaction signature before executing the transaction with `\\__execute__`. +3. `\\__validate_declare__` Optional entrypoint similar to \\__validate__ but for transactions meant to declare other contracts. -3. <> acts as the state-changing entry point for all user interaction with any contract, including managing the account contract itself. -That's why if you want to change the public key controlling the Account, you would send a transaction targeting the very Account contract: -[,python] ----- -await signer.send_transaction( - account, - account.contract_address, - 'set_public_key', - [NEW_KEY] -) ----- +NOTE: Even when this entrypoints can be called directly at contract level, they are not designed for that, but to be called by the Starknet OS in the transaction execution flow. -Or if you want to update the Account's L1 address on the `AccountRegistry` contract, you would +=== Interface -[,python] ----- -await signer.send_transaction(account, registry.contract_address, 'set_L1_address', [NEW_ADDRESS]) ----- +Notice that we haven't mentioned the parameters or the return values of these entrypoints. This is because function selectors in Starknet are computed from the function name, without including the rest of the signature. This means that the entrypoints can be implemented with any signature, and the protocol will be able to call them as long as the function name is correct. -NOTE: You can read more about how messages are structured and hashed in the https://github.com/OpenZeppelin/cairo-contracts/discussions/24[Account message scheme discussion]. -For more information on the design choices and implementation of multicall, you can read the https://github.com/OpenZeppelin/cairo-contracts/discussions/27[How should Account multicall work discussion]. +In the following interface, we are using the `Array` for enabling multicall transactions. Notice that we don't need signature related parameters, because they are part of the transaction information that is accesible using the global context (ex: `starknet::get_tx_info()`). -The `\\__validate__` and `\\__execute__` methods accept the same arguments; however, `\\__execute__` returns a transaction response: - -[,cairo] ----- -func __validate__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt*) { -} - -func __execute__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* -) -> (response_len: felt, response: felt*) { -} ----- - -Where: - -* `call_array_len` is the number of calls. -* `call_array` is an array representing each `Call`. -* `calldata_len` is the number of calldata parameters. -* `calldata` is an array representing the function parameters. - -NOTE: The scheme of building multicall transactions within the `\\__execute__` method will change once StarkNet allows for pointers in struct arrays. -In which case, multiple transactions can be passed to (as opposed to built within) `\\__execute__`. - -There's a fourth canonical entrypoint for accounts, the `\\__validate_deploy__` method. It is **only callable by the protocol** during the execution of a `DeployAccount` type of transaction, but not by any other contract. This entrypoint is for counterfactual deployments. - -=== Counterfactual Deployments - -Counterfactual means something that hasn't happened. - -A deployment is said to be counterfactual when the deployed contract pays for it. It's called like this because we need to send the funds to the address before deployment. A deployment that hasn't happened. - -The steps are the following: - -1. Precompute the `address` given a `class_hash`, `salt`, and constructor `calldata`. -2. Send funds to `address`. -3. Send a `DeployAccount` type transaction. -4. The protocol will then validate with `\\__validate_deploy__`. -5. If successful, the protocol deploys the contract and the contract itself pays for the transaction. - -Since `address` will ultimately depend on the `class_hash` and `calldata`, it's safe for the protocol to validate the signature and spend the funds on that address. - -== Standard interface - -The https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/account/IAccount.cairo[`IAccount.cairo`] contract interface contains the standard account interface proposed in https://github.com/OpenZeppelin/cairo-contracts/discussions/41[#41] and adopted by OpenZeppelin and Argent. -It implements https://eips.ethereum.org/EIPS/eip-1271[EIP-1271] and it is agnostic of signature validation. Further, nonce management is handled on the protocol level. - -NOTE: `\\__validate_deploy__` is not part of the interface since it's only callable by the protocol. Also contracts don't need to implement it to be considered accounts. - -[,cairo] +[,javascript] ---- +/// Represents a call to a target contract function. struct Call { - to: felt, - selector: felt, - calldata_len: felt, - calldata: felt*, -} - -// Tmp struct introduced while we wait for Cairo to support passing `[Call]` to __execute__ -struct CallArray { - to: felt, - selector: felt, - data_offset: felt, - data_len: felt, + to: ContractAddress, + selector: felt252, + calldata: Array } +trait BaseAccount { + /// Executes a transaction through the account. + fn __execute__(calls: Array) -> Array>; -@contract_interface -namespace IAccount { - func supportsInterface(interfaceId: felt) -> (success: felt) { - } - - func isValidSignature(hash: felt, signature_len: felt, signature: felt*) -> (isValid: felt) { - } - - func __validate__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* - ) { - } + /// Asserts whether the transaction is valid to be executed. + fn __validate__(calls: Array) -> felt252; - func __validate_declare__(class_hash: felt) { - } - - func __execute__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* - ) -> (response_len: felt, response: felt*) { - } + // (Optional) Asserts whether the transaction is valid to be declared. + fn __validate_declare__(class_hash: felt252) -> felt252; } - ---- -== Keys, signatures and signers - -While the interface is agnostic of signature validation schemes, this implementation assumes there's a public-private key pair controlling the Account. -That's why the `constructor` function expects a `public_key` parameter to set it. -Since there's also a `setPublicKey()` method, accounts can be effectively transferred. - -=== Signature validation - -Signature validation occurs separately from execution as of Cairo v0.10. -Upon receiving transactions, an account contract first calls `\\__validate__`. -An account will only execute a transaction if, and only if, the signature proves valid. -This decoupling allows for a protocol-level distinction between invalid and reverted transactions. -See <>. - -=== Signer +== Standard Account Interface -The signer is responsible for creating a transaction signature with the user's private key for a given transaction. -This implementation utilizes https://github.com/OpenZeppelin/nile/blob/main/src/nile/signer.py[Nile's Signer] class to create transaction signatures through the `Signer` method `sign_transaction`. +In the previous section we've presented the minimal interface a contract must implement to act as an Account by propagating transactions through the network. However, this interface lacks some features required for supporting interoperability among accounts and DApps in the ecosystem. For example, there is no mechanism for recognizing on-chain whether a contract is an Account or not. -`sign_transaction` expects the following parameters per transaction: +To address this issue, we have the {snip-6}[SNIP-6] proposal, which defines a standard interface for Account contracts. -* `sender` the contract address invoking the tx. -* `calls` a list containing a sublist of each call to be sent. -Each sublist must consist of: - .. `to` the address of the target contract of the message. - .. `selector` the function to be called on the target contract. - .. `calldata` the parameters for the given `selector`. -* `nonce` an unique identifier of this message to prevent transaction replays. -* `max_fee` the maximum fee a user will pay. +=== ISRC6 Interface -Which returns: - -* `calldata` a list of arguments for each call. -* `sig_r` the transaction signature. -* `sig_s` the transaction signature. - -While the `Signer` class performs much of the work for a transaction to be sent, it neither manages nonces nor invokes the actual transaction on the Account contract. -To simplify Account management, most of this is abstracted away with `MockSigner`. - -=== MockSigner utility - -The `MockSigner` class in {test-signers}[signers.py] is used to perform transactions on a given Account, crafting the transaction and managing nonces. - -NOTE: StarkNet's testing framework does not currently support transaction invocations from account contracts. `MockSigner` therefore utilizes StarkNet's API gateway to manually execute the `InvokeFunction` for testing. - -A `MockSigner` instance exposes the following methods: - -* `send_transaction(account, to, selector_name, calldata, nonce=None, max_fee=0)` returns a link:https://docs.python.org/3/library/asyncio-future.html[future] of a signed transaction, ready to be sent. -* `send_transactions(account, calls, nonce=None, max_fee=0)` returns a future of batched signed transactions, ready to be sent. -* `declare_class(account, contract_name, nonce=None, max_fee=0)` returns a future of a declaration transaction. -* `deploy_account(state, calldata, salt=0, nonce=0, max_fee=0)`: returns a future of a counterfactual deployment. - -To use `MockSigner`, pass a private key when instantiating the class: - -[,python] +[,javascript] ---- -from utils import MockSigner +/// Standard Account Interface +trait ISRC6 { + /// Executes a transaction through the account. + fn __execute__(calls: Array) -> Array>; -PRIVATE_KEY = 123456789987654321 -signer = MockSigner(PRIVATE_KEY) ----- - -Then send single transactions with the `send_transaction` method. + /// Asserts whether the transaction is valid to be executed. + fn __validate__(calls: Array) -> felt252; -[,python] ----- -await signer.send_transaction(account, contract_address, 'method_name', []) ----- - -If utilizing multicall, send multiple transactions with the `send_transactions` method. - -[,python] ----- -await signer.send_transactions( - account, - [ - (contract_address, 'method_name', [param1, param2]), - (contract_address, 'another_method', []) - ] -) ----- - -Use `declare_class` to declare a contract: - -[,python] ----- -await signer.declare_class(account, "MyToken") ----- - -And `deploy_account` to <> deploy an account: - -[,python] ----- -await signer.deploy_account(state, [signer.public_key]) ----- - - -=== MockEthSigner utility - -The `MockEthSigner` class in {test-signers}[signers.py] is used to perform transactions on a given Account with a secp256k1 curve key pair, crafting the transaction and managing nonces. -It differs from the `MockSigner` implementation by: - -* Not using the public key but its derived address instead (the last 20 bytes of the keccak256 hash of the public key and adding `0x` to the beginning). -* Signing the message with a secp256k1 curve address. - -== `Call` and `AccountCallArray` format - -The idea is for all user intent to be encoded into a `Call` representing a smart contract call. -Users can also pack multiple messages into a single transaction (creating a multicall transaction). -Cairo currently does not support arrays of structs with pointers which means the `\\__execute__` function cannot properly iterate through multiple ``Call``s. -Instead, this implementation utilizes a workaround with the `AccountCallArray` struct. -See <>. - -=== `Call` - -A single `Call` is structured as follows: - -[,cairo] ----- -struct Call { - to: felt - selector: felt - calldata_len: felt - calldata: felt* + /// Asserts whether a given signature for a given hash is valid. + fn is_valid_signature(hash: felt252, signature: Array) -> felt252; } ---- -Where: +The {snip-6}[SNIP-6] adds the `is_valid_signature` method. This method is not used by the protocol, but it's useful for DApps to verify the validity of signatures, supporting features like Sign In with Starknet. -* `to` is the address of the target contract of the message. -* `selector` is the selector of the function to be called on the target contract. -* `calldata_len` is the number of calldata parameters. -* `calldata` is an array representing the function parameters. +The SNIP-6 also defines that compliant Accounts must implement the SRC5 interface following {snip-5}[SNIP-5], as a mechanism for detecting whether a contract is an Account or not through introspection. -=== `AccountCallArray` +=== ISRC5 Interface -`AccountCallArray` is structured as: - -[,cairo] ----- -struct AccountCallArray { - to: felt - selector: felt - data_offset: felt - data_len: felt -} ----- - -Where: - -* `to` is the address of the target contract of the message. -* `selector` is the selector of the function to be called on the target contract. -* `data_offset` is the starting position of the calldata array that holds the ``Call``'s calldata. -* `data_len` is the number of calldata elements in the `Call`. - -== Multicall transactions - -A multicall transaction packs the `to`, `selector`, `calldata_offset`, and `calldata_len` of each call into the `AccountCallArray` struct and keeps the cumulative calldata for every call in a separate array. -The `\\__execute__` function rebuilds each message by combining the `AccountCallArray` with its calldata (demarcated by the offset and calldata length specified for that particular call). -The rebuilding logic is set in the internal `_from_call_array_to_call`. - -This is the basic flow: - -First, the user sends the messages for the transaction through a Signer instantiation which looks like this: - -[,python] ----- -await signer.send_transaction( - account, [ - (contract_address, 'contract_method', [arg_1]), - (contract_address, 'another_method', [arg_1, arg_2]) - ] -) +[,javascript] ---- - -Then the `from_call_to_call_array` method in link:https://github.com/OpenZeppelin/nile/blob/main/src/nile/signer.py[Nile's signer] converts each call into the `AccountCallArray` format and cumulatively stores the calldata of every call into a single array. -Next, both arrays (as well as the `sender`, `nonce`, and `max_fee`) are used to create the transaction hash. -The Signer then invokes `\__execute__` with the signature and passes `AccountCallArray`, calldata, and nonce as arguments. - -Finally, the `\\__execute__` method takes the `AccountCallArray` and calldata and builds an array of ``Call``s (MultiCall). - -NOTE: Every transaction utilizes `AccountCallArray`. -A single `Call` is treated as a bundle with one message. - -== API Specification - -This in a nutshell is the Account contract public API: - -[,cairo] ----- -namespace Account { - func constructor(publicKey: felt) { - } - - func getPublicKey() -> (publicKey: felt) { - } - - func supportsInterface(interfaceId: felt) -> (success: felt) { - } - - func setPublicKey(newPublicKey: felt) { - } - - func isValidSignature(hash: felt, signature_len: felt, signature: felt*) -> (isValid: felt) { - } - - func __validate__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* - ) -> (response_len: felt, response: felt*) { - } - - func __validate_declare__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* - ) -> (response_len: felt, response: felt*) { - } - - func __execute__( - call_array_len: felt, call_array: AccountCallArray*, calldata_len: felt, calldata: felt* - ) -> (response_len: felt, response: felt*) { +/// Standard Interface Detection +trait ISRC5 { + /// Queries if a contract implements a given interface. + fn supports_interface(interface_id: felt252) -> bool; } ---- -=== `constructor` - -Initializes and sets the public key for the Account contract. - -Parameters: - -[,cairo] ----- -publicKey: felt ----- - -Returns: None. - -=== `getPublicKey` - -Returns the public key associated with the Account. - -Parameters: None. - -Returns: - -[,cairo] ----- -publicKey: felt ----- - -=== `supportsInterface` - -Returns `TRUE` if this contract implements the interface defined by `interfaceId`. -Account contracts now implement ERC165 through static support (see <>). - -Parameters: - -[,cairo] ----- -interfaceId: felt ----- - -Returns: - -[,cairo] ----- -success: felt ----- - -=== `setPublicKey` - -Sets the public key that will control this Account. -It can be used to rotate keys for security, change them in case of compromised keys or even transferring ownership of the account. - -Parameters: - -[,cairo] ----- -newPublicKey: felt ----- - -Returns: None. - -=== `isValidSignature` - -This function is inspired by https://eips.ethereum.org/EIPS/eip-1271[EIP-1271] and returns `TRUE` if a given signature is valid, otherwise it reverts. -In the future it will return `FALSE` if a given signature is invalid (for more info please check https://github.com/OpenZeppelin/cairo-contracts/issues/327[this issue]). - -Parameters: - -[,cairo] ----- -hash: felt -signature_len: felt -signature: felt* ----- - -Returns: - -[,cairo] ----- -isValid: felt ----- - -NOTE: It may return `FALSE` in the future if a given signature is invalid (follow the discussion on https://github.com/OpenZeppelin/cairo-contracts/issues/327[this issue]). - -=== `\\__validate__` - -Validates the transaction signature and is called prior to `\\__execute__`. - -Parameters: - -[,cairo] ----- -call_array_len: felt -call_array: AccountCallArray* -calldata_len: felt -calldata: felt* ----- - -Returns: None. - -=== `\\__validate_declare__` - -Validates the signature for declaration transactions. - -Parameters: - -[,cairo] ----- -class_hash: felt ----- - -Returns: None. - -=== `\\__validate_deploy__` - -Validates the signature for counterfactual deployment transactions. - -It takes the `class_hash` of the account being deployed along with the `salt` and `calldata`, the latter being expanded. For example if the account is deployed with calldata `[arg_1, ..., arg_n]`: - -Parameters: - -[,cairo] ----- -class_hash: felt -salt: felt -arg_1: felt -... -arg_n: felt ----- - -Returns: None. - -=== `\\__execute__` - -This is the only external entrypoint to interact with the Account contract. -It: - -. Calls the target contract with the intended function selector and calldata parameters. -. Forwards the contract call response data as return value. - -Parameters: - -[,cairo] ----- -call_array_len: felt -call_array: AccountCallArray* -calldata_len: felt -calldata: felt* ----- - -NOTE: The current signature scheme expects a 2-element array like `[sig_r, sig_s]`. - -Returns: - -[,cairo] ----- -response_len: felt -response: felt* ----- - -== Presets - -The following contract presets are ready to deploy and can be used as-is for quick prototyping and testing. -Each preset differs on the signature type being used by the Account. - -=== Account - -The https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/account/presets/Account.cairo[`Account`] preset uses StarkNet keys to validate transactions. - -=== Eth Account - -The https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/account/presets/EthAccount.cairo[`EthAccount`] preset supports Ethereum addresses, validating transactions with secp256k1 keys. - -== Account introspection with ERC165 - -Certain contracts like ERC721 or ERC1155 require a means to differentiate between account contracts and non-account contracts. -For a contract to declare itself as an account, it should implement https://eips.ethereum.org/EIPS/eip-165[ERC165] as proposed in https://github.com/OpenZeppelin/cairo-contracts/discussions/100[#100]. - -To be in compliance with ERC165 specifications, we calculate the account contract ID as the XOR of ``IAccount``'s equivalent EVM selectors (not StarkNet selectors). -This magic value has been tracking the changes of the still evolving Account interface standard, and **its current value is `0xa66bd575`**. - -Our ERC165 integration on StarkNet is inspired by OpenZeppelin's Solidity implementation of https://docs.openzeppelin.com/contracts/4.x/api/utils#ERC165Storage[ERC165Storage] which stores the interfaces that the implementing contract supports. -In the case of account contracts, querying `supportsInterface` of an account's address with the `IAccount` magic value should return `TRUE`. - -NOTE: For Account contracts, ERC165 support is static and does not require Account contracts to register. - -== Extending the Account contract - -Account contracts can be extended by following the xref:extensibility.adoc#the_pattern[extensibility pattern]. - -To implement custom account contracts, it's required by the StarkNet compiler that they include the three entrypoint functions `\\__validate__`, `\\__validate_declare__`, and `\\__execute__`. - -`\\__validate__` and `\\__validate_declare__` should include the same signature validation method; whereas, `\\__execute__` should only handle the actual transaction. Incorporating a new validation scheme necessitates only that it's invoked by both `\\__validate__` and `\\__validate_declare__`. - -This is why the Account library comes with different flavors of signature validation methods like `is_valid_eth_signature` and the vanilla `is_valid_signature`. - -Account contract developers are encouraged to implement the https://github.com/OpenZeppelin/cairo-contracts/discussions/41[standard Account interface] and incorporate the custom logic thereafter. - -IMPORTANT: Due to current inconsistencies between the testing framework and the actual StarkNet network, extreme caution should be used when integrating new Account contracts. -Instances have occurred where account functionality tests pass and transactions execute correctly on the local node; yet, they fail on public networks. -For this reason, it's highly encouraged that new account contracts are also deployed and tested on the public testnet. -See https://github.com/OpenZeppelin/cairo-contracts/issues/386[issue #386] for more information. - -Some other validation schemes to look out for in the future: - -* Multisig. -* Guardian logic like in https://github.com/argentlabs/argent-contracts-starknet/blob/de5654555309fa76160ba3d7393d32d2b12e7349/contracts/ArgentAccount.cairo[Argent's account]. +{snip-6}[SNIP-6] compliant Accounts must return `true` when queried for the ISRC6 interface Id. -== L1 escape hatch mechanism +Even though these interfaces are not enforced by the protocol, it's recommended to implement them for enabling interoperability with the ecosystem. -[unknown, to be defined] +== Deploying an Account -== Paying for gas +In Starknet, there are two different ways for deploying smart contracts: the regular deployment using the `deploy_syscall` and the counterfactual deployment. The xref:udc.adoc[Universal Deployer Contract (UDC)] provides an interface for deploying arbitrary contracts through account calls (leveraging the first way through the `deploy_syscall`), but if you are deploying your first Account, you will probably want to use the counterfactual deployment, from the fact that you don't have an Account for calling the UDC in the first place. -[unknown, to be defined] +For using counterfactual deployments, you need to implement another protocol-level entrypoint (not specific to accounts) named `\\__validate_deploy__`. You can check the xref:/guides/deployment.adoc[Deploying Contracts] guide for getting into the specifics. diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc new file mode 100644 index 000000000..9fa82e32c --- /dev/null +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -0,0 +1,53 @@ +:github-icon: pass:[] + += Account + +Reference of interfaces and utilities related to Account contracts. + +TIP: For an overview of Accounts, read our xref:accounts.adoc[Accounts guide]. + +== Core + +[.contract] +[[ISRC6]] +=== `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/b40c35b5ca82598ae5bd9610aa3ffd0ded1f3c5f/src/account/interface.cairo#L12[{github-icon},role=heading-link] + +[.hljs-theme-light.nopadding] +```javascript +use openzeppelin::account::interface::ISRC6; +``` + +Interface of the ISRC6 standard as defined in the SNIP. + + +[.contract-index] +.Functions +-- +* xref:#\\__execute__[`++__execute__(calls: Array)++`] +* xref:#\\__validate__[`++__validate__(calls: Array)++`] +* xref:#\\__is_valid_signature__[`++__is_valid_signature__(hash: felt252, signature: Array)++`] +-- + +[.contract-item] +[[__execute__]] +==== `[.contract-item-name]#++__execute__++#++(calls: Array) → Array>++` [.item-kind]#external# + +Executes the list of calls as a transaction after validation. + +Returns the list of each call output. + +[.contract-item] +[[__validate__]] +==== `[.contract-item-name]#++__validate__++#++(calls: Array) → felt252++` [.item-kind]#external# + +Validates a transaction before execution. + +Returns the short string `'VALID'` if valid, or any other value otherwise. + +[.contract-item] +[[__is_valid_signature__]] +==== `[.contract-item-name]#++__is_valid_signature__++#++(hash: felt252, signature: Array) → felt252++` [.item-kind]#external# + +Validates whether a signature is valid or not for the given message hash. + +Returns the short string `'VALID'` if valid, or any other value otherwise. diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc new file mode 100644 index 000000000..e69de29bb From 6ba12a983041a13a4b002d4f0e42615a4b7c9cf2 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 23 Aug 2023 14:29:13 +0200 Subject: [PATCH 02/88] fix: typo --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index d2277a2b1..f75680009 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,4 +2,4 @@ name: contracts-cairo title: Contracts for Cairo version: 0.6.1 nav: - - modules/ROOT/nav.adoc \ No newline at end of file + - modules/ROOT/nav.adoc From 38a73636cdf5680cb5bccd635376b1165f89fa9c Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 24 Aug 2023 13:47:59 +0200 Subject: [PATCH 03/88] feat: add counterfactual deployment doc --- docs/modules/ROOT/nav.adoc | 2 +- docs/modules/ROOT/pages/accounts.adoc | 2 +- .../modules/ROOT/pages/guides/deployment.adoc | 35 +++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index fb6f7c083..47c42f3e6 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -19,7 +19,7 @@ * xref:contracts::index.adoc[Contracts for Solidity] * Guides -** xref:/guides/deployment.adoc[Deploying contracts] +** xref:/guides/deployment.adoc[Counterfactual Deployments] * API ** xref:/api/account.adoc[Account] \ No newline at end of file diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index fac21eb38..fc43bc7a6 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -114,4 +114,4 @@ Even though these interfaces are not enforced by the protocol, it's recommended In Starknet, there are two different ways for deploying smart contracts: the regular deployment using the `deploy_syscall` and the counterfactual deployment. The xref:udc.adoc[Universal Deployer Contract (UDC)] provides an interface for deploying arbitrary contracts through account calls (leveraging the first way through the `deploy_syscall`), but if you are deploying your first Account, you will probably want to use the counterfactual deployment, from the fact that you don't have an Account for calling the UDC in the first place. -For using counterfactual deployments, you need to implement another protocol-level entrypoint (not specific to accounts) named `\\__validate_deploy__`. You can check the xref:/guides/deployment.adoc[Deploying Contracts] guide for getting into the specifics. +For using counterfactual deployments, you need to implement another protocol-level entrypoint named `\\__validate_deploy__`. You can check the xref:/guides/deployment.adoc[Counterfactual Deployments] guide for getting into the specifics. diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc index e69de29bb..0ec44d384 100644 --- a/docs/modules/ROOT/pages/guides/deployment.adoc +++ b/docs/modules/ROOT/pages/guides/deployment.adoc @@ -0,0 +1,35 @@ +:foundry: https://foundry-rs.github.io/starknet-foundry/starknet/account.html[Starknet Foundry] +:starkli: https://book.starkli.rs/accounts#account-deployment[Starkli] + += Counterfactual deployments + +A deployment is said to be counterfactual when the one paying for the deployment fees is the address of the contract to be deployed. It’s called like this because we need to send the funds to the address even when the deployment hasn’t happened. + +This process can be described with the following steps: + +TIP: For testing this flow you can check the {foundry} or the {starkli} guides for deploying accounts. + +1. Deterministically precompute the `contract_address` given a `class_hash`, `salt`, and constructor `calldata`. Note that the `class_hash` must be previously declared for the deployment to succeed. + +2. Send funds to the `contract_address`. Usually you will estimate the fee of the transaction first. Existing tools usually do this for you. + +3. Send a `DeployAccount` type transaction to the network. + +4. The protocol will then validate the transaction with the `\\__validate_deploy__` entrypoint. + +5. If the validation succeeds, the protocol will charge the fee and then register the contract as deployed. + + +== Deployment validation + +As you noticed, for contracts being able to be counterfactually deployed, they must implement the `\\__validate_deploy__` entrypoint, and it is called by the protocol when a `DeployAccount` transaction is sent to the network. + +[,javascript] +---- +trait IDeployable { + /// Must return 'VALID' when the validation is successful. + fn __validate_deploy__( + class_hash: felt252, contract_address_salt: felt252, _public_key: felt252 + ) -> felt252; +} +---- From 06d338487ec0960af7702af81c5ae30b65c4d697 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 24 Aug 2023 14:21:07 +0200 Subject: [PATCH 04/88] feat: add API entries --- docs/modules/ROOT/pages/api/account.adoc | 98 +++++++++++++++++++++--- 1 file changed, 88 insertions(+), 10 deletions(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 9fa82e32c..dd68bea8c 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -1,8 +1,9 @@ :github-icon: pass:[] +:snip6: https://github.com/ericnordelo/SNIPs/blob/feat/standard-account/SNIPS/snip-6.md[SNIP-6] = Account -Reference of interfaces and utilities related to Account contracts. +Reference of interfaces, presets, and utilities related to Account contracts. TIP: For an overview of Accounts, read our xref:accounts.adoc[Accounts guide]. @@ -10,26 +11,26 @@ TIP: For an overview of Accounts, read our xref:accounts.adoc[Accounts guide]. [.contract] [[ISRC6]] -=== `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/b40c35b5ca82598ae5bd9610aa3ffd0ded1f3c5f/src/account/interface.cairo#L12[{github-icon},role=heading-link] +=== `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/account/interface.cairo#L12[{github-icon},role=heading-link] [.hljs-theme-light.nopadding] ```javascript use openzeppelin::account::interface::ISRC6; ``` -Interface of the ISRC6 standard as defined in the SNIP. +Interface of the ISRC6 standard as defined in the {snip6}. [.contract-index] .Functions -- -* xref:#\\__execute__[`++__execute__(calls: Array)++`] -* xref:#\\__validate__[`++__validate__(calls: Array)++`] -* xref:#\\__is_valid_signature__[`++__is_valid_signature__(hash: felt252, signature: Array)++`] +* xref:#ISRC6-\\__execute__[`++__execute__(calls: Array)++`] +* xref:#ISRC6-\\__validate__[`++__validate__(calls: Array)++`] +* xref:#ISRC6-is_valid_signature[`++is_valid_signature(hash: felt252, signature: Array)++`] -- [.contract-item] -[[__execute__]] +[[ISRC6-__execute__]] ==== `[.contract-item-name]#++__execute__++#++(calls: Array) → Array>++` [.item-kind]#external# Executes the list of calls as a transaction after validation. @@ -37,7 +38,7 @@ Executes the list of calls as a transaction after validation. Returns the list of each call output. [.contract-item] -[[__validate__]] +[[ISRC6-__validate__]] ==== `[.contract-item-name]#++__validate__++#++(calls: Array) → felt252++` [.item-kind]#external# Validates a transaction before execution. @@ -45,9 +46,86 @@ Validates a transaction before execution. Returns the short string `'VALID'` if valid, or any other value otherwise. [.contract-item] -[[__is_valid_signature__]] -==== `[.contract-item-name]#++__is_valid_signature__++#++(hash: felt252, signature: Array) → felt252++` [.item-kind]#external# +[[ISRC6-is_valid_signature]] +==== `[.contract-item-name]#++is_valid_signature++#++(hash: felt252, signature: Array) → felt252++` [.item-kind]#external# Validates whether a signature is valid or not for the given message hash. Returns the short string `'VALID'` if valid, or any other value otherwise. + +[.contract] +[[Account]] +=== `++Account++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/account/account.cairo#L27[{github-icon},role=heading-link] + +[.hljs-theme-light.nopadding] +```javascript +use openzeppelin::account::Account; +``` + +Base Account contract implementation. + + +[.contract-index] +.Functions +-- +* xref:#Account-\\__execute__[`++__execute__(calls: Array)++`] +* xref:#Account-\\__validate__[`++__validate__(calls: Array)++`] +* xref:#Account-\\__validate_declare__[`++__validate_declare__(class_hash: felt252)++`] +* xref:#Account-\\__validate_deploy__[`++__validate_deploy__(hash: felt252, signature: Array)++`] +* xref:#Account-set_public_key[`++set_public_key(new_public_key: felt252)++`] +* xref:#Account-get_public_key[`++get_public_key()++`] +* xref:#Account-is_valid_signature[`++is_valid_signature(hash: felt252, signature: Array)++`] +* xref:#Account-supports_interface[`++supports_interface(interface_id: felt252)++`] +-- + +[.contract-item] +[[Account-__execute__]] +==== `[.contract-item-name]#++__execute__++#++(calls: Array) → Array>++` [.item-kind]#external# + +See xref:ISRC6-\\__execute__[ISRC6::\\__execute__]. + +[.contract-item] +[[Account-__validate__]] +==== `[.contract-item-name]#++__validate__++#++(calls: Array) → felt252++` [.item-kind]#external# + +See xref:ISRC6-\\__validate__[ISRC6::\\__validate__]. + +[.contract-item] +[[Account-__validate_declare__]] +==== `[.contract-item-name]#++__validate_declare__++#++(class_hash: felt252) → felt252++` [.item-kind]#external# + +Validates a Declare transaction. + +Returns the short string `'VALID'` if valid, or any other value otherwise. + +[.contract-item] +[[Account-__validate_deploy__]] +==== `[.contract-item-name]#++__validate_deploy__++#++(class_hash: felt252, contract_address_salt: felt252, _public_key: felt252) → felt252++` [.item-kind]#external# + +Validates a DeployAccount transaction. + +Returns the short string `'VALID'` if valid, or any other value otherwise. + +[.contract-item] +[[Account-set_public_key]] +==== `[.contract-item-name]#++set_public_key++#++(new_public_key: felt252)++` [.item-kind]#external# + +Sets a new public key for the account. + +[.contract-item] +[[Account-get_public_key]] +==== `[.contract-item-name]#++get_public_key++#++()++ → felt252` [.item-kind]#external# + +Returns the current public key of the account. + +[.contract-item] +[[Account-is_valid_signature]] +==== `[.contract-item-name]#++is_valid_signature++#++(hash: felt252, signature: Array) → felt252++` [.item-kind]#external# + +See xref:ISRC6-is_valid_signature[ISRC6::is_valid_signature]. + +[.contract-item] +[[Account-supports_interface]] +==== `[.contract-item-name]#++supports_interface++#++(interface_id: felt252) → bool++` [.item-kind]#external# + +Returns whether a contract implements a given interface or not. From 48e77cffd8fbcea51694a054a772604dcd9952e6 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 24 Aug 2023 14:33:21 +0200 Subject: [PATCH 05/88] feat: add events --- docs/modules/ROOT/pages/api/account.adoc | 47 +++++++++++++++++++----- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index dd68bea8c..1f5b39194 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -24,9 +24,9 @@ Interface of the ISRC6 standard as defined in the {snip6}. [.contract-index] .Functions -- -* xref:#ISRC6-\\__execute__[`++__execute__(calls: Array)++`] -* xref:#ISRC6-\\__validate__[`++__validate__(calls: Array)++`] -* xref:#ISRC6-is_valid_signature[`++is_valid_signature(hash: felt252, signature: Array)++`] +* xref:#ISRC6-\\__execute__[`++__execute__(calls)++`] +* xref:#ISRC6-\\__validate__[`++__validate__(calls)++`] +* xref:#ISRC6-is_valid_signature[`++is_valid_signature(hash, signature)++`] -- [.contract-item] @@ -68,14 +68,29 @@ Base Account contract implementation. [.contract-index] .Functions -- -* xref:#Account-\\__execute__[`++__execute__(calls: Array)++`] -* xref:#Account-\\__validate__[`++__validate__(calls: Array)++`] -* xref:#Account-\\__validate_declare__[`++__validate_declare__(class_hash: felt252)++`] -* xref:#Account-\\__validate_deploy__[`++__validate_deploy__(hash: felt252, signature: Array)++`] -* xref:#Account-set_public_key[`++set_public_key(new_public_key: felt252)++`] +* xref:#Account-\\__validate_declare__[`++__validate_declare__(class_hash)++`] +* xref:#Account-\\__validate_deploy__[`++__validate_deploy__(hash, signature)++`] +* xref:#Account-set_public_key[`++set_public_key(new_public_key)++`] * xref:#Account-get_public_key[`++get_public_key()++`] -* xref:#Account-is_valid_signature[`++is_valid_signature(hash: felt252, signature: Array)++`] -* xref:#Account-supports_interface[`++supports_interface(interface_id: felt252)++`] + +[.contract-subindex-inherited] +.ISRC6 + +* xref:#Account-\\__execute__[`++__execute__(calls)++`] +* xref:#Account-\\__validate__[`++__validate__(calls)++`] +* xref:#Account-is_valid_signature[`++is_valid_signature(hash, signature)++`] + +[.contract-subindex-inherited] +.ISRC5 + +* xref:#Account-supports_interface[`++supports_interface(interface_id)++`] +-- + +[.contract-index] +.Events +-- +* xref:#Account-OwnerAdded[`++OwnerAdded(new_owner_guid)++`] +* xref:#Account-OwnerRemoved[`++OwnerRemoved(removed_owner_guid)++`] -- [.contract-item] @@ -129,3 +144,15 @@ See xref:ISRC6-is_valid_signature[ISRC6::is_valid_signature]. ==== `[.contract-item-name]#++supports_interface++#++(interface_id: felt252) → bool++` [.item-kind]#external# Returns whether a contract implements a given interface or not. + +[.contract-item] +[[Account-OwnerAdded]] +==== `[.contract-item-name]#++OwnerAdded++#++(new_owner_guid: felt252)++` [.item-kind]#event# + +Emitted when the account `public_key` is updated. + +[.contract-item] +[[Account-OwnerRemoved]] +==== `[.contract-item-name]#++OwnerRemoved++#++(removed_owner_guid: felt252)++` [.item-kind]#event# + +Emitted when the account `public_key` is updated except for initialization. From 2cce06a6792a627e65d73a93f2d8fa3cb88a9fe5 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 25 Aug 2023 13:25:09 +0200 Subject: [PATCH 06/88] Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index fc43bc7a6..0c8738b34 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -32,7 +32,7 @@ As we mentioned, Accounts in Starknet are smart contracts, and so they can be de The first two following methods are protocol-level enforced functions that must be implemented by any Account contract. The third one is optional and can be used for enabling declarations. -1. `\\__validate__` verifies the validity of the transaction to be executed. Is usually used to validate signatures, but following the account abstraction design, the entrypoint implementation can be customized to feature any different validation mechanism. +1. `\\__validate__` verifies the validity of the transaction to be executed. This is usually used to validate signatures, but following the account abstraction design, the entrypoint implementation can be customized to feature any validation mechanism. 2. `\\__execute__` executes the transaction if the validation is successful. From 71cc37d88df9b308a48677251c166e184e5f0220 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 25 Aug 2023 13:26:36 +0200 Subject: [PATCH 07/88] Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 0c8738b34..c9ee0333e 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -45,7 +45,7 @@ NOTE: Even when this entrypoints can be called directly at contract level, they Notice that we haven't mentioned the parameters or the return values of these entrypoints. This is because function selectors in Starknet are computed from the function name, without including the rest of the signature. This means that the entrypoints can be implemented with any signature, and the protocol will be able to call them as long as the function name is correct. -In the following interface, we are using the `Array` for enabling multicall transactions. Notice that we don't need signature related parameters, because they are part of the transaction information that is accesible using the global context (ex: `starknet::get_tx_info()`). +In the following interface, we are using the `Array` for enabling multicall transactions. Notice that we don't need signature-related parameters, because they are part of the transaction information that is accesible using the global context (ex: `starknet::get_tx_info()`). [,javascript] ---- From a34020e1c5e8662bba527b4a58711d8240f078c3 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 25 Aug 2023 13:26:47 +0200 Subject: [PATCH 08/88] Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index c9ee0333e..52a89d3c6 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -36,7 +36,7 @@ The first two following methods are protocol-level enforced functions that must 2. `\\__execute__` executes the transaction if the validation is successful. -3. `\\__validate_declare__` Optional entrypoint similar to \\__validate__ but for transactions meant to declare other contracts. +3. `\\__validate_declare__` Optional entrypoint similar to `\\__validate__` but for transactions meant to declare other contracts. NOTE: Even when this entrypoints can be called directly at contract level, they are not designed for that, but to be called by the Starknet OS in the transaction execution flow. From 60305e7ed748e44e267d849ac4a21e8f89939428 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 25 Aug 2023 13:44:48 +0200 Subject: [PATCH 09/88] Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/guides/deployment.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc index 0ec44d384..9dba7e4d0 100644 --- a/docs/modules/ROOT/pages/guides/deployment.adoc +++ b/docs/modules/ROOT/pages/guides/deployment.adoc @@ -3,7 +3,7 @@ = Counterfactual deployments -A deployment is said to be counterfactual when the one paying for the deployment fees is the address of the contract to be deployed. It’s called like this because we need to send the funds to the address even when the deployment hasn’t happened. +A deployment is said to be counterfactual when the one paying for the deployment fees is the address of the contract to be deployed. In other words, we need to send the funds to the address even when the deployment hasn’t happened. This process can be described with the following steps: From 2223482644b3932f1b26236c2fe86d806e05e7be Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 25 Aug 2023 13:45:07 +0200 Subject: [PATCH 10/88] Update docs/modules/ROOT/pages/guides/deployment.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/guides/deployment.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc index 9dba7e4d0..63307fa67 100644 --- a/docs/modules/ROOT/pages/guides/deployment.adoc +++ b/docs/modules/ROOT/pages/guides/deployment.adoc @@ -22,7 +22,7 @@ TIP: For testing this flow you can check the {foundry} or the {starkli} guides f == Deployment validation -As you noticed, for contracts being able to be counterfactually deployed, they must implement the `\\__validate_deploy__` entrypoint, and it is called by the protocol when a `DeployAccount` transaction is sent to the network. +For counterfactual deployments, contracts must implement the `\\__validate_deploy__` entrypoint, and it is called by the protocol when a `DeployAccount` transaction is sent to the network. [,javascript] ---- From 1ae6d1864e9a5cbe76781127c0404183f782114a Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 25 Aug 2023 19:07:20 +0200 Subject: [PATCH 11/88] feat: update from reviews --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index fc43bc7a6..d0f1533ff 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -45,7 +45,7 @@ NOTE: Even when this entrypoints can be called directly at contract level, they Notice that we haven't mentioned the parameters or the return values of these entrypoints. This is because function selectors in Starknet are computed from the function name, without including the rest of the signature. This means that the entrypoints can be implemented with any signature, and the protocol will be able to call them as long as the function name is correct. -In the following interface, we are using the `Array` for enabling multicall transactions. Notice that we don't need signature related parameters, because they are part of the transaction information that is accesible using the global context (ex: `starknet::get_tx_info()`). +In the following interface, we are using the `Array` for enabling multicall transactions. Note that we don't need signature related parameters, because they are part of the transaction information that is accesible using the global context (ex: `starknet::get_tx_info()`). [,javascript] ---- From 7a9f38e570261e09ea3df1f066faf365174b3b5b Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 25 Aug 2023 19:50:03 +0200 Subject: [PATCH 12/88] feat: apply review updates --- docs/modules/ROOT/pages/accounts.adoc | 65 ++++++++++++++----- docs/modules/ROOT/pages/api/account.adoc | 4 +- .../modules/ROOT/pages/guides/deployment.adoc | 13 ++-- 3 files changed, 59 insertions(+), 23 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index bace4b3c1..aabe09d6a 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -4,12 +4,17 @@ = Accounts -Unlike Ethereum where accounts are directly derived from a private key, there's no native Externally Owned Account (EOA) concept on Starknet. +Unlike Ethereum where accounts are directly derived from a private key, there's no native Externally Owned Account (EOA) +concept on Starknet. -Instead, the L2 features native account abstraction, and signature validation has to be done at the contract level. To relieve smart contract applications such as ERC20 tokens or exchanges from this responsibility, we make use of Account contracts to deal with transaction authentication. +Instead, the network features native account abstraction, and signature validation has to be done at the contract level. +To relieve smart contract applications such as ERC20 tokens or exchanges from this responsibility, +we make use of Account contracts to deal with transaction authentication. -For a general overview of the account abstraction, see StarkWare's https://medium.com/starkware/starknet-alpha-0-10-0-923007290470[StarkNet Alpha 0.10]. -A more detailed discussion on the topic can be found in https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[StarkNet Account Abstraction Part 1]. +For a general overview of the account abstraction, see StarkWare's +https://medium.com/starkware/starknet-alpha-0-10-0-923007290470[StarkNet Alpha 0.10]. +A more detailed discussion on the topic can be found in +https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[StarkNet Account Abstraction Part 1]. TIP: For detailed information on the usage and implementation check the xref:/api/account.adoc[API Reference] section. @@ -25,27 +30,39 @@ TIP: For detailed information on the usage and implementation check the xref:/ap == Basic Account -As we mentioned, Accounts in Starknet are smart contracts, and so they can be deployed and interacted with like any other contract, and can be extended to implement any custom logic. However, the Account is a special type of contract that is used to validate and execute transactions, and there are a set of entrypoints that must be implemented for enabling these features. - +As we mentioned, Accounts in Starknet are smart contracts, and so they can be deployed and interacted +with like any other contract, and can be extended to implement any custom logic. However, the Account is a special +type of contract that is used to validate and execute transactions, and there are a set of entrypoints +that must be implemented for enabling these features. === Account entrypoints -The first two following methods are protocol-level enforced functions that must be implemented by any Account contract. The third one is optional and can be used for enabling declarations. +The first two following methods are protocol-level enforced functions that must be implemented by any Account contract. +The third one is optional and can be used for enabling declarations. -1. `\\__validate__` verifies the validity of the transaction to be executed. This is usually used to validate signatures, but following the account abstraction design, the entrypoint implementation can be customized to feature any validation mechanism. +1. `\\__validate__` verifies the validity of the transaction to be executed. This is usually used to validate signatures, +but following the account abstraction design, the entrypoint implementation can be customized to feature any +validation mechanism. 2. `\\__execute__` executes the transaction if the validation is successful. -3. `\\__validate_declare__` Optional entrypoint similar to `\\__validate__` but for transactions meant to declare other contracts. +3. `\\__validate_declare__` Optional entrypoint similar to `\\__validate__` but for transactions +meant to declare other contracts. -NOTE: Even when this entrypoints can be called directly at contract level, they are not designed for that, but to be called by the Starknet OS in the transaction execution flow. +NOTE: Even when this entrypoints can be called directly at contract level, they are not designed for that, +but to be called by the Starknet OS in the transaction execution flow. === Interface -Notice that we haven't mentioned the parameters or the return values of these entrypoints. This is because function selectors in Starknet are computed from the function name, without including the rest of the signature. This means that the entrypoints can be implemented with any signature, and the protocol will be able to call them as long as the function name is correct. +Notice that we haven't mentioned the parameters or the return values of these entrypoints. This is because function +selectors in Starknet are computed from the function name, without including the rest of the signature. This means +that the entrypoints can be implemented with any signature, and the protocol will be able to call them as long +as the function name is correct. -In the following interface, we are using the `Array` for enabling multicall transactions. Note that we don't need signature related parameters, because they are part of the transaction information that is accesible using the global context (ex: `starknet::get_tx_info()`). +In the following interface, we are using the `Array` for enabling multicall transactions. Note that we +don't need signature related parameters, because they are part of the transaction information that is accesible +using the global context (ex: `starknet::get_tx_info()`). [,javascript] ---- @@ -70,7 +87,10 @@ trait BaseAccount { == Standard Account Interface -In the previous section we've presented the minimal interface a contract must implement to act as an Account by propagating transactions through the network. However, this interface lacks some features required for supporting interoperability among accounts and DApps in the ecosystem. For example, there is no mechanism for recognizing on-chain whether a contract is an Account or not. +In the previous section we've presented the minimal interface a contract must implement to act as an Account by +propagating transactions through the network. However, this interface lacks some features required for supporting +interoperability among accounts and DApps in the ecosystem. For example, there is no mechanism for +recognizing on-chain whether a contract is an Account or not. To address this issue, we have the {snip-6}[SNIP-6] proposal, which defines a standard interface for Account contracts. @@ -91,9 +111,11 @@ trait ISRC6 { } ---- -The {snip-6}[SNIP-6] adds the `is_valid_signature` method. This method is not used by the protocol, but it's useful for DApps to verify the validity of signatures, supporting features like Sign In with Starknet. +The {snip-6}[SNIP-6] adds the `is_valid_signature` method. This method is not used by the protocol, but it's useful for +DApps to verify the validity of signatures, supporting features like Sign In with Starknet. -The SNIP-6 also defines that compliant Accounts must implement the SRC5 interface following {snip-5}[SNIP-5], as a mechanism for detecting whether a contract is an Account or not through introspection. +The SNIP-6 also defines that compliant Accounts must implement the SRC5 interface following {snip-5}[SNIP-5], as +a mechanism for detecting whether a contract is an Account or not through introspection. === ISRC5 Interface @@ -108,10 +130,17 @@ trait ISRC5 { {snip-6}[SNIP-6] compliant Accounts must return `true` when queried for the ISRC6 interface Id. -Even though these interfaces are not enforced by the protocol, it's recommended to implement them for enabling interoperability with the ecosystem. +Even though these interfaces are not enforced by the protocol, it's recommended to implement them for enabling +interoperability with the ecosystem. == Deploying an Account -In Starknet, there are two different ways for deploying smart contracts: the regular deployment using the `deploy_syscall` and the counterfactual deployment. The xref:udc.adoc[Universal Deployer Contract (UDC)] provides an interface for deploying arbitrary contracts through account calls (leveraging the first way through the `deploy_syscall`), but if you are deploying your first Account, you will probably want to use the counterfactual deployment, from the fact that you don't have an Account for calling the UDC in the first place. +In Starknet, there are two different ways for deploying smart contracts: the regular deployment using the +`deploy_syscall` and the counterfactual deployment. The xref:udc.adoc[Universal Deployer Contract (UDC)] provides +an interface for deploying arbitrary contracts through account calls (leveraging the first way through +the `deploy_syscall`), but if you are deploying your first Account, you will probably want to use the +counterfactual deployment, from the fact that you don't have an Account for calling the UDC in the first place. -For using counterfactual deployments, you need to implement another protocol-level entrypoint named `\\__validate_deploy__`. You can check the xref:/guides/deployment.adoc[Counterfactual Deployments] guide for getting into the specifics. +For using counterfactual deployments, you need to implement another protocol-level entrypoint named +`\\__validate_deploy__`. You can check the xref:/guides/deployment.adoc[Counterfactual Deployments] guide for +getting into the specifics. diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 1f5b39194..224edf7b2 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -125,7 +125,9 @@ Returns the short string `'VALID'` if valid, or any other value otherwise. [[Account-set_public_key]] ==== `[.contract-item-name]#++set_public_key++#++(new_public_key: felt252)++` [.item-kind]#external# -Sets a new public key for the account. +Sets a new public key for the account. Can be called only by self through the `\\__execute__` mechanism. + +Emits an xref:Account-OwnerRemoved[OwnerRemoved], and an xref:Account-OwnerAdded[OwnerAdded] event. [.contract-item] [[Account-get_public_key]] diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc index 63307fa67..bc2ec6006 100644 --- a/docs/modules/ROOT/pages/guides/deployment.adoc +++ b/docs/modules/ROOT/pages/guides/deployment.adoc @@ -3,15 +3,19 @@ = Counterfactual deployments -A deployment is said to be counterfactual when the one paying for the deployment fees is the address of the contract to be deployed. In other words, we need to send the funds to the address even when the deployment hasn’t happened. +A deployment is said to be counterfactual when the one paying for the deployment fees is the address of +the contract to be deployed. In other words, we need to send the funds to the address even when the +deploymenthasn’t happened. This process can be described with the following steps: TIP: For testing this flow you can check the {foundry} or the {starkli} guides for deploying accounts. -1. Deterministically precompute the `contract_address` given a `class_hash`, `salt`, and constructor `calldata`. Note that the `class_hash` must be previously declared for the deployment to succeed. +1. Deterministically precompute the `contract_address` given a `class_hash`, `salt`, and constructor `calldata`. +Note that the `class_hash` must be previously declared for the deployment to succeed. -2. Send funds to the `contract_address`. Usually you will estimate the fee of the transaction first. Existing tools usually do this for you. +2. Send funds to the `contract_address`. Usually you will estimate the fee of the transaction first. Existing +tools usually do this for you. 3. Send a `DeployAccount` type transaction to the network. @@ -22,7 +26,8 @@ TIP: For testing this flow you can check the {foundry} or the {starkli} guides f == Deployment validation -For counterfactual deployments, contracts must implement the `\\__validate_deploy__` entrypoint, and it is called by the protocol when a `DeployAccount` transaction is sent to the network. +For counterfactual deployments, contracts must implement the `\\__validate_deploy__` entrypoint, and it is +called by the protocol when a `DeployAccount` transaction is sent to the network. [,javascript] ---- From e809b1f2fc4dc53288c98fd17bd68b1a4185626e Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Tue, 29 Aug 2023 17:31:44 +0200 Subject: [PATCH 13/88] feat: update docs --- docs/modules/ROOT/nav.adoc | 3 +- docs/modules/ROOT/pages/access.adoc | 889 +++++++++--------------- docs/modules/ROOT/pages/api/access.adoc | 445 ++++++++++++ 3 files changed, 765 insertions(+), 572 deletions(-) create mode 100644 docs/modules/ROOT/pages/api/access.adoc diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 47c42f3e6..7f4905d0e 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -22,4 +22,5 @@ ** xref:/guides/deployment.adoc[Counterfactual Deployments] * API -** xref:/api/account.adoc[Account] \ No newline at end of file +** xref:/api/account.adoc[Account] +** xref:/api/access.adoc[Access Control] \ No newline at end of file diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index bc8996b98..c488eb247 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -1,672 +1,419 @@ -:ownable-cairo: link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/access/ownable/library.cairo[Ownable] - +:ownable-cairo: link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/access/ownable/ownable.cairo[Ownable] +:sn_keccak: https://docs.starknet.io/documentation/architecture_and_concepts/Cryptography/hash-functions/#starknet_keccak[sn_keccak] :extensibility-pattern: xref:extensibility.adoc#the_pattern = Access -CAUTION: Expect these modules to evolve. - Access control--that is, "who is allowed to do this thing"--is incredibly important in the world of smart contracts. The access control of your contract may govern who can mint tokens, vote on proposals, freeze transfers, and many other things. -It is therefore critical to understand how you implement it, lest someone else https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7/[steals your whole system]. - -== Table of Contents - -* <> - ** <> - ** <> - ** <> -* <> - ** <> - ** <> - ** <> - ** <> - ** <> +It is therefore critical to understand how you implement it, lest someone else +https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7/[steals your whole system]. -== Ownable +== Ownership and `Ownable` -The most common and basic form of access control is the concept of ownership: there's an account that is the `owner` of a contract and can do administrative tasks on it. +The most common and basic form of access control is the concept of ownership: there's an account that is the `owner` +of a contract and can do administrative tasks on it. This approach is perfectly reasonable for contracts that have a single administrative user. OpenZeppelin Contracts for Cairo provides {ownable-cairo} for implementing ownership in your contracts. -=== Quickstart +=== Usage -Integrating {ownable-cairo} into a contract first requires assigning an owner. -The implementing contract's constructor should set the initial owner by passing the owner's address to Ownable's <> like this: +Integrating this module into a contract first requires assigning an owner. +The implementing contract's constructor should set the initial owner by passing the owner's address to Ownable's +`initializer` like this: -[,cairo] +[,javascript] ---- -from openzeppelin.access.ownable.library import Ownable +use openzeppelin::access::ownable::Ownable; -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}(owner: felt) { - Ownable.initializer(owner); - return (); -} ----- +#[starknet::contract] +mod Contract { + use starknet::ContractAddress; + use super::Ownable; -To restrict a function's access to the owner only, add in the `assert_only_owner` method: + #[storage] + struct Storage {} -[,cairo] ----- -from openzeppelin.access.ownable.library import Ownable + #[constructor] + fn constructor(self: @ContractState, owner: ContractAddress) { + let mut unsafe_state = Ownable::unsafe_new_contract_state(); + Ownable::InternalImpl::initializer(ref unsafe_state, owner); + } -func protected_function{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { - Ownable.assert_only_owner(); - return (); + (...) } ---- -=== Ownable library API +To restrict a function's access to the owner only, add in the `assert_only_owner` method: -[,cairo] +[,javascript] ---- -func initializer(owner: felt) { -} -func assert_only_owner() { -} - -func owner() -> (owner: felt) { -} +use openzeppelin::access::ownable::Ownable; -func transfer_ownership(new_owner: felt) { -} +#[starknet::contract] +mod Contract { + (...) -func renounce_ownership() { -} + #[external(v0)] + fn foo(ref self: ContractState) { + // This function can only be called by the owner + self.assert_only_owner(); -func _transfer_ownership(new_owner: felt) { + (...) + } } ---- -==== `initializer` - -Initializes Ownable access control and should be called in the implementing contract's constructor. -Assigns `owner` as the initial owner address of the contract. - -This must be called only once. - -Parameters: - -[,cairo] ----- -owner: felt ----- - -Returns: None. - -==== `assert_only_owner` - -Reverts if called by any account other than the owner. -In case of renounced ownership, any call from the default zero address will also be reverted. - -Parameters: None. - -Returns: None. - -==== `owner` - -Returns the address of the current owner. - -Parameters: None. - -Returns: - -[,cairo] ----- -owner: felt ----- - -==== `transfer_ownership` - -Transfers ownership of the contract to a new account (`new_owner`). -Can only be called by the current owner. - -Emits a <> event. - -Parameters: - -[,cairo] ----- -new_owner: felt ----- - -Returns: None. +=== Interface -==== `renounce_ownership` +This is the full interface a contract must implement to be compliant with the `Ownable` implementation: -Leaves the contract without owner. -It will not be possible to call functions with `assert_only_owner` anymore. -Can only be called by the current owner. - -Emits a <> event. - -Parameters: None. - -Returns: None. - -[#transfer-ownership-internal] -==== `_transfer_ownership` - -Transfers ownership of the contract to a new account (`new_owner`). {extensibility-pattern}[`internal`] function without access restriction. - -Emits a <> event. - -Parameters: - -[,cairo] ----- -new_owner: felt +[,javascript] ---- +trait IOwnable { + /// Returns the current owner. + fn owner() -> ContractAddress; -Returns: None. + /// Transfers the ownership from the current owner to a new owner. + fn transfer_ownership(new_owner: ContractAddress); -=== Ownable events - -[,cairo] ----- -func OwnershipTransferred(previousOwner: felt, newOwner: felt) { + /// Renounces the ownership of the contract. + fn renounce_ownership(); } ---- -==== OwnershipTransferred +Ownable also lets you: -Emitted when ownership of a contract is transferred from `previousOwner` to `newOwner`. +- `transfer_ownership` from the owner account to a new one, and +- `renounce_ownership` for the owner to relinquish this administrative privilege, a common pattern +after an initial stage with centralized administration is over. -Parameters: - -[,cairo] ----- -previousOwner: felt -newOwner: felt ----- +WARNING: Removing the owner altogether will mean that administrative tasks that are protected by `assert_only_owner` +will no longer be callable! -== AccessControl +== Role-Based `AccessControl` -While the simplicity of ownership can be useful for simple systems or quick prototyping, different levels of authorization are often needed. -You may want for an account to have permission to ban users from a system, but not create new tokens. -https://en.wikipedia.org/wiki/Role-based_access_control[Role-Based Access Control (RBAC)] offers flexibility in this regard. +While the simplicity of ownership can be useful for simple systems or quick prototyping, different levels of +authorization are often needed. You may want for an account to have permission to ban users from a system, but not +create new tokens. https://en.wikipedia.org/wiki/Role-based_access_control[Role-Based Access Control (RBAC)] offers +flexibility in this regard. In essence, we will be defining multiple roles, each allowed to perform different sets of actions. -An account may have, for example, 'moderator', 'minter' or 'admin' roles, which you will then check for instead of simply using <>. -This check can be enforced through <>. +An account may have, for example, 'moderator', 'minter' or 'admin' roles, which you will then check for +instead of simply using `assert_only_owner`. This check can be enforced through `assert_only_role`. Separately, you will be able to define rules for how accounts can be granted a role, have it revoked, and more. -Most software uses access control systems that are role-based: some users are regular users, some may be supervisors or managers, and a few will often have administrative privileges. +Most software uses access control systems that are role-based: some users are regular users, some may be supervisors +or managers, and a few will often have administrative privileges. === Usage -For each role that you want to define, you will create a new _role identifier_ that is used to grant, revoke, and check if an account has that role (see <> for information on creating identifiers). - -Here's a simple example of implementing `AccessControl` on a portion of an link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/src/openzeppelin/token/erc20/presets/ERC20.cairo[ERC20 token contract] which defines and sets the 'minter' role: - -[,cairo] ----- -from openzeppelin.token.erc20.library import ERC20 - -from openzeppelin.access.accesscontrol.library import AccessControl - - -const MINTER_ROLE = 0x4f96f87f6963bb246f2c30526628466840c642dc5c50d5a67777c6cc0e44ab5 - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, decimals: felt, minter: felt -) { - ERC20.initializer(name, symbol, decimals); - AccessControl.initializer(); - AccessControl._grant_role(MINTER_ROLE, minter); - return (); +For each role that you want to define, you will create a new _role identifier_ that is used to grant, revoke, and +check if an account has that role. See xref:#creating_role_identifiers[Creating role identifiers] for information +on creating identifiers. + +Here's a simple example of implementing `AccessControl` on a portion of an ERC20 token contract which defines +and sets a 'minter' role: + +[,javascript] +---- +// sn_keccak('MINTER_ROLE') +const MINTER_ROLE: felt252 = + 0x32df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6; + +#[starknet::contract] +mod Contract { + use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; + use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::token::erc20::ERC20; + use starknet::ContractAddress; + use super::MINTER_ROLE; + + #[storage] + struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + name: felt252, + symbol: felt252, + initial_supply: u256, + recipient: ContractAddress, + minter: ContractAddress + ) { + // ERC20 related initialization + let mut erc20_state = ERC20::unsafe_new_contract_state(); + ERC20::InternalImpl::initializer(ref erc20_state, name, symbol); + ERC20::InternalImpl::_mint(ref erc20_state, recipient, initial_supply); + + // AccessControl related initialization + let mut access_state = AccessControl::unsafe_new_contract_state(); + AccessControl::InternalImpl::initializer(ref access_state); + AccessControl::InternalImpl::_grant_role( + ref access_state, + MINTER_ROLE, + minter + ); + } + + // This function can only be called by a minter + #[external(v0)] + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { + let access_state = AccessControl::unsafe_new_contract_state(); + assert_only_role(@access_state, MINTER_ROLE); + + let mut erc20_state = AccessControl::unsafe_new_contract_state(); + ERC20::InternalImpl::_mint(ref erc20_state, recipient, amount); + } } - -@external -func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, amount: Uint256 -) { - AccessControl.assert_only_role(MINTER_ROLE); - ERC20._mint(to, amount); - return (); -} ----- - -CAUTION: Make sure you fully understand how <> works before using it on your system, or copy-pasting the examples from this guide. - -While clear and explicit, this isn't anything we wouldn't have been able to achieve with <>. -Indeed, where `AccessControl` shines is in scenarios where granular permissions are required, which can be implemented by defining _multiple_ roles. - -Let's augment our ERC20 token example by also defining a 'burner' role, which lets accounts destroy tokens, and by using `assert_only_role`: - -[,cairo] ---- -from openzeppelin.token.erc20.library import ERC20 -from openzeppelin.access.accesscontrol.library import AccessControl - - -const MINTER_ROLE = 0x4f96f87f6963bb246f2c30526628466840c642dc5c50d5a67777c6cc0e44ab5 -const BURNER_ROLE = 0x7823a2d975ffa03bed39c38809ec681dc0ae931ebe0048c321d4a8440aed509 - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, decimals: felt, minter: felt, burner: felt -) { - ERC20.initializer(name, symbol, decimals); - AccessControl.initializer(); - AccessControl._grant_role(MINTER_ROLE, minter); - AccessControl._grant_role(BURNER_ROLE, burner); - return (); -} - -@external -func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, amount: Uint256 -) { - AccessControl.assert_only_role(MINTER_ROLE); - ERC20._mint(to, amount); - return (); -} - -@external -func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, amount: Uint256 -) { - AccessControl.assert_only_role(BURNER_ROLE); - ERC20._burn(from_, amount); - return (); +CAUTION: Make sure you fully understand how xref:api/access.adoc#AccessControl[AccessControl] works before +using it on your system, or copy-pasting the examples from this guide. + +While clear and explicit, this isn't anything we wouldn't have been able to achieve with +xref:api/access.adoc#Ownable[Ownable]. Where `AccessControl` shines is in scenarios where granular +permissions are required, which can be implemented by defining _multiple_ roles. + +Let's augment our ERC20 token example by also defining a 'burner' role, which lets accounts destroy tokens: + +[,javascript] +---- +// sn_keccak('MINTER_ROLE') +const MINTER_ROLE: felt252 = + 0x32df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6; +// sn_keccak('BURNER_ROLE') +const BURNER_ROLE: felt252 = + 0x11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848; + +#[starknet::contract] +mod Contract { + use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; + use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::token::erc20::ERC20; + use starknet::ContractAddress; + use super::{MINTER_ROLE, BURNER_ROLE}; + + #[storage] + struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + name: felt252, + symbol: felt252, + initial_supply: u256, + recipient: ContractAddress, + minter: ContractAddress, + burner: ContractAddress + ) { + // ERC20 related initialization + let mut erc20_state = ERC20::unsafe_new_contract_state(); + ERC20::InternalImpl::initializer(ref erc20_state, name, symbol); + ERC20::InternalImpl::_mint(ref erc20_state, recipient, initial_supply); + + // AccessControl related initialization + let mut access_state = AccessControl::unsafe_new_contract_state(); + AccessControl::InternalImpl::initializer(ref access_state); + AccessControl::InternalImpl::_grant_role( + ref access_state, + MINTER_ROLE, + minter + ); + AccessControl::InternalImpl::_grant_role( + ref access_state, + BURNER_ROLE, + minter + ); + } + + + // This function can only be called by a minter + #[external(v0)] + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { + let access_state = AccessControl::unsafe_new_contract_state(); + assert_only_role(@access_state, MINTER_ROLE); + + let mut erc20_state = AccessControl::unsafe_new_contract_state(); + ERC20::InternalImpl::_mint(ref erc20_state, recipient, amount); + } + + // This function can only be called by a burner + #[external(v0)] + fn burn(ref self: ContractState, account: ContractAddress, amount: u256) { + let access_state = AccessControl::unsafe_new_contract_state(); + assert_only_role(@access_state, BURNER_ROLE); + + let mut erc20_state = AccessControl::unsafe_new_contract_state(); + ERC20::InternalImpl::_burn(ref erc20_state, account, amount); + } } ---- So clean! -By splitting concerns this way, more granular levels of permission may be implemented than were possible with the simpler ownership approach to access control. -Limiting what each component of a system is able to do is known as the https://en.wikipedia.org/wiki/Principle_of_least_privilege[principle of least privilege], and is a good security practice. -Note that each account may still have more than one role, if so desired. +By splitting concerns this way, more granular levels of permission may be implemented than were possible with the +simpler ownership approach to access control. Limiting what each component of a system is able to do is known +as the https://en.wikipedia.org/wiki/Principle_of_least_privilege[principle of least privilege], and is a good +security practice. Note that each account may still have more than one role, if so desired. === Granting and revoking roles -The ERC20 token example above uses `_grant_role`, an {extensibility-pattern}[`internal`] function that is useful when programmatically assigning roles (such as during construction). -But what if we later want to grant the 'minter' role to additional accounts? +The ERC20 token example above uses `_grant_role`, an `internal` function that is useful when programmatically assigning +roles (such as during construction). But what if we later want to grant the 'minter' role to additional accounts? -By default, *accounts with a role cannot grant it or revoke it from other accounts*: all having a role does is making the `assert_only_role` check pass. -To grant and revoke roles dynamically, you will need help from the role's _admin_. +By default, *accounts with a role cannot grant it or revoke it from other accounts*: all having a role does is making +the `assert_only_role` check pass. To grant and revoke roles dynamically, you will need help from the role's _admin_. Every role has an associated admin role, which grants permission to call the `grant_role` and `revoke_role` functions. A role can be granted or revoked by using these if the calling account has the corresponding admin role. Multiple roles may have the same admin role to make management easier. -A role's admin can even be the same role itself, which would cause accounts with that role to be able to also grant and revoke it. +A role's admin can even be the same role itself, which would cause accounts with that role to be able +to also grant and revoke it. -This mechanism can be used to create complex permissioning structures resembling organizational charts, but it also provides an easy way to manage simpler applications. -`AccessControl` includes a special role with the role identifier of `0`, called `DEFAULT_ADMIN_ROLE`, which acts as the *default admin role for all roles*. +This mechanism can be used to create complex permissioning structures resembling organizational charts, but it also +provides an easy way to manage simpler applications. `AccessControl` includes a special role with the role identifier +of `0`, called `DEFAULT_ADMIN_ROLE`, which acts as the *default admin role for all roles*. An account with this role will be able to manage any other role, unless `_set_role_admin` is used to select a new admin role. Let's take a look at the ERC20 token example, this time taking advantage of the default admin role: -[,cairo] ----- -from openzeppelin.token.erc20.library import ERC20 - -from openzeppelin.access.accesscontrol.library import AccessControl - -from openzeppelin.utils.constants import DEFAULT_ADMIN_ROLE - - -const MINTER_ROLE = 0x4f96f87f6963bb246f2c30526628466840c642dc5c50d5a67777c6cc0e44ab5 -const BURNER_ROLE = 0x7823a2d975ffa03bed39c38809ec681dc0ae931ebe0048c321d4a8440aed509 - -@constructor -func constructor{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - name: felt, symbol: felt, decimals: felt, admin: felt, -) { - ERC20.initializer(name, symbol, decimals); - AccessControl.initializer(); - - AccessControl._grant_role(DEFAULT_ADMIN_ROLE, admin); - return (); -} - -@external -func mint{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - to: felt, amount: Uint256 -) { - AccessControl.assert_only_role(MINTER_ROLE); - ERC20._mint(to, amount); - return (); -} - -@external -func burn{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}( - from_: felt, amount: Uint256 -) { - AccessControl.assert_only_role(BURNER_ROLE); - ERC20._burn(from_, amount); - return (); +[,javascript] +---- +// sn_keccak('MINTER_ROLE') +const MINTER_ROLE: felt252 = + 0x32df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6; +// sn_keccak('BURNER_ROLE') +const BURNER_ROLE: felt252 = + 0x11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848; + +#[starknet::contract] +mod Contract { + use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; + use openzeppelin::access::accesscontrol::AccessControl; + use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; + use openzeppelin::token::erc20::ERC20; + use starknet::ContractAddress; + use super::{MINTER_ROLE, BURNER_ROLE}; + + #[storage] + struct Storage {} + + #[constructor] + fn constructor( + ref self: ContractState, + name: felt252, + symbol: felt252, + initial_supply: u256, + recipient: ContractAddress, + admin: ContractAddress + ) { + // ERC20 related initialization + let mut erc20_state = ERC20::unsafe_new_contract_state(); + ERC20::InternalImpl::initializer(ref erc20_state, name, symbol); + ERC20::InternalImpl::_mint(ref erc20_state, recipient, initial_supply); + + // AccessControl related initialization + let mut access_state = AccessControl::unsafe_new_contract_state(); + AccessControl::InternalImpl::initializer(ref access_state); + AccessControl::InternalImpl::_grant_role( + ref access_state, + DEFAULT_ADMIN_ROLE, + admin + ); + } + + // This function can only be called by a minter + #[external(v0)] + fn mint(ref self: ContractState, recipient: ContractAddress, amount: u256) { + let access_state = AccessControl::unsafe_new_contract_state(); + assert_only_role(@access_state, MINTER_ROLE); + + let mut erc20_state = AccessControl::unsafe_new_contract_state(); + ERC20::InternalImpl::_mint(ref erc20_state, recipient, amount); + } + + // This function can only be called by a burner + #[external(v0)] + fn burn(ref self: ContractState, account: ContractAddress, amount: u256) { + let access_state = AccessControl::unsafe_new_contract_state(); + assert_only_role(@access_state, BURNER_ROLE); + + let mut erc20_state = AccessControl::unsafe_new_contract_state(); + ERC20::InternalImpl::_burn(ref erc20_state, account, amount); + } + + // These function can only be called by the roles' admin + #[external(v0)] + fn grant_role(ref self: ContractState, role: felt252, account: ContractAddress) { + let mut unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControl::AccessControlImpl::grant_role(ref unsafe_state, role, account); + } + #[external(v0)] + fn revoke_role(ref self: ContractState, role: felt252, account: ContractAddress) { + let mut unsafe_state = AccessControl::unsafe_new_contract_state(); + AccessControl::AccessControlImpl::revoke_role(ref unsafe_state, role, account); + } } ---- Note that, unlike the previous examples, no accounts are granted the 'minter' or 'burner' roles. -However, because those roles' admin role is the default admin role, and that role was granted to the 'admin', that same account can call `grant_role` to give minting or burning permission, and `revoke_role` to remove it. +However, because those roles' admin role is the default admin role, and that role was granted to the 'admin', that +same account can call `grant_role` to give minting or burning permission, and `revoke_role` to remove it. -Dynamic role allocation is often a desirable property, for example in systems where trust in a participant may vary over time. -It can also be used to support use cases such as https://en.wikipedia.org/wiki/Know_your_customer[KYC], where the list of role-bearers may not be known up-front, or may be prohibitively expensive to include in a single transaction. - -The following example uses the link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/tests/mocks/AccessControl.cairo[AccessControl mock contract] which exposes the role management functions. -To grant and revoke roles in Python, for example: - -[,python] ----- -MINTER_ROLE = 0x4f96f87f6963bb246f2c30526628466840c642dc5c50d5a67777c6cc0e44ab5 -BURNER_ROLE = 0x7823a2d975ffa03bed39c38809ec681dc0ae931ebe0048c321d4a8440aed509 - -# grants MINTER_ROLE and BURNER_ROLE to account1 and account2 respectively -await signer.send_transactions( - admin, [ - (accesscontrol.contract_address, 'grantRole', [MINTER_ROLE, account1.contract_address]), - (accesscontrol.contract_address, 'grantRole', [BURNER_ROLE, account2.contract_address]) - ] -) - -# revokes MINTER_ROLE from account1 -await signer.send_transaction( - admin, - accesscontrol.contract_address, - 'revokeRole', - [MINTER_ROLE, account1.contract_address] -) ----- +Dynamic role allocation is often a desirable property, for example in systems where trust in a participant may vary +over time. It can also be used to support use cases such as https://en.wikipedia.org/wiki/Know_your_customer[KYC], +where the list of role-bearers may not be known up-front, or may be prohibitively expensive to include in a single transaction. === Creating role identifiers -In the Solidity implementation of AccessControl, contracts generally refer to the https://docs.soliditylang.org/en/latest/units-and-global-variables.html?highlight=keccak256#mathematical-and-cryptographic-functions[keccak256 hash] of a role as the role identifier. +In the Solidity implementation of AccessControl, contracts generally refer to the +https://docs.soliditylang.org/en/latest/units-and-global-variables.html?highlight=keccak256#mathematical-and-cryptographic-functions[keccak256 hash] +of a role as the role identifier. + For example: -[,solidity] +[,javascript] ---- bytes32 public constant SOME_ROLE = keccak256("SOME_ROLE") ---- These identifiers take up 32 bytes (256 bits). -Cairo field elements store a maximum of 252 bits. -Even further, a declared _constant_ field element in a StarkNet contract stores even less (see https://github.com/starkware-libs/cairo-lang/blob/release-v0.6.1/src/starkware/cairo/lang/cairo_constants.py#L1[cairo_constants]). +Cairo field elements (`felt252`) store a maximum of 252 bits. With this discrepancy, this library maintains an agnostic stance on how contracts should create identifiers. Some ideas to consider: -* Use the first or last 251 bits of keccak256 hash digests. -* Use Cairo's https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/cairo/common/hash.cairo[hash2]. - -=== AccessControl library API - -[,cairo] ----- -func initializer() { -} - -func assert_only_role(role: felt) { -} - -func has_role(role: felt, user: felt) -> (has_role: felt) { -} - -func get_role_admin(role: felt) -> (admin: felt) { -} - -func grant_role(role: felt, user: felt) { -} +* Use the {sn_keccak} instead. +* Use Cairo friendly hashing algorithms like Poseidon, which are implemented in the +https://github.com/starkware-libs/cairo/blob/main/corelib/src/poseidon.cairo[Cairo corelib]. -func revoke_role(role: felt, user: felt) { -} - -func renounce_role(role: felt, user: felt) { -} +=== Interface -func _grant_role(role: felt, user: felt) { -} +This is the full interface a contract must implement to be compliant with the `AccessControl` implementation: -func _revoke_role(role: felt, user: felt) { -} - -func _set_role_admin(role: felt, admin_role: felt) { -} +[,javascript] ---- +trait IAccessControl { + /// Returns whether the account has the role or not. + fn has_role(role: felt252, account: ContractAddress) -> bool; -[#initializer-accesscontrol] -==== `initializer` + /// Returns the adming role that controls `role`. + fn get_role_admin(role: felt252) -> felt252; -Initializes AccessControl and should be called in the implementing contract's constructor. + /// Grants `role` to `account`. + fn grant_role(role: felt252, account: ContractAddress); -This must only be called once. + /// Revokes `role` from `account`. + fn revoke_role(role: felt252, account: ContractAddress); -Parameters: None. - -Returns: None. - -==== `assert_only_role` - -Checks that an account has a specific role. -Reverts with a message including the required role. - -Parameters: - -[,cairo] ----- -role: felt ----- - -Returns: None. - -==== has_role - -Returns `TRUE` if `user` has been granted `role`, `FALSE` otherwise. - -Parameters: - -[,cairo] ----- -role: felt -user: felt ----- - -Returns: - -[,cairo] ----- -has_role: felt ----- - -==== `get_role_admin` - -Returns the admin role that controls `role`. -See <> and <>. - -To change a role's admin, use <>. - -Parameters: - -[,cairo] ----- -role: felt ----- - -Returns: - -[,cairo] ----- -admin: felt ----- - -==== `grant_role` - -Grants `role` to `user`. - -If `user` had not been already granted `role`, emits a <> event. - -Requirements: - -* The caller must have ``role``'s admin role. - -Parameters: - -[,cairo] ----- -role: felt -user: felt ----- - -Returns: None. - -==== `revoke_role` - -Revokes `role` from `user`. - -If `user` had been granted `role`, emits a <> event. - -Requirements: - -* The caller must have ``role``'s admin role. - -Parameters: - -[,cairo] ----- -role: felt -user: felt ----- - -Returns: None. - -==== `renounce_role` - -Revokes `role` from the calling `user`. - -Roles are often managed via <> and <>: this function's purpose is to provide a mechanism for accounts to lose their privileges if they are compromised (such as when a trusted device is misplaced). - -If the calling `user` had been revoked `role`, emits a <> event. - -Requirements: - -* The caller must be `user`. - -Parameters: - -[,cairo] ----- -role: felt -user: felt ----- - -Returns: None. - -[#grantrole-internal] -==== `_grant_role` - -Grants `role` to `user`. - -{extensibility-pattern}[`internal`] function without access restriction. - -Emits a <> event. - -Parameters: - -[,cairo] ----- -role: felt -user: felt ----- - -Returns: None. - -[#revokerole-internal] -==== `_revoke_role` - -Revokes `role` from `user`. - -{extensibility-pattern}[`internal`] function without access restriction. - -Emits a <> event. - -Parameters: - -[,cairo] ----- -role: felt -user: felt ----- - -Returns: None. - -[#setroleadmin] -==== `_set_role_admin` - -{extensibility-pattern}[`internal`] function that sets `admin_role` as ``role``'s admin role. - -Emits a <> event. - -Parameters: - -[,cairo] ----- -role: felt -admin_role: felt ----- - -Returns: None. - -=== AccessControl events - -[,cairo] ----- -func RoleGranted(role: felt, account: felt, sender: felt) { -} - -func RoleRevoked(role: felt, account: felt, sender: felt) { -} - -func RoleAdminChanged(role: felt, previousAdminRole: felt, newAdminRole: felt) { + /// Revokes `role` from self. + fn renounce_role(role: felt252, account: ContractAddress); } ---- -==== `RoleGranted` - -Emitted when `account` is granted `role`. - -`sender` is the account that originated the contract call, an admin role bearer. +AccessControl also lets you: -Parameters: - -[,cairo] ----- -role: felt -account: felt -sender: felt ----- - -==== `RoleRevoked` - -Emitted when account is revoked role. - -`sender` is the account that originated the contract call: - -* If using <>, it is the admin role bearer. -* If using <>, it is the role bearer (i.e. -`account`). - -[,cairo] ----- -role: felt -account: felt -sender: felt ----- - -==== `RoleAdminChanged` - -Emitted when `newAdminRole` is set as ``role``'s admin role, replacing `previousAdminRole`. - -`DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite `RoleAdminChanged` not being emitted signaling this. - -[,cairo] ----- -role: felt -previousAdminRole: felt -newAdminRole: felt ----- +- `renounce_role` from the calling account. The method expects an account as input as an extra security measure, to +ensure you are not renuncing a role from an unintended account. diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc new file mode 100644 index 000000000..d6c441d51 --- /dev/null +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -0,0 +1,445 @@ +:github-icon: pass:[] +:AccessControl: xref:AccessControl[AccessControl] +:Ownable: xref:Ownable[Ownable] + += Access Control + +[.readme-notice] +NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/api/access + +This directory provides ways to restrict who can access the functions of a contract or when they can do it. + +- {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and +assigned each to multiple accounts. +- {Ownable} is a simpler mechanism with a single owner "role" that can be assigned to a single account. +This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. + +== Authorization + +[.contract] +[[Ownable]] +=== `++Ownable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/access/ownable/ownable.cairo[{github-icon},role=heading-link] + +[.hljs-theme-light.nopadding] +```javascript +use openzeppelin::access::ownable::Ownable; +``` + +Contract module which provides a basic access control mechanism, where +there is an account (an owner) that can be granted exclusive access to +specific functions. + +This module provides an internal utility named `assert_only_owner`, which can be applied to your functions +to restrict their use to the owner. + +[.contract-index] +.Utilities +-- +* xref:Ownable-assert_only_owner[`++InternalImpl::assert_only_owner(self: @ContractState)++`] +-- + +[.contract-index] +.Functions +-- +[.contract-subindex-inherited] +.InternalImpl + +* xref:Ownable-initializer[`++initializer(ref self: ContractState, owner: ContractAddress)++`] +* xref:Ownable-_transfer_ownership[`++_transfer_ownership(ref self: ContractState, new_owner: ContractAddress)++`] + +[.contract-subindex-inherited] +.OwnableImpl + +* xref:Ownable-owner[`++owner(self: @ContractState)++`] +* xref:Ownable-renounce_ownership[`++renounce_ownership(ref self: ContractState)++`] +* xref:Ownable-transfer_ownership[`++transfer_ownership(ref self: ContractState, new_owner: ContractAddress)++`] + +-- + +[.contract-index] +.Events +-- +* xref:Ownable-OwnershipTransferred[`++OwnershipTransferred(previous_owner, new_owner)++`] +-- + +[.contract-item] +[[Ownable-assert_only_owner]] +==== `[.contract-item-name]#++assert_only_owner++#++(self: @ContractState)++` [.item-kind]#internal# + +Throws if called by any account other than the owner. + +[.contract-item] +[[Ownable-initializer]] +==== `[.contract-item-name]#++initializer++#++(ref self: ContractState, owner: ContractAddress)++` [.item-kind]#internal# + +Initializes the contract setting `owner` as the initial owner. + +Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. + +[.contract-item] +[[Ownable-_transfer_ownership]] +==== `[.contract-item-name]#++_transfer_ownership++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#internal# + +Transfers ownership of the contract to a new account (`new_owner`). +Internal function without access restriction. + +Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. + +[.contract-item] +[[Ownable-owner]] +==== `[.contract-item-name]#++owner++#++(self: @ContractState) → ContractAddress++` [.item-kind]#external# + +Returns the address of the current owner. + +[.contract-item] +[[Ownable-renounce_ownership--]] +==== `[.contract-item-name]#++renounce_ownership++#++(ref self: ContractState)++` [.item-kind]#external# + +Leaves the contract without owner. It will not be possible to call +`assert_only_owner` functions anymore. Can only be called by the current owner. + +NOTE: Renouncing ownership will leave the contract without an owner, +thereby removing any functionality that is only available to the owner. + +[.contract-item] +[[Ownable-transfer_ownership]] +==== `[.contract-item-name]#++transfer_ownership++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#external# + +Transfers ownership of the contract to a new account (`new_owner`). +Can only be called by the current owner. + +Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. + +[.contract-item] +[[Ownable-OwnershipTransferred]] +==== `[.contract-item-name]#++OwnershipTransferred++#++(previous_owner: ContractAddress, new_owner: ContractAddress)++` [.item-kind]#event# + +Emitted when the ownership is transferred. + +[.contract] +[[IAccessControl]] +=== `++IAccessControl++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/05429e4fd34a250ce7a01450190c53275e5c1c0b/src/access/accesscontrol/interface.cairo#L10[{github-icon},role=heading-link] + +:grant_role: xref:#IAccessControl-grant_role[grant_role] +:revoke_role: xref:#IAccessControl-revoke_role[revoke_role] +:RoleGranted: xref:#IAccessControl-RoleGranted[RoleGranted] +:RoleRevoked: xref:#IAccessControl-RoleRevoked[RoleRevoked] +:RoleAdminChanged: xref:#IAccessControl-RoleAdminChanged[RoleAdminChanged] + +[.hljs-theme-light.nopadding] +```javascript +use openzeppelin::access::accesscontrol::interface::IAccessControl; +``` + +External interface of AccessControl declared to support https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md[SRC5] detection. + +[.contract-index] +.Functions +-- +* xref:IAccessControl-has_role[`++has_role(role: felt252, account: ContractAddress)++`] +* xref:IAccessControl-get_role_admin[`++get_role_admin(role: felt252)++`] +* xref:IAccessControl-grant_role[`++grant_role(role: felt252, account: ContractAddress)++`] +* xref:IAccessControl-revoke_role[`++revoke_role(role: felt252, account: ContractAddress)++`] +* xref:IAccessControl-renounce_role[`++renounce_role(role: felt252, account: ContractAddress)++`] + +-- + +[.contract-index] +.Events +-- +* xref:IAccessControl-RoleAdminChanged[`++RoleAdminChanged(role, previous_admin_role, new_admin_role)++`] +* xref:IAccessControl-RoleGranted[`++RoleGranted(role, account, sender)++`] +* xref:IAccessControl-RoleRevoked[`++RoleRevoked(role, account, sender)++`] + +-- + +[.contract-item] +[[IAccessControl-has_role]] +==== `[.contract-item-name]#++has_role++#++(role: felt252, account: ContractAddress) → bool++` [.item-kind]#external# + +Returns `true` if `account` has been granted `role`. + +[.contract-item] +[[IAccessControl-get_role_admin]] +==== `[.contract-item-name]#++get_role_admin++#++(role: felt252) → felt252++` [.item-kind]#external# + +Returns the admin role that controls `role`. See {grant_role} and +{revoke_role}. + +To change a role's admin, use {AccessControl-_setRoleAdmin}. + +[.contract-item] +[[IAccessControl-grant_role]] +==== `[.contract-item-name]#++grant_role++#++(role: felt252, account: ContractAddress)++` [.item-kind]#external# + +Grants `role` to `account`. + +If `account` had not been already granted `role`, emits a {RoleGranted} +event. + +Requirements: + +- the caller must have ``role``'s admin role. + +[.contract-item] +[[IAccessControl-revoke_role]] +==== `[.contract-item-name]#++revoke_role++#++(role: felt252, account: ContractAddress)++` [.item-kind]#external# + +Revokes `role` from `account`. + +If `account` had been granted `role`, emits a {RoleRevoked} event. + +Requirements: + +- the caller must have ``role``'s admin role. + +[.contract-item] +[[IAccessControl-renounce_role]] +==== `[.contract-item-name]#++renounce_role++#++(role: felt252, account: ContractAddress)++` [.item-kind]#external# + +Revokes `role` from the calling account. + +Roles are often managed via {grant_role} and {revoke_role}. This function's +purpose is to provide a mechanism for accounts to lose their privileges +if they are compromised (such as when a trusted device is misplaced). + +If the calling account had been granted `role`, emits a {RoleRevoked} +event. + +Requirements: + +- the caller must be `account`. + + +[.contract-item] +[[IAccessControl-RoleAdminChanged]] +==== `[.contract-item-name]#++RoleAdminChanged++#++(role: felt252, previous_admin_role: ContractAddress, new_admin_role: ContractAddress)++` [.item-kind]#event# + +Emitted when `new_admin_role` is set as ``role``'s admin role, replacing `previous_admin_role` + +`DEFAULT_ADMIN_ROLE` is the starting admin for all roles, despite +{RoleAdminChanged} not being emitted signaling this. + +[.contract-item] +[[IAccessControl-RoleGranted]] +==== `[.contract-item-name]#++RoleGranted++#++(role: felt252, account: ContractAddress, sender: ContractAddress)++` [.item-kind]#event# + +Emitted when `account` is granted `role`. + +`sender` is the account that originated the contract call, an admin role +bearer. + +[.contract-item] +[[IAccessControl-RoleRevoked]] +==== `[.contract-item-name]#++RoleRevoked++#++(role: felt252, account: ContractAddress, sender: ContractAddress)++` [.item-kind]#event# + +Emitted when `account` is revoked `role`. + +`sender` is the account that originated the contract call: + +- if using `revoke_role`, it is the admin role bearer. +- if using `renounce_role`, it is the role bearer (i.e. `account`). + +[.contract] +[[AccessControl]] +=== `++AccessControl++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/access/accesscontrol/accesscontrol.cairo[{github-icon},role=heading-link] + +:assert_only_role: xref:#AccessControl-assert_only_role +:grant_role: xref:#AccessControl-grant_role[grant_role] +:revoke_role: xref:#AccessControl-revoke_role[revoke_role] +:set_role_admin: xref:#AccessControl-set_role_admin[set_role_admin] + +[.hljs-theme-light.nopadding] +```javascript +use openzeppelin::access::accesscontrol::AccessControl; +``` + +Contract module that allows children to implement role-based access control mechanisms. +Roles are referred to by their `felt252` identifier: + +```javascript +// sn_keccak('MY_ROLE') +const MY_ROLE: felt252 = + 0x3c877e40edb41710f0baf588c878ee15a04499b06ae8c98cf488875d91a7213; +``` + +Roles can be used to represent a set of permissions. To restrict access to a +function call, use {assert_only_role}[`assert_only_role`]: + +```javascript +use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; +use openzeppelin::access::accesscontrol::AccessControl; +use openzeppelin::token::erc20::ERC20; + +#[external(v0)] +fn foo(ref self: ContractState, account: ContractAddress, amount: u256) { + let access_state = AccessControl::unsafe_new_contract_state(); + assert_only_role(@access_state, BURNER_ROLE); + + let mut erc20_state = ERC20::unsafe_new_contract_state(); + ERC20::InternalImpl::_burn(ref erc20_state, account, amount); +} +``` + +Roles can be granted and revoked dynamically via the {grant_role} and +{revoke_role} functions. Each role has an associated admin role, and only +accounts that have a role's admin role can call {grant_role} and {revoke_role}. + +By default, the admin role for all roles is `DEFAULT_ADMIN_ROLE`, which means +that only accounts with this role will be able to grant or revoke other +roles. More complex role relationships can be created by using +{_set_role_admin}. + +WARNING: The `DEFAULT_ADMIN_ROLE` is also its own admin: it has permission to +grant and revoke this role. Extra precautions should be taken to secure +accounts that have been granted it. + +[.contract-index] +.Utilities +-- +* xref:#AccessControl-assert_only_role[`++InternalImpl::assert_only_role(self: @ContractState, role: felt252)++`] +-- + +[.contract-index] +.Functions +-- +[.contract-subindex-inherited] +.InternalImpl + +* xref:#AccessControl-initializer[`++initializer(ref self: ContractState)++`] +* xref:#AccessControl-_set_role_admin[`++_set_role_admin(ref self: ContractState, role: felt252, admin_role: felt252)++`] +* xref:#AccessControl-_grant_role[`++_grant_role(ref self: ContractState, role: felt252, account: ContractAddress)++`] +* xref:#AccessControl-_revoke_role[`++_revoke_role(ref self: ContractState, role: felt252, account: ContractAddress)++`] + +[.contract-subindex-inherited] +.AccessControlImpl + +* xref:#AccessControl-has_role[`++has_role(self: @ContractState, role: felt252, account: ContractAddress)++`] +* xref:#AccessControl-get_role_admin[`++get_role_admin(self: @ContractState, role: felt252)++`] +* xref:#AccessControl-grant_role[`++grant_role(ref self: ContractState, role: felt252, account: ContractAddress)++`] +* xref:#AccessControl-revoke_role[`++revoke_role(ref self: ContractState, role: felt252, account: ContractAddress)++`] +* xref:#AccessControl-renounce_role[`++renounce_role(ref self: ContractState, role: felt252, account: ContractAddress)++`] + +[.contract-subindex-inherited] +.SRC5Impl +* xref:#AccessControl-supports_interface[`++supports_interface(self: @ContractState, interface_id: felt252)++`] +-- + +[.contract-index] +.Events +-- +[.contract-subindex-inherited] +.IAccessControl +* xref:#IAccessControl-RoleAdminChanged[`++RoleAdminChanged(role, previous_admin_role, new_admin_role)++`] +* xref:#IAccessControl-RoleGranted[`++RoleGranted(role, account, sender)++`] +* xref:#IAccessControl-RoleRevoked[`++RoleRevoked(role, account, sender)++`] +-- + +[.contract-item] +[[AccessControl-assert_only_role]] +==== `[.contract-item-name]#++assert_only_role++#++(self: @ContractState, role: felt252)++` [.item-kind]#internal# + +Throws if called by any account without the given `role`. + +[.contract-item] +[[AccessControl-initializer]] +==== `[.contract-item-name]#++initializer++#++(ref self: ContractState)++` [.item-kind]#internal# + +Initializes the contract by registering the IAccessControl interface ID. + +[.contract-item] +[[AccessControl-_set_role_admin]] +==== `[.contract-item-name]#++_set_role_admin++#++(ref self: ContractState, role: felt252, admin_role: felt252)++` [.item-kind]#internal# + +Sets `adminRole` as ``role``'s admin role. + +Emits a {RoleAdminChanged} event. + +[.contract-item] +[[AccessControl-_grant_role]] +==== `[.contract-item-name]#++_grant_role++#++(ref self: ContractState, role: felt252, account: ContractState)++` [.item-kind]#internal# + +Grants `role` to `account`. + +Internal function without access restriction. + +May emit a {RoleGranted} event. + +[.contract-item] +[[AccessControl-_revoke_role]] +==== `[.contract-item-name]#++_revoke_role++#++(ref self: ContractState, role: felt252, account: ContractState)++` [.item-kind]#internal# + +Revokes `role` from `account`. + +Internal function without access restriction. + +May emit a {RoleRevoked} event. + +[.contract-item] +[[AccessControl-has_role]] +==== `[.contract-item-name]#++has_role++#++(self: @ContractState, role: felt252, account: ContractAddress) → bool++` [.item-kind]#external# + +Returns `true` if `account` has been granted `role`. + +[.contract-item] +[[AccessControl-get_role_admin]] +==== `[.contract-item-name]#++get_role_admin++#++(self: @ContractState, role: felt252) → felt252++` [.item-kind]#external# + +Returns the admin role that controls `role`. See {grant_role} and +{revoke_role}. + +To change a role's admin, use {_setRoleAdmin}. + +[.contract-item] +[[AccessControl-grant_role_]] +==== `[.contract-item-name]#++grant_role++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#external# + +Grants `role` to `account`. + +If `account` had not been already granted `role`, emits a {RoleGranted} +event. + +Requirements: + +- the caller must have ``role``'s admin role. + +May emit a {RoleGranted} event. + +[.contract-item] +[[AccessControl-revoke_role]] +==== `[.contract-item-name]#++revoke_role++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#external# + +Revokes `role` from `account`. + +If `account` had been granted `role`, emits a {RoleRevoked} event. + +Requirements: + +- the caller must have ``role``'s admin role. + +May emit a {RoleRevoked} event. + +[.contract-item] +[[AccessControl-renounce_role]] +==== `[.contract-item-name]#++renounce_role++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#external# + +Revokes `role` from the calling account. + +Roles are often managed via {grant_role} and {revoke_role}. This function's +purpose is to provide a mechanism for accounts to lose their privileges +if they are compromised (such as when a trusted device is misplaced). + +If the calling account had been revoked `role`, emits a {RoleRevoked} +event. + +Requirements: + +- the caller must be `account`. + +May emit a {RoleRevoked} event. + +[.contract-item] +[[AccessControl-supports_interface]] +==== `[.contract-item-name]#++supports_interface++#++(self: @ContractState, interface_id: felt252) → bool++` [.item-kind]#external# + +Returns whether a contract implements a given interface or not. From 2c3b73414867b7e99e267e1293abd1f52192c36d Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 30 Aug 2023 14:08:04 +0200 Subject: [PATCH 14/88] feat: update docs --- docs/modules/ROOT/nav.adoc | 5 +- docs/modules/ROOT/pages/api/account.adoc | 115 +++++++++++++++++------ 2 files changed, 86 insertions(+), 34 deletions(-) diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 47c42f3e6..d2b13623b 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -4,6 +4,8 @@ * xref:proxies.adoc[Proxies and Upgrades] * xref:accounts.adoc[Accounts] +** xref:/guides/deployment.adoc[Counterfactual Deployments] + * xref:access.adoc[Access Control] * Tokens @@ -18,8 +20,5 @@ * xref:contracts::index.adoc[Contracts for Solidity] -* Guides -** xref:/guides/deployment.adoc[Counterfactual Deployments] - * API ** xref:/api/account.adoc[Account] \ No newline at end of file diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 224edf7b2..db7a14d8d 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -5,8 +5,6 @@ Reference of interfaces, presets, and utilities related to Account contracts. -TIP: For an overview of Accounts, read our xref:accounts.adoc[Accounts guide]. - == Core [.contract] @@ -57,33 +55,56 @@ Returns the short string `'VALID'` if valid, or any other value otherwise. [[Account]] === `++Account++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/account/account.cairo#L27[{github-icon},role=heading-link] +:OwnerAdded: xref:Account-OwnerAdded[OwnerAdded] +:OwnerRemoved: xref:Account-OwnerRemoved[OwnerRemoved] + [.hljs-theme-light.nopadding] ```javascript use openzeppelin::account::Account; ``` - Base Account contract implementation. +[.contract-index] +.Utilities +-- +* xref:#Account-assert_only_self[`++InternalImpl::assert_only_self(self)++`] +-- [.contract-index] .Functions -- -* xref:#Account-\\__validate_declare__[`++__validate_declare__(class_hash)++`] -* xref:#Account-\\__validate_deploy__[`++__validate_deploy__(hash, signature)++`] -* xref:#Account-set_public_key[`++set_public_key(new_public_key)++`] -* xref:#Account-get_public_key[`++get_public_key()++`] +* xref:#Account-\\__validate_deploy__[`++__validate_deploy__(self, hash, signature)++`] + +[.contract-subindex-inherited] +.SRC6Impl + +* xref:#Account-\\__execute__[`++__execute__(self, calls)++`] +* xref:#Account-\\__validate__[`++__validate__(self, calls)++`] +* xref:#Account-is_valid_signature[`++is_valid_signature(self, hash, signature)++`] + +[.contract-subindex-inherited] +.SRC5Impl + +* xref:#Account-supports_interface[`++supports_interface(self, interface_id)++`] + +[.contract-subindex-inherited] +.DeclarerImpl + +* xref:#Account-\\__validate_declare__[`++__validate_declare__(self, class_hash)++`] [.contract-subindex-inherited] -.ISRC6 +.PublicKeyImpl -* xref:#Account-\\__execute__[`++__execute__(calls)++`] -* xref:#Account-\\__validate__[`++__validate__(calls)++`] -* xref:#Account-is_valid_signature[`++is_valid_signature(hash, signature)++`] +* xref:#Account-set_public_key[`++set_public_key(self, new_public_key)++`] +* xref:#Account-get_public_key[`++get_public_key(self)++`] [.contract-subindex-inherited] -.ISRC5 +.InternalImpl -* xref:#Account-supports_interface[`++supports_interface(interface_id)++`] +* xref:#Account-initializer[`++initializer(self, _public_key)++`] +* xref:#Account-validate_transaction[`++validate_transaction(self)++`] +* xref:#Account-_set_public_key[`++_set_public_key(self, new_public_key)++`] +* xref:#Account-_is_valid_signature[`++_is_valid_signature(self, hash, signature)++`] -- [.contract-index] @@ -93,59 +114,91 @@ Base Account contract implementation. * xref:#Account-OwnerRemoved[`++OwnerRemoved(removed_owner_guid)++`] -- +[.contract-item] +[[Account-__validate_deploy__]] +==== `[.contract-item-name]#++__validate_deploy__++#++(self: @ContractState, class_hash: felt252, contract_address_salt: felt252, _public_key: felt252) → felt252++` [.item-kind]#external# + +Validates a DeployAccount transaction. + +Returns the short string `'VALID'` if valid, or any other value otherwise. + [.contract-item] [[Account-__execute__]] -==== `[.contract-item-name]#++__execute__++#++(calls: Array) → Array>++` [.item-kind]#external# +==== `[.contract-item-name]#++__execute__++#++(ref self: ContractState, calls: Array) → Array>++` [.item-kind]#external# See xref:ISRC6-\\__execute__[ISRC6::\\__execute__]. [.contract-item] [[Account-__validate__]] -==== `[.contract-item-name]#++__validate__++#++(calls: Array) → felt252++` [.item-kind]#external# +==== `[.contract-item-name]#++__validate__++#++(self: @ContractState, calls: Array) → felt252++` [.item-kind]#external# See xref:ISRC6-\\__validate__[ISRC6::\\__validate__]. [.contract-item] -[[Account-__validate_declare__]] -==== `[.contract-item-name]#++__validate_declare__++#++(class_hash: felt252) → felt252++` [.item-kind]#external# +[[Account-is_valid_signature]] +==== `[.contract-item-name]#++is_valid_signature++#++(self: @ContractState, hash: felt252, signature: Array) → felt252++` [.item-kind]#external# -Validates a Declare transaction. +See xref:ISRC6-is_valid_signature[ISRC6::is_valid_signature]. -Returns the short string `'VALID'` if valid, or any other value otherwise. +[.contract-item] +[[Account-supports_interface]] +==== `[.contract-item-name]#++supports_interface++#++(self: @ContractState, interface_id: felt252) → bool++` [.item-kind]#external# + +Returns whether a contract implements a given interface or not. [.contract-item] -[[Account-__validate_deploy__]] -==== `[.contract-item-name]#++__validate_deploy__++#++(class_hash: felt252, contract_address_salt: felt252, _public_key: felt252) → felt252++` [.item-kind]#external# +[[Account-__validate_declare__]] +==== `[.contract-item-name]#++__validate_declare__++#++(self: @ContractState, class_hash: felt252) → felt252++` [.item-kind]#external# -Validates a DeployAccount transaction. +Validates a Declare transaction. Returns the short string `'VALID'` if valid, or any other value otherwise. [.contract-item] [[Account-set_public_key]] -==== `[.contract-item-name]#++set_public_key++#++(new_public_key: felt252)++` [.item-kind]#external# +==== `[.contract-item-name]#++set_public_key++#++(ref self: ContractState, new_public_key: felt252)++` [.item-kind]#external# Sets a new public key for the account. Can be called only by self through the `\\__execute__` mechanism. -Emits an xref:Account-OwnerRemoved[OwnerRemoved], and an xref:Account-OwnerAdded[OwnerAdded] event. +Emits an {OwnerRemoved}, and an {OwnerAdded} event. [.contract-item] [[Account-get_public_key]] -==== `[.contract-item-name]#++get_public_key++#++()++ → felt252` [.item-kind]#external# +==== `[.contract-item-name]#++get_public_key++#++(self: @ContractState)++ → felt252` [.item-kind]#external# Returns the current public key of the account. [.contract-item] -[[Account-is_valid_signature]] -==== `[.contract-item-name]#++is_valid_signature++#++(hash: felt252, signature: Array) → felt252++` [.item-kind]#external# +[[Account-initializer]] +==== `[.contract-item-name]#++initializer++#++(ref self: ContractState, _public_key: felt252)++` [.item-kind]#internal# -See xref:ISRC6-is_valid_signature[ISRC6::is_valid_signature]. +Initializes the account with the given public key, and registers the ISRC6 interface ID. + +Emits an {OwnerAdded} event. [.contract-item] -[[Account-supports_interface]] -==== `[.contract-item-name]#++supports_interface++#++(interface_id: felt252) → bool++` [.item-kind]#external# +[[Account-validate_transaction]] +==== `[.contract-item-name]#++validate_transaction++#++(self: @ContractState)++ → felt252` [.item-kind]#internal# -Returns whether a contract implements a given interface or not. +Validates a transaction signature from the global context. + +Returns the short string `'VALID'` if valid. + +[.contract-item] +[[Account-_set_public_key]] +==== `[.contract-item-name]#++_set_public_key++#++(ref self: ContractState, new_public_key: felt252)++` [.item-kind]#internal# + +Set the public key without asserting the context. + +Emits an {OwnerAdded} event. + +CAUTION: The usage of this method outside the `set_public_key` function is discouraged. + +[.contract-item] +[[Account-_is_valid_signature]] +==== `[.contract-item-name]#++_is_valid_signature++#++(self: @ContractState, hash: felt252, signature: Span)++ → bool` [.item-kind]#internal# + +Validates the provided `signature` for the `hash`, using the account current public key. [.contract-item] [[Account-OwnerAdded]] From 4982b4ea1d23ec46a364cb7f915186d3dbce91b9 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 30 Aug 2023 14:12:49 +0200 Subject: [PATCH 15/88] feat: update from account docs --- docs/modules/ROOT/pages/api/access.adoc | 42 ++++++++++++------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index d6c441d51..fe427da22 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -35,7 +35,7 @@ to restrict their use to the owner. [.contract-index] .Utilities -- -* xref:Ownable-assert_only_owner[`++InternalImpl::assert_only_owner(self: @ContractState)++`] +* xref:Ownable-assert_only_owner[`++InternalImpl::assert_only_owner(self)++`] -- [.contract-index] @@ -44,15 +44,15 @@ to restrict their use to the owner. [.contract-subindex-inherited] .InternalImpl -* xref:Ownable-initializer[`++initializer(ref self: ContractState, owner: ContractAddress)++`] -* xref:Ownable-_transfer_ownership[`++_transfer_ownership(ref self: ContractState, new_owner: ContractAddress)++`] +* xref:Ownable-initializer[`++initializer(self, owner)++`] +* xref:Ownable-_transfer_ownership[`++_transfer_ownership(self, new_owner)++`] [.contract-subindex-inherited] .OwnableImpl -* xref:Ownable-owner[`++owner(self: @ContractState)++`] -* xref:Ownable-renounce_ownership[`++renounce_ownership(ref self: ContractState)++`] -* xref:Ownable-transfer_ownership[`++transfer_ownership(ref self: ContractState, new_owner: ContractAddress)++`] +* xref:Ownable-owner[`++owner(self)++`] +* xref:Ownable-renounce_ownership[`++renounce_ownership(self)++`] +* xref:Ownable-transfer_ownership[`++transfer_ownership(self, new_owner)++`] -- @@ -136,11 +136,11 @@ External interface of AccessControl declared to support https://github.com/stark [.contract-index] .Functions -- -* xref:IAccessControl-has_role[`++has_role(role: felt252, account: ContractAddress)++`] -* xref:IAccessControl-get_role_admin[`++get_role_admin(role: felt252)++`] -* xref:IAccessControl-grant_role[`++grant_role(role: felt252, account: ContractAddress)++`] -* xref:IAccessControl-revoke_role[`++revoke_role(role: felt252, account: ContractAddress)++`] -* xref:IAccessControl-renounce_role[`++renounce_role(role: felt252, account: ContractAddress)++`] +* xref:IAccessControl-has_role[`++has_role(role, account)++`] +* xref:IAccessControl-get_role_admin[`++get_role_admin(role)++`] +* xref:IAccessControl-grant_role[`++grant_role(role, account)++`] +* xref:IAccessControl-revoke_role[`++revoke_role(role, account)++`] +* xref:IAccessControl-renounce_role[`++renounce_role(role, account)++`] -- @@ -306,23 +306,23 @@ accounts that have been granted it. [.contract-subindex-inherited] .InternalImpl -* xref:#AccessControl-initializer[`++initializer(ref self: ContractState)++`] -* xref:#AccessControl-_set_role_admin[`++_set_role_admin(ref self: ContractState, role: felt252, admin_role: felt252)++`] -* xref:#AccessControl-_grant_role[`++_grant_role(ref self: ContractState, role: felt252, account: ContractAddress)++`] -* xref:#AccessControl-_revoke_role[`++_revoke_role(ref self: ContractState, role: felt252, account: ContractAddress)++`] +* xref:#AccessControl-initializer[`++initializer(self)++`] +* xref:#AccessControl-_set_role_admin[`++_set_role_admin(self, role, admin_role)++`] +* xref:#AccessControl-_grant_role[`++_grant_role(self, role, account)++`] +* xref:#AccessControl-_revoke_role[`++_revoke_role(self, role, account)++`] [.contract-subindex-inherited] .AccessControlImpl -* xref:#AccessControl-has_role[`++has_role(self: @ContractState, role: felt252, account: ContractAddress)++`] -* xref:#AccessControl-get_role_admin[`++get_role_admin(self: @ContractState, role: felt252)++`] -* xref:#AccessControl-grant_role[`++grant_role(ref self: ContractState, role: felt252, account: ContractAddress)++`] -* xref:#AccessControl-revoke_role[`++revoke_role(ref self: ContractState, role: felt252, account: ContractAddress)++`] -* xref:#AccessControl-renounce_role[`++renounce_role(ref self: ContractState, role: felt252, account: ContractAddress)++`] +* xref:#AccessControl-has_role[`++has_role(self, role, account)++`] +* xref:#AccessControl-get_role_admin[`++get_role_admin(self, role)++`] +* xref:#AccessControl-grant_role[`++grant_role(self, role, account)++`] +* xref:#AccessControl-revoke_role[`++revoke_role(self, role, account)++`] +* xref:#AccessControl-renounce_role[`++renounce_role(self, role, account)++`] [.contract-subindex-inherited] .SRC5Impl -* xref:#AccessControl-supports_interface[`++supports_interface(self: @ContractState, interface_id: felt252)++`] +* xref:#AccessControl-supports_interface[`++supports_interface(self, interface_id: felt252)++`] -- [.contract-index] From fbc18fbec7bf1c6b4da5ecb1d256c11eee78e74c Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:18:14 +0200 Subject: [PATCH 16/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index db7a14d8d..58d05ec17 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -33,7 +33,7 @@ Interface of the ISRC6 standard as defined in the {snip6}. Executes the list of calls as a transaction after validation. -Returns the list of each call output. +Returns an array with each call's output. [.contract-item] [[ISRC6-__validate__]] From b235619203f64edcc3b16ffa4437b24c66000054 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:19:31 +0200 Subject: [PATCH 17/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index aabe09d6a..74f931a12 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -4,7 +4,7 @@ = Accounts -Unlike Ethereum where accounts are directly derived from a private key, there's no native Externally Owned Account (EOA) +Unlike Ethereum where accounts are derived from a private key, all Starknet accounts are contracts. This means there's no Externally Owned Account (EOA) concept on Starknet. Instead, the network features native account abstraction, and signature validation has to be done at the contract level. From 13248e482b34ef146cdeafa828de56cb113c61b6 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:21:20 +0200 Subject: [PATCH 18/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 74f931a12..9250be0ad 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -7,7 +7,7 @@ Unlike Ethereum where accounts are derived from a private key, all Starknet accounts are contracts. This means there's no Externally Owned Account (EOA) concept on Starknet. -Instead, the network features native account abstraction, and signature validation has to be done at the contract level. +Instead, the network features native account abstraction and signature validation happens at the contract level. To relieve smart contract applications such as ERC20 tokens or exchanges from this responsibility, we make use of Account contracts to deal with transaction authentication. From cdf7bd2aad2e433384b76ae908f31d7acaac4ec1 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:24:24 +0200 Subject: [PATCH 19/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 2 -- 1 file changed, 2 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 9250be0ad..c9872df98 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -8,8 +8,6 @@ Unlike Ethereum where accounts are derived from a private key, all Starknet acco concept on Starknet. Instead, the network features native account abstraction and signature validation happens at the contract level. -To relieve smart contract applications such as ERC20 tokens or exchanges from this responsibility, -we make use of Account contracts to deal with transaction authentication. For a general overview of the account abstraction, see StarkWare's https://medium.com/starkware/starknet-alpha-0-10-0-923007290470[StarkNet Alpha 0.10]. From bea7e8d2ad1717ddd6f3b97b039ef001c1d0a52f Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:25:01 +0200 Subject: [PATCH 20/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index c9872df98..b2504d360 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -9,8 +9,8 @@ concept on Starknet. Instead, the network features native account abstraction and signature validation happens at the contract level. -For a general overview of the account abstraction, see StarkWare's -https://medium.com/starkware/starknet-alpha-0-10-0-923007290470[StarkNet Alpha 0.10]. +For a general overview of the account abstraction, see +https://docs.starknet.io/documentation/architecture_and_concepts/Accounts/introduction/[Starknet's documentation]. A more detailed discussion on the topic can be found in https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[StarkNet Account Abstraction Part 1]. From 437b19641007cc63cc7195ae00ad0f8f9cf3019e Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:25:22 +0200 Subject: [PATCH 21/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index b2504d360..26bd0093a 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -12,7 +12,7 @@ Instead, the network features native account abstraction and signature validatio For a general overview of the account abstraction, see https://docs.starknet.io/documentation/architecture_and_concepts/Accounts/introduction/[Starknet's documentation]. A more detailed discussion on the topic can be found in -https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[StarkNet Account Abstraction Part 1]. +https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[Starknet Shaman's forum]. TIP: For detailed information on the usage and implementation check the xref:/api/account.adoc[API Reference] section. From d3ffdf4baa59c599d964553c022b0973f67c9571 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:25:56 +0200 Subject: [PATCH 22/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 26bd0093a..8b1b89db3 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -28,7 +28,7 @@ TIP: For detailed information on the usage and implementation check the xref:/ap == Basic Account -As we mentioned, Accounts in Starknet are smart contracts, and so they can be deployed and interacted +As mentioned, accounts in Starknet are smart contracts and so they can be deployed and interacted with like any other contract, and can be extended to implement any custom logic. However, the Account is a special type of contract that is used to validate and execute transactions, and there are a set of entrypoints that must be implemented for enabling these features. From 0d8bdce70994ed2b80a504ea3b149a14d7149d9d Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:26:23 +0200 Subject: [PATCH 23/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 8b1b89db3..38aef515f 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -29,7 +29,7 @@ TIP: For detailed information on the usage and implementation check the xref:/ap == Basic Account As mentioned, accounts in Starknet are smart contracts and so they can be deployed and interacted -with like any other contract, and can be extended to implement any custom logic. However, the Account is a special +with like any other contract, and can be extended to implement any custom logic. However accounts are a special type of contract that is used to validate and execute transactions, and there are a set of entrypoints that must be implemented for enabling these features. From 964e58bea2bbc1729970847a27c580668f8f8d06 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:26:39 +0200 Subject: [PATCH 24/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 58d05ec17..af93ee168 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -160,7 +160,7 @@ Returns the short string `'VALID'` if valid, or any other value otherwise. Sets a new public key for the account. Can be called only by self through the `\\__execute__` mechanism. -Emits an {OwnerRemoved}, and an {OwnerAdded} event. +Emits both an {OwnerRemoved} and an {OwnerAdded} event. [.contract-item] [[Account-get_public_key]] From 99fa76f1ee253ec6c824c192b5191e5cce6b7d3e Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:26:59 +0200 Subject: [PATCH 25/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index af93ee168..b1e86f811 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -182,7 +182,7 @@ Emits an {OwnerAdded} event. Validates a transaction signature from the global context. -Returns the short string `'VALID'` if valid. +Returns the short string `'VALID'` if valid, otherwise it reverts. [.contract-item] [[Account-_set_public_key]] From e5afaebe724b1a5b71ecf3452ddead7cd782c499 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:36:45 +0200 Subject: [PATCH 26/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 38aef515f..7ec4ec65a 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -133,11 +133,11 @@ interoperability with the ecosystem. == Deploying an Account -In Starknet, there are two different ways for deploying smart contracts: the regular deployment using the -`deploy_syscall` and the counterfactual deployment. The xref:udc.adoc[Universal Deployer Contract (UDC)] provides -an interface for deploying arbitrary contracts through account calls (leveraging the first way through -the `deploy_syscall`), but if you are deploying your first Account, you will probably want to use the -counterfactual deployment, from the fact that you don't have an Account for calling the UDC in the first place. +In Starknet there are two ways of deploying smart contracts: using the `deploy_syscall` and doing +counterfactual deployments. +The former can be easily done with the xref:udc.adoc[Universal Deployer Contract (UDC)], a contract that +wraps and exposes the `deploy_syscall` to provide arbitrary deployments through regular contract calls. +But if you don't have an account to invoke it, you will probably want to use the latter. For using counterfactual deployments, you need to implement another protocol-level entrypoint named `\\__validate_deploy__`. You can check the xref:/guides/deployment.adoc[Counterfactual Deployments] guide for From 56715e7e95845f9dcfbe2a225d4591ae1ebc71d8 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:39:02 +0200 Subject: [PATCH 27/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 7ec4ec65a..03d76e47e 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -139,6 +139,6 @@ The former can be easily done with the xref:udc.adoc[Universal Deployer Contract wraps and exposes the `deploy_syscall` to provide arbitrary deployments through regular contract calls. But if you don't have an account to invoke it, you will probably want to use the latter. -For using counterfactual deployments, you need to implement another protocol-level entrypoint named +To do counterfactual deployments, you need to implement another protocol-level entrypoint named `\\__validate_deploy__`. You can check the xref:/guides/deployment.adoc[Counterfactual Deployments] guide for getting into the specifics. From a59695758499801b352431baaccb58ec2cb96091 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:39:30 +0200 Subject: [PATCH 28/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 03d76e47e..ddf906d86 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -140,5 +140,4 @@ wraps and exposes the `deploy_syscall` to provide arbitrary deployments through But if you don't have an account to invoke it, you will probably want to use the latter. To do counterfactual deployments, you need to implement another protocol-level entrypoint named -`\\__validate_deploy__`. You can check the xref:/guides/deployment.adoc[Counterfactual Deployments] guide for -getting into the specifics. +`\\__validate_deploy__`. You can check the xref:/guides/deployment.adoc[Counterfactual Deployments] guide to learn how. From c5d146669cc1d5c7a99039e2d7e2d4fffa104cc3 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:40:15 +0200 Subject: [PATCH 29/88] Update docs/modules/ROOT/pages/guides/deployment.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/guides/deployment.adoc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc index bc2ec6006..d1ebf59ee 100644 --- a/docs/modules/ROOT/pages/guides/deployment.adoc +++ b/docs/modules/ROOT/pages/guides/deployment.adoc @@ -3,9 +3,10 @@ = Counterfactual deployments -A deployment is said to be counterfactual when the one paying for the deployment fees is the address of -the contract to be deployed. In other words, we need to send the funds to the address even when the -deploymenthasn’t happened. +A counterfactual contract is a contract we can interact with even before actually deploying it on-chain. +For example, we can send funds or assign privileges to a contract that doesn't yet exist. +Why? Because deployments in Starknet are deterministic, allowing us to predict the address where our contract will be deployed. +We can leverage this property to make a contract pay for its own deployment by simply sending funds in advance. We call this a counterfactual deployment. This process can be described with the following steps: From 022d8bd0e7bb049cedbf8ed730016754f956ad65 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:40:53 +0200 Subject: [PATCH 30/88] Update docs/modules/ROOT/pages/guides/deployment.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/guides/deployment.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc index d1ebf59ee..e50262cbf 100644 --- a/docs/modules/ROOT/pages/guides/deployment.adoc +++ b/docs/modules/ROOT/pages/guides/deployment.adoc @@ -20,7 +20,7 @@ tools usually do this for you. 3. Send a `DeployAccount` type transaction to the network. -4. The protocol will then validate the transaction with the `\\__validate_deploy__` entrypoint. +4. The protocol will then validate the transaction with the `\\__validate_deploy__` entrypoint of the contract to be deployed. 5. If the validation succeeds, the protocol will charge the fee and then register the contract as deployed. From 4ede5cc2658c11fa89394174e5a1e562bbae76a0 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:41:21 +0200 Subject: [PATCH 31/88] Update docs/modules/ROOT/pages/guides/deployment.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/guides/deployment.adoc | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc index e50262cbf..aa0214e52 100644 --- a/docs/modules/ROOT/pages/guides/deployment.adoc +++ b/docs/modules/ROOT/pages/guides/deployment.adoc @@ -24,6 +24,7 @@ tools usually do this for you. 5. If the validation succeeds, the protocol will charge the fee and then register the contract as deployed. +NOTE: Although this method is very popular to deploy accounts, this works for any kind of contract. == Deployment validation From f007a1f71e413959931f0448a9be6e315fce5198 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:41:50 +0200 Subject: [PATCH 32/88] Update docs/modules/ROOT/pages/guides/deployment.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/guides/deployment.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc index aa0214e52..6c72a2652 100644 --- a/docs/modules/ROOT/pages/guides/deployment.adoc +++ b/docs/modules/ROOT/pages/guides/deployment.adoc @@ -28,7 +28,7 @@ NOTE: Although this method is very popular to deploy accounts, this works for an == Deployment validation -For counterfactual deployments, contracts must implement the `\\__validate_deploy__` entrypoint, and it is +To counterfactually deploy contracts, they must implement the `\\__validate_deploy__` entrypoint, called by the protocol when a `DeployAccount` transaction is sent to the network. [,javascript] From 76ce366f9b4739cfc4fb7acb7d89c73893343777 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:42:24 +0200 Subject: [PATCH 33/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index b1e86f811..61dc4812f 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -41,7 +41,7 @@ Returns an array with each call's output. Validates a transaction before execution. -Returns the short string `'VALID'` if valid, or any other value otherwise. +Returns the short string `'VALID'` if valid, otherwise it reverts. [.contract-item] [[ISRC6-is_valid_signature]] From 207662c6c3571461ef9351aa9d272d3128f7a46e Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:46:02 +0200 Subject: [PATCH 34/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 61dc4812f..7bad8dc09 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -62,7 +62,7 @@ Returns the short string `'VALID'` if valid, or any other value otherwise. ```javascript use openzeppelin::account::Account; ``` -Base Account contract implementation. +Account contract implementation extending xref:ISRC6[`ISRC6`]. [.contract-index] .Utilities From 699a27a3fe2eea161fb6f66609b23b1c8f04387d Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:46:53 +0200 Subject: [PATCH 35/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 7bad8dc09..bea379d34 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -204,7 +204,7 @@ Validates the provided `signature` for the `hash`, using the account current pub [[Account-OwnerAdded]] ==== `[.contract-item-name]#++OwnerAdded++#++(new_owner_guid: felt252)++` [.item-kind]#event# -Emitted when the account `public_key` is updated. +Emitted when a `public_key` is added. [.contract-item] [[Account-OwnerRemoved]] From 29b23f41266ce3030542b24fd3e762efcd5d3167 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:49:00 +0200 Subject: [PATCH 36/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index bea379d34..f46b45ad5 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -158,7 +158,7 @@ Returns the short string `'VALID'` if valid, or any other value otherwise. [[Account-set_public_key]] ==== `[.contract-item-name]#++set_public_key++#++(ref self: ContractState, new_public_key: felt252)++` [.item-kind]#external# -Sets a new public key for the account. Can be called only by self through the `\\__execute__` mechanism. +Sets a new public key for the account. Only accesible by the account calling itself through `\\__execute__`. Emits both an {OwnerRemoved} and an {OwnerAdded} event. From 19b8372c488063374a968834dbef1a7cec7b5c66 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:49:24 +0200 Subject: [PATCH 37/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index f46b45ad5..5b181f1b3 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -118,7 +118,7 @@ Account contract implementation extending xref:ISRC6[`ISRC6`]. [[Account-__validate_deploy__]] ==== `[.contract-item-name]#++__validate_deploy__++#++(self: @ContractState, class_hash: felt252, contract_address_salt: felt252, _public_key: felt252) → felt252++` [.item-kind]#external# -Validates a DeployAccount transaction. +Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/Blocks/transactions/#deploy_account_transaction[`DeployAccount` transaction]. See xref:/guides/deployment.adoc[Counterfactual Deployments]. Returns the short string `'VALID'` if valid, or any other value otherwise. From d9095166a74d14b692594d693e4b22a53ffbb4db Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:50:19 +0200 Subject: [PATCH 38/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 5b181f1b3..811f8d93d 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -150,7 +150,7 @@ Returns whether a contract implements a given interface or not. [[Account-__validate_declare__]] ==== `[.contract-item-name]#++__validate_declare__++#++(self: @ContractState, class_hash: felt252) → felt252++` [.item-kind]#external# -Validates a Declare transaction. +Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/Blocks/transactions/#declare-transaction[`Declare` transaction]. Returns the short string `'VALID'` if valid, or any other value otherwise. From 8c23b4c09d230ca2b1a1b81822f9c72a311eb7ec Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:50:48 +0200 Subject: [PATCH 39/88] feat: apply review updates --- docs/modules/ROOT/pages/accounts.adoc | 17 +++-------------- docs/modules/ROOT/pages/api/account.adoc | 13 +++++++------ 2 files changed, 10 insertions(+), 20 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index aabe09d6a..38b55f00a 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -18,24 +18,13 @@ https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[St TIP: For detailed information on the usage and implementation check the xref:/api/account.adoc[API Reference] section. -== Table of Contents - -* <> -** <> -** <> -* <> -** <> -** <> -* <> - == Basic Account As we mentioned, Accounts in Starknet are smart contracts, and so they can be deployed and interacted -with like any other contract, and can be extended to implement any custom logic. However, the Account is a special -type of contract that is used to validate and execute transactions, and there are a set of entrypoints -that must be implemented for enabling these features. +with like any other contract, and can be extended to implement any custom logic. However, accounts are a special type +of contract that are used to validate and execute transactions, for which they must implement a minimum set of functions. -=== Account entrypoints +=== Account methods The first two following methods are protocol-level enforced functions that must be implemented by any Account contract. The third one is optional and can be used for enabling declarations. diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index db7a14d8d..14843f980 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -16,8 +16,7 @@ Reference of interfaces, presets, and utilities related to Account contracts. use openzeppelin::account::interface::ISRC6; ``` -Interface of the ISRC6 standard as defined in the {snip6}. - +Interface of the SRC6 Standard Account as defined in the {snip6}. [.contract-index] .Functions @@ -35,13 +34,15 @@ Executes the list of calls as a transaction after validation. Returns the list of each call output. +NOTE: The `Call` struct is defined in https://github.com/starkware-libs/cairo/blob/main/corelib/src/starknet/account.cairo#L3[corelib]. + [.contract-item] [[ISRC6-__validate__]] ==== `[.contract-item-name]#++__validate__++#++(calls: Array) → felt252++` [.item-kind]#external# Validates a transaction before execution. -Returns the short string `'VALID'` if valid, or any other value otherwise. +Returns the short string `'VALID'` if valid, otherwise ir reverts. [.contract-item] [[ISRC6-is_valid_signature]] @@ -49,7 +50,7 @@ Returns the short string `'VALID'` if valid, or any other value otherwise. Validates whether a signature is valid or not for the given message hash. -Returns the short string `'VALID'` if valid, or any other value otherwise. +Returns the short string `'VALID'` if valid, otherwise ir reverts. [.contract] [[Account]] @@ -120,7 +121,7 @@ Base Account contract implementation. Validates a DeployAccount transaction. -Returns the short string `'VALID'` if valid, or any other value otherwise. +Returns the short string `'VALID'` if valid, otherwise it reverts. [.contract-item] [[Account-__execute__]] @@ -152,7 +153,7 @@ Returns whether a contract implements a given interface or not. Validates a Declare transaction. -Returns the short string `'VALID'` if valid, or any other value otherwise. +Returns the short string `'VALID'` if valid, otherwise it reverts. [.contract-item] [[Account-set_public_key]] From 501b241ee728f251543ecd36589992eefd2880bc Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 14:53:33 +0200 Subject: [PATCH 40/88] fix: account casing --- docs/modules/ROOT/pages/accounts.adoc | 16 ++++++++-------- docs/modules/ROOT/pages/api/account.adoc | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 54edab19c..cab21c374 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -18,13 +18,13 @@ TIP: For detailed information on the usage and implementation check the xref:/ap == Basic Account -As we mentioned, Accounts in Starknet are smart contracts, and so they can be deployed and interacted +As we mentioned, accounts in Starknet are smart contracts, and so they can be deployed and interacted with like any other contract, and can be extended to implement any custom logic. However, accounts are a special type of contract that are used to validate and execute transactions, for which they must implement a minimum set of functions. === Account methods -The first two following methods are protocol-level enforced functions that must be implemented by any Account contract. +The first two following methods are protocol-level enforced functions that must be implemented by any account contract. The third one is optional and can be used for enabling declarations. 1. `\\__validate__` verifies the validity of the transaction to be executed. This is usually used to validate signatures, @@ -74,12 +74,12 @@ trait BaseAccount { == Standard Account Interface -In the previous section we've presented the minimal interface a contract must implement to act as an Account by +In the previous section we've presented the minimal interface a contract must implement to act as an account by propagating transactions through the network. However, this interface lacks some features required for supporting interoperability among accounts and DApps in the ecosystem. For example, there is no mechanism for recognizing on-chain whether a contract is an Account or not. -To address this issue, we have the {snip-6}[SNIP-6] proposal, which defines a standard interface for Account contracts. +To address this issue, we have the {snip-6}[SNIP-6] proposal, which defines a standard interface for account contracts. === ISRC6 Interface @@ -101,8 +101,8 @@ trait ISRC6 { The {snip-6}[SNIP-6] adds the `is_valid_signature` method. This method is not used by the protocol, but it's useful for DApps to verify the validity of signatures, supporting features like Sign In with Starknet. -The SNIP-6 also defines that compliant Accounts must implement the SRC5 interface following {snip-5}[SNIP-5], as -a mechanism for detecting whether a contract is an Account or not through introspection. +The SNIP-6 also defines that compliant accounts must implement the SRC5 interface following {snip-5}[SNIP-5], as +a mechanism for detecting whether a contract is an account or not through introspection. === ISRC5 Interface @@ -115,12 +115,12 @@ trait ISRC5 { } ---- -{snip-6}[SNIP-6] compliant Accounts must return `true` when queried for the ISRC6 interface Id. +{snip-6}[SNIP-6] compliant accounts must return `true` when queried for the ISRC6 interface Id. Even though these interfaces are not enforced by the protocol, it's recommended to implement them for enabling interoperability with the ecosystem. -== Deploying an Account +== Deploying an account In Starknet there are two ways of deploying smart contracts: using the `deploy_syscall` and doing counterfactual deployments. diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index e6d52d994..a03b779fd 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -3,7 +3,7 @@ = Account -Reference of interfaces, presets, and utilities related to Account contracts. +Reference of interfaces, presets, and utilities related to account contracts. == Core From 5b33694478f7c050de642fbdc4be77dcce7ab3c1 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 15:08:38 +0200 Subject: [PATCH 41/88] feat: add headers --- docs/modules/ROOT/nav.adoc | 2 +- docs/modules/ROOT/pages/api/account.adoc | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index d2b13623b..36423c0fa 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -4,7 +4,7 @@ * xref:proxies.adoc[Proxies and Upgrades] * xref:accounts.adoc[Accounts] -** xref:/guides/deployment.adoc[Counterfactual Deployments] +** xref:/guides/deployment.adoc[Counterfactual deployments] * xref:access.adoc[Access Control] diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index a03b779fd..0aa1bf2bf 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -26,6 +26,9 @@ Interface of the SRC6 Standard Account as defined in the {snip6}. * xref:#ISRC6-is_valid_signature[`++is_valid_signature(hash, signature)++`] -- +[#ISRC6-Functions] +==== Functions + [.contract-item] [[ISRC6-__execute__]] ==== `[.contract-item-name]#++__execute__++#++(calls: Array) → Array>++` [.item-kind]#external# @@ -115,11 +118,24 @@ Account contract implementation extending xref:ISRC6[`ISRC6`]. * xref:#Account-OwnerRemoved[`++OwnerRemoved(removed_owner_guid)++`] -- +[#Account-Utilities] +==== Utilities + +[.contract-item] +[[Account-assert_only_self]] +==== `[.contract-item-name]#++assert_only_self++#++(self: @ContractState)++` [.item-kind]#internal# + +Validates that the caller is the account itself. Otherwise it reverts. + +[#Account-Functions] +==== Functions + [.contract-item] [[Account-__validate_deploy__]] ==== `[.contract-item-name]#++__validate_deploy__++#++(self: @ContractState, class_hash: felt252, contract_address_salt: felt252, _public_key: felt252) → felt252++` [.item-kind]#external# -Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/Blocks/transactions/#deploy_account_transaction[`DeployAccount` transaction]. See xref:/guides/deployment.adoc[Counterfactual Deployments]. +Validates a https://docs.starknet.io/documentation/architecture_and_concepts/Network_Architecture/Blocks/transactions/#deploy_account_transaction[`DeployAccount` transaction]. +See xref:/guides/deployment.adoc[Counterfactual Deployments]. Returns the short string `'VALID'` if valid, otherwise it reverts. @@ -201,6 +217,9 @@ CAUTION: The usage of this method outside the `set_public_key` function is disco Validates the provided `signature` for the `hash`, using the account current public key. +[#Account-Events] +==== Events + [.contract-item] [[Account-OwnerAdded]] ==== `[.contract-item-name]#++OwnerAdded++#++(new_owner_guid: felt252)++` [.item-kind]#event# From e781bfd1070dca5539e7b8cf5c7b499431f16778 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 15:21:32 +0200 Subject: [PATCH 42/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 0aa1bf2bf..932b5f842 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -230,4 +230,4 @@ Emitted when a `public_key` is added. [[Account-OwnerRemoved]] ==== `[.contract-item-name]#++OwnerRemoved++#++(removed_owner_guid: felt252)++` [.item-kind]#event# -Emitted when the account `public_key` is updated except for initialization. +Emitted when a `public_key` is removed. From 7fdf47b046a937224b67e8adc73e31a7513346b8 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 31 Aug 2023 15:21:55 +0200 Subject: [PATCH 43/88] feat: add link --- docs/modules/ROOT/pages/api/account.adoc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 0aa1bf2bf..30bc5cf8b 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -197,7 +197,8 @@ Emits an {OwnerAdded} event. [[Account-validate_transaction]] ==== `[.contract-item-name]#++validate_transaction++#++(self: @ContractState)++ → felt252` [.item-kind]#internal# -Validates a transaction signature from the global context. +Validates a transaction signature from the +https://github.com/starkware-libs/cairo/blob/main/corelib/src/starknet/info.cairo#L61[global context]. Returns the short string `'VALID'` if valid, otherwise it reverts. @@ -205,7 +206,7 @@ Returns the short string `'VALID'` if valid, otherwise it reverts. [[Account-_set_public_key]] ==== `[.contract-item-name]#++_set_public_key++#++(ref self: ContractState, new_public_key: felt252)++` [.item-kind]#internal# -Set the public key without asserting the context. +Set the public key without asserting the caller. Emits an {OwnerAdded} event. From 77da3674ddd1927b33dd1fd5da72139ef4ec57cd Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 1 Sep 2023 12:45:09 +0200 Subject: [PATCH 44/88] feat: move API --- docs/antora.yml | 3 +++ docs/modules/ROOT/nav.adoc | 4 +--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/antora.yml b/docs/antora.yml index f75680009..7ff2862d9 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -3,3 +3,6 @@ title: Contracts for Cairo version: 0.6.1 nav: - modules/ROOT/nav.adoc +asciidoc: + attributes: + page-sidebar-collapse-default: true \ No newline at end of file diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc index 36423c0fa..d78f8a2bd 100644 --- a/docs/modules/ROOT/nav.adoc +++ b/docs/modules/ROOT/nav.adoc @@ -5,6 +5,7 @@ * xref:accounts.adoc[Accounts] ** xref:/guides/deployment.adoc[Counterfactual deployments] +** xref:/api/account.adoc[API Reference] * xref:access.adoc[Access Control] @@ -19,6 +20,3 @@ * xref:utilities.adoc[Utilities] * xref:contracts::index.adoc[Contracts for Solidity] - -* API -** xref:/api/account.adoc[Account] \ No newline at end of file From ae6e30c81634f196ceac0db6b55129725e7547f9 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 1 Sep 2023 13:26:33 +0200 Subject: [PATCH 45/88] feat: add event references --- docs/modules/ROOT/pages/api/access.adoc | 48 +++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 3 deletions(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index fe427da22..22e37674b 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -62,12 +62,18 @@ to restrict their use to the owner. * xref:Ownable-OwnershipTransferred[`++OwnershipTransferred(previous_owner, new_owner)++`] -- +[#Ownable-Utilities] +==== Utilities + [.contract-item] [[Ownable-assert_only_owner]] ==== `[.contract-item-name]#++assert_only_owner++#++(self: @ContractState)++` [.item-kind]#internal# Throws if called by any account other than the owner. +[#Ownable-Functions] +==== Functions + [.contract-item] [[Ownable-initializer]] ==== `[.contract-item-name]#++initializer++#++(ref self: ContractState, owner: ContractAddress)++` [.item-kind]#internal# @@ -110,6 +116,9 @@ Can only be called by the current owner. Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. +[#Ownable-Events] +==== Events + [.contract-item] [[Ownable-OwnershipTransferred]] ==== `[.contract-item-name]#++OwnershipTransferred++#++(previous_owner: ContractAddress, new_owner: ContractAddress)++` [.item-kind]#event# @@ -153,6 +162,9 @@ External interface of AccessControl declared to support https://github.com/stark -- +[#IAccessControl-Functions] +==== Functions + [.contract-item] [[IAccessControl-has_role]] ==== `[.contract-item-name]#++has_role++#++(role: felt252, account: ContractAddress) → bool++` [.item-kind]#external# @@ -210,6 +222,8 @@ Requirements: - the caller must be `account`. +[#IAccessControl-Events] +==== Events [.contract-item] [[IAccessControl-RoleAdminChanged]] @@ -330,17 +344,23 @@ accounts that have been granted it. -- [.contract-subindex-inherited] .IAccessControl -* xref:#IAccessControl-RoleAdminChanged[`++RoleAdminChanged(role, previous_admin_role, new_admin_role)++`] -* xref:#IAccessControl-RoleGranted[`++RoleGranted(role, account, sender)++`] -* xref:#IAccessControl-RoleRevoked[`++RoleRevoked(role, account, sender)++`] +* xref:#AccessControl-RoleAdminChanged[`++RoleAdminChanged(role, previous_admin_role, new_admin_role)++`] +* xref:#AccessControl-RoleGranted[`++RoleGranted(role, account, sender)++`] +* xref:#AccessControl-RoleRevoked[`++RoleRevoked(role, account, sender)++`] -- +[#AccessControl-Utilities] +==== Utilities + [.contract-item] [[AccessControl-assert_only_role]] ==== `[.contract-item-name]#++assert_only_role++#++(self: @ContractState, role: felt252)++` [.item-kind]#internal# Throws if called by any account without the given `role`. +[#AccessControl-Functions] +==== Functions + [.contract-item] [[AccessControl-initializer]] ==== `[.contract-item-name]#++initializer++#++(ref self: ContractState)++` [.item-kind]#internal# @@ -443,3 +463,25 @@ May emit a {RoleRevoked} event. ==== `[.contract-item-name]#++supports_interface++#++(self: @ContractState, interface_id: felt252) → bool++` [.item-kind]#external# Returns whether a contract implements a given interface or not. + + +[#AccessControl-Events] +==== Events + +[.contract-item] +[[AccessControl-RoleAdminChanged]] +==== `[.contract-item-name]#++RoleAdminChanged++#++(role: felt252, previous_admin_role: ContractAddress, new_admin_role: ContractAddress)++` [.item-kind]#event# + +See xref:IAccessControl-RoleAdminChanged[IAccessControl::RoleAdminChanged]. + +[.contract-item] +[[AccessControl-RoleGranted]] +==== `[.contract-item-name]#++RoleGranted++#++(role: felt252, account: ContractAddress, sender: ContractAddress)++` [.item-kind]#event# + +See xref:IAccessControl-RoleGranted[IAccessControl::RoleGranted]. + +[.contract-item] +[[AccessControl-RoleRevoked]] +==== `[.contract-item-name]#++RoleRevoked++#++(role: felt252, account: ContractAddress, sender: ContractAddress)++` [.item-kind]#event# + +See xref:IAccessControl-RoleRevoked[IAccessControl::RoleRevoked]. From 76fd058aa41b95a2f0fe471722920b6d638ab044 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 12:03:39 +0200 Subject: [PATCH 46/88] Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index cab21c374..51f75b640 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -9,7 +9,7 @@ concept on Starknet. Instead, the network features native account abstraction and signature validation happens at the contract level. -For a general overview of the account abstraction, see +For a general overview of account abstraction, see https://docs.starknet.io/documentation/architecture_and_concepts/Accounts/introduction/[Starknet's documentation]. A more detailed discussion on the topic can be found in https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[Starknet Shaman's forum]. From 0342dfc132a07eb7ff4a0109ee7c64915de4bce5 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 12:05:25 +0200 Subject: [PATCH 47/88] Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 51f75b640..5b633f60f 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -37,7 +37,7 @@ validation mechanism. meant to declare other contracts. -NOTE: Even when this entrypoints can be called directly at contract level, they are not designed for that, +NOTE: Even though these entrypoints _can_ be called directly at the contract level, they are not designed for that, but to be called by the Starknet OS in the transaction execution flow. === Interface From 7e5a3ec4c7656e6d70ee6be741d636dbdc435716 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 12:05:45 +0200 Subject: [PATCH 48/88] Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 5b633f60f..c2d036116 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -98,7 +98,7 @@ trait ISRC6 { } ---- -The {snip-6}[SNIP-6] adds the `is_valid_signature` method. This method is not used by the protocol, but it's useful for +{snip-6}[SNIP-6] adds the `is_valid_signature` method. This method is not used by the protocol, but it's useful for DApps to verify the validity of signatures, supporting features like Sign In with Starknet. The SNIP-6 also defines that compliant accounts must implement the SRC5 interface following {snip-5}[SNIP-5], as From f3cccacf963dbe53f37376c5d956574106e3d4f6 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 12:05:56 +0200 Subject: [PATCH 49/88] Update docs/modules/ROOT/pages/accounts.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index c2d036116..fdf4247d7 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -101,7 +101,7 @@ trait ISRC6 { {snip-6}[SNIP-6] adds the `is_valid_signature` method. This method is not used by the protocol, but it's useful for DApps to verify the validity of signatures, supporting features like Sign In with Starknet. -The SNIP-6 also defines that compliant accounts must implement the SRC5 interface following {snip-5}[SNIP-5], as +SNIP-6 also defines that compliant accounts must implement the SRC5 interface following {snip-5}[SNIP-5], as a mechanism for detecting whether a contract is an account or not through introspection. === ISRC5 Interface From 0f4583dc8350c930831819ba07cd4be57985f22b Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 12:07:34 +0200 Subject: [PATCH 50/88] refactor: update wording --- docs/modules/ROOT/pages/accounts.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index cab21c374..00322a1f4 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -24,7 +24,7 @@ of contract that are used to validate and execute transactions, for which they m === Account methods -The first two following methods are protocol-level enforced functions that must be implemented by any account contract. +SRC6 standard account contracts must implement the following methods, the first two being enforced by the protocol. The third one is optional and can be used for enabling declarations. 1. `\\__validate__` verifies the validity of the transaction to be executed. This is usually used to validate signatures, From 039fb1f2df1b3c7df3e1b657256801481cef925a Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 12:22:14 +0200 Subject: [PATCH 51/88] Update docs/antora.yml Co-authored-by: Andrew Fleming --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index 7ff2862d9..71b849a89 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -5,4 +5,4 @@ nav: - modules/ROOT/nav.adoc asciidoc: attributes: - page-sidebar-collapse-default: true \ No newline at end of file + page-sidebar-collapse-default: true From 2f51db79eda1767f25e627badb416ce0d138aa00 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 12:26:50 +0200 Subject: [PATCH 52/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 7f977755d..c4a9b4b15 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -206,7 +206,7 @@ Returns the short string `'VALID'` if valid, otherwise it reverts. [[Account-_set_public_key]] ==== `[.contract-item-name]#++_set_public_key++#++(ref self: ContractState, new_public_key: felt252)++` [.item-kind]#internal# -Set the public key without asserting the caller. +Set the public key without validating the caller. Emits an {OwnerAdded} event. From bf2543ca46ecb75e108348527ca146e366f04a6a Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 12:30:41 +0200 Subject: [PATCH 53/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index c4a9b4b15..738fa3ddb 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -53,7 +53,7 @@ Returns the short string `'VALID'` if valid, otherwise ir reverts. Validates whether a signature is valid or not for the given message hash. -Returns the short string `'VALID'` if valid, otherwise ir reverts. +Returns the short string `'VALID'` if valid, otherwise it reverts. [.contract] [[Account]] From eba29924a5823b260c221b7ae69ebe0006ea664a Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 12:34:40 +0200 Subject: [PATCH 54/88] feat: apply update reviews --- docs/modules/ROOT/pages/accounts.adoc | 4 ++-- docs/modules/ROOT/pages/api/account.adoc | 9 +++++++++ docs/modules/ROOT/pages/guides/deployment.adoc | 2 +- src/account/account.cairo | 4 ++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 18a586bbf..61bbc6b53 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -19,8 +19,8 @@ TIP: For detailed information on the usage and implementation check the xref:/ap == Basic Account As we mentioned, accounts in Starknet are smart contracts, and so they can be deployed and interacted -with like any other contract, and can be extended to implement any custom logic. However, accounts are a special type -of contract that are used to validate and execute transactions, for which they must implement a minimum set of functions. +with like any other contract, and can be extended to implement any custom logic. However, an account is a special type +of contract that is used to validate and execute transactions, for which it must implement a minimum set of functions. === Account methods diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 7f977755d..7e13d48ea 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -77,6 +77,7 @@ Account contract implementation extending xref:ISRC6[`ISRC6`]. [.contract-index] .Functions -- +* xref:#Account-constructor[`++constructor(self, _public_key)++`] * xref:#Account-\\__validate_deploy__[`++__validate_deploy__(self, hash, signature)++`] [.contract-subindex-inherited] @@ -130,6 +131,14 @@ Validates that the caller is the account itself. Otherwise it reverts. [#Account-Functions] ==== Functions +[.contract-item] +[[Account-constructor]] +==== `[.contract-item-name]#++constructor++#++(ref self: ContractState, _public_key: felt252)++` [.item-kind]#constructor# + +Initializes the account with the given public key, and registers the ISRC6 interface ID. + +Emits an {OwnerAdded} event. + [.contract-item] [[Account-__validate_deploy__]] ==== `[.contract-item-name]#++__validate_deploy__++#++(self: @ContractState, class_hash: felt252, contract_address_salt: felt252, _public_key: felt252) → felt252++` [.item-kind]#external# diff --git a/docs/modules/ROOT/pages/guides/deployment.adoc b/docs/modules/ROOT/pages/guides/deployment.adoc index 6c72a2652..92f6a1bd2 100644 --- a/docs/modules/ROOT/pages/guides/deployment.adoc +++ b/docs/modules/ROOT/pages/guides/deployment.adoc @@ -28,7 +28,7 @@ NOTE: Although this method is very popular to deploy accounts, this works for an == Deployment validation -To counterfactually deploy contracts, they must implement the `\\__validate_deploy__` entrypoint, +To be counterfactually deployed, the deploying contract must implement the `\\__validate_deploy__` entrypoint, called by the protocol when a `DeployAccount` transaction is sent to the network. [,javascript] diff --git a/src/account/account.cairo b/src/account/account.cairo index 3bda0e34a..1dad67720 100644 --- a/src/account/account.cairo +++ b/src/account/account.cairo @@ -221,7 +221,7 @@ mod Account { assert(self == caller, 'Account: unauthorized'); } - #[internal] + #[private] fn _execute_calls(mut calls: Array) -> Array> { let mut res = ArrayTrait::new(); loop { @@ -238,7 +238,7 @@ mod Account { res } - #[internal] + #[private] fn _execute_single_call(call: Call) -> Span { let Call{to, selector, calldata } = call; starknet::call_contract_syscall(to, selector, calldata.span()).unwrap() From 694b3a2c3a4296d57cd798a7bf8bfb3201d4075e Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 12:55:34 +0200 Subject: [PATCH 55/88] Update docs/modules/ROOT/pages/api/account.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/account.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 7d7e5c5fe..0eb2d7850 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -45,7 +45,7 @@ NOTE: The `Call` struct is defined in https://github.com/starkware-libs/cairo/bl Validates a transaction before execution. -Returns the short string `'VALID'` if valid, otherwise ir reverts. +Returns the short string `'VALID'` if valid, otherwise it reverts. [.contract-item] [[ISRC6-is_valid_signature]] From 5de23f27c7f8c09b2cbe1405a35e2fc1667eecfc Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 13:09:18 +0200 Subject: [PATCH 56/88] refactor: UI --- docs/modules/ROOT/pages/api/account.adoc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 0eb2d7850..28f62f395 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -19,7 +19,7 @@ use openzeppelin::account::interface::ISRC6; Interface of the SRC6 Standard Account as defined in the {snip6}. [.contract-index] -.Functions +.External Functions -- * xref:#ISRC6-\\__execute__[`++__execute__(calls)++`] * xref:#ISRC6-\\__validate__[`++__validate__(calls)++`] @@ -27,7 +27,7 @@ Interface of the SRC6 Standard Account as defined in the {snip6}. -- [#ISRC6-Functions] -==== Functions +==== External Functions [.contract-item] [[ISRC6-__execute__]] @@ -75,9 +75,8 @@ Account contract implementation extending xref:ISRC6[`ISRC6`]. -- [.contract-index] -.Functions +.External Functions -- -* xref:#Account-constructor[`++constructor(self, _public_key)++`] * xref:#Account-\\__validate_deploy__[`++__validate_deploy__(self, hash, signature)++`] [.contract-subindex-inherited] @@ -102,6 +101,12 @@ Account contract implementation extending xref:ISRC6[`ISRC6`]. * xref:#Account-set_public_key[`++set_public_key(self, new_public_key)++`] * xref:#Account-get_public_key[`++get_public_key(self)++`] +-- + +[.contract-index] +.Internal Functions +-- +* xref:#Account-constructor[`++constructor(self, _public_key)++`] [.contract-subindex-inherited] .InternalImpl From 717f54811133a186e9c9429f4eee9a54cb15bbe0 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 13:10:40 +0200 Subject: [PATCH 57/88] fix: UI --- docs/modules/ROOT/pages/api/account.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 28f62f395..203006599 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -19,7 +19,7 @@ use openzeppelin::account::interface::ISRC6; Interface of the SRC6 Standard Account as defined in the {snip6}. [.contract-index] -.External Functions +.Functions -- * xref:#ISRC6-\\__execute__[`++__execute__(calls)++`] * xref:#ISRC6-\\__validate__[`++__validate__(calls)++`] @@ -27,7 +27,7 @@ Interface of the SRC6 Standard Account as defined in the {snip6}. -- [#ISRC6-Functions] -==== External Functions +==== Functions [.contract-item] [[ISRC6-__execute__]] From a5d6f94273b39019615990a5d8509816ab4351b7 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 13:38:27 +0200 Subject: [PATCH 58/88] feat: focus on SRC6 --- docs/modules/ROOT/pages/accounts.adoc | 85 +++++++++------------------ 1 file changed, 28 insertions(+), 57 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 61bbc6b53..28cab2ee5 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -1,6 +1,7 @@ :test-signers: https://github.com/OpenZeppelin/cairo-contracts/blob/release-v0.6.1/tests/signers.py :snip-5: https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md :snip-6: https://github.com/ericnordelo/SNIPs/blob/feat/standard-account/SNIPS/snip-6.md +:counterfactual: xref:/guides/deployment.adoc[Counterfactual Deployments] = Accounts @@ -16,40 +17,15 @@ https://community.starknet.io/t/starknet-account-abstraction-model-part-1/781[St TIP: For detailed information on the usage and implementation check the xref:/api/account.adoc[API Reference] section. -== Basic Account +== Standard Account Interface -As we mentioned, accounts in Starknet are smart contracts, and so they can be deployed and interacted +Accounts in Starknet are smart contracts, and so they can be deployed and interacted with like any other contract, and can be extended to implement any custom logic. However, an account is a special type -of contract that is used to validate and execute transactions, for which it must implement a minimum set of functions. - -=== Account methods - -SRC6 standard account contracts must implement the following methods, the first two being enforced by the protocol. -The third one is optional and can be used for enabling declarations. - -1. `\\__validate__` verifies the validity of the transaction to be executed. This is usually used to validate signatures, -but following the account abstraction design, the entrypoint implementation can be customized to feature any -validation mechanism. +of contract that is used to validate and execute transactions. For this reason, it must implement a set of entrypoints +that the protocol uses for this execution flow. The {snip-6}[SNIP-6] proposal defines a standard interface for accounts, +supporting this execution flow and interoperability with DApps in the ecosystem. -2. `\\__execute__` executes the transaction if the validation is successful. - -3. `\\__validate_declare__` Optional entrypoint similar to `\\__validate__` but for transactions -meant to declare other contracts. - - -NOTE: Even though these entrypoints _can_ be called directly at the contract level, they are not designed for that, -but to be called by the Starknet OS in the transaction execution flow. - -=== Interface - -Notice that we haven't mentioned the parameters or the return values of these entrypoints. This is because function -selectors in Starknet are computed from the function name, without including the rest of the signature. This means -that the entrypoints can be implemented with any signature, and the protocol will be able to call them as long -as the function name is correct. - -In the following interface, we are using the `Array` for enabling multicall transactions. Note that we -don't need signature related parameters, because they are part of the transaction information that is accesible -using the global context (ex: `starknet::get_tx_info()`). +=== ISRC6 Interface [,javascript] ---- @@ -60,31 +36,6 @@ struct Call { calldata: Array } -trait BaseAccount { - /// Executes a transaction through the account. - fn __execute__(calls: Array) -> Array>; - - /// Asserts whether the transaction is valid to be executed. - fn __validate__(calls: Array) -> felt252; - - // (Optional) Asserts whether the transaction is valid to be declared. - fn __validate_declare__(class_hash: felt252) -> felt252; -} ----- - -== Standard Account Interface - -In the previous section we've presented the minimal interface a contract must implement to act as an account by -propagating transactions through the network. However, this interface lacks some features required for supporting -interoperability among accounts and DApps in the ecosystem. For example, there is no mechanism for -recognizing on-chain whether a contract is an Account or not. - -To address this issue, we have the {snip-6}[SNIP-6] proposal, which defines a standard interface for account contracts. - -=== ISRC6 Interface - -[,javascript] ----- /// Standard Account Interface trait ISRC6 { /// Executes a transaction through the account. @@ -120,6 +71,26 @@ trait ISRC5 { Even though these interfaces are not enforced by the protocol, it's recommended to implement them for enabling interoperability with the ecosystem. + +== Protocol-level methods + +In this section we will describe the methods that the protocol uses for abstracting the accounts. The first two +are required for enabling accounts to be used for executing transactions. The rest are optional: + +1. `\\__validate__` verifies the validity of the transaction to be executed. This is usually used to validate signatures, +but following the account abstraction design, the entrypoint implementation can be customized to feature any +validation mechanism. + +2. `\\__execute__` executes the transaction if the validation is successful. + +3. `\\__validate_declare__` optional entrypoint similar to `\\__validate__` but for transactions +meant to declare other contracts. + +4. `\\__validate_deploy__` optional entrypoint similar to `\\__validate__` but meant for {counterfactual}. + +NOTE: Even though these entrypoints _can_ be called directly at the contract level, they are not designed for that, +but to be called by the Starknet OS in the transaction execution flow. + == Deploying an account In Starknet there are two ways of deploying smart contracts: using the `deploy_syscall` and doing @@ -129,4 +100,4 @@ wraps and exposes the `deploy_syscall` to provide arbitrary deployments through But if you don't have an account to invoke it, you will probably want to use the latter. To do counterfactual deployments, you need to implement another protocol-level entrypoint named -`\\__validate_deploy__`. You can check the xref:/guides/deployment.adoc[Counterfactual Deployments] guide to learn how. +`\\__validate_deploy__`. You can check the {counterfactual} guide to learn how. From 68e59be5842037ba763ffcc08e04904ef0bba71c Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 13:47:51 +0200 Subject: [PATCH 59/88] Update docs/modules/ROOT/pages/api/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 22e37674b..9153a3d70 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -69,7 +69,7 @@ to restrict their use to the owner. [[Ownable-assert_only_owner]] ==== `[.contract-item-name]#++assert_only_owner++#++(self: @ContractState)++` [.item-kind]#internal# -Throws if called by any account other than the owner. +Panics if called by any account other than the owner. [#Ownable-Functions] ==== Functions From 51998270dc3f1887201b4687256b8eb6e7b90e82 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 14:03:59 +0200 Subject: [PATCH 60/88] Update docs/modules/ROOT/pages/api/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 9153a3d70..1e25522bd 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -356,7 +356,7 @@ accounts that have been granted it. [[AccessControl-assert_only_role]] ==== `[.contract-item-name]#++assert_only_role++#++(self: @ContractState, role: felt252)++` [.item-kind]#internal# -Throws if called by any account without the given `role`. +Panics if called by any account without the given `role`. [#AccessControl-Functions] ==== Functions From 0052f4c5b158b7ff3c00d491e22bef8625b2eae7 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 14:04:17 +0200 Subject: [PATCH 61/88] Update docs/modules/ROOT/pages/api/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 1e25522bd..a8caa1963 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -377,7 +377,7 @@ Emits a {RoleAdminChanged} event. [.contract-item] [[AccessControl-_grant_role]] -==== `[.contract-item-name]#++_grant_role++#++(ref self: ContractState, role: felt252, account: ContractState)++` [.item-kind]#internal# +==== `[.contract-item-name]#++_grant_role++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#internal# Grants `role` to `account`. From aa81069cc27ed8918f2849357b5bd102e6d08060 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 14:04:25 +0200 Subject: [PATCH 62/88] Update docs/modules/ROOT/pages/api/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index a8caa1963..4d86c8cc9 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -387,7 +387,7 @@ May emit a {RoleGranted} event. [.contract-item] [[AccessControl-_revoke_role]] -==== `[.contract-item-name]#++_revoke_role++#++(ref self: ContractState, role: felt252, account: ContractState)++` [.item-kind]#internal# +==== `[.contract-item-name]#++_revoke_role++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#internal# Revokes `role` from `account`. From d89710460db14495e0f573128ac61e89b14c94c4 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 11 Sep 2023 14:12:29 +0200 Subject: [PATCH 63/88] feat: apply review updates --- docs/modules/ROOT/pages/access.adoc | 2 ++ docs/modules/ROOT/pages/api/access.adoc | 16 +++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index c488eb247..a9dcdaa6a 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -389,6 +389,8 @@ Some ideas to consider: * Use Cairo friendly hashing algorithms like Poseidon, which are implemented in the https://github.com/starkware-libs/cairo/blob/main/corelib/src/poseidon.cairo[Cairo corelib]. +TIP: The `selector!` macro can be used for computing the {sn_keccak} in Cairo. + === Interface This is the full interface a contract must implement to be compliant with the `AccessControl` implementation: diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 22e37674b..b04b53424 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -1,6 +1,8 @@ :github-icon: pass:[] :AccessControl: xref:AccessControl[AccessControl] :Ownable: xref:Ownable[Ownable] +:src5: https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md[SRC5] +:_set_role_admin: xref:#AccessControl-_set_role_admin[_set_role_admin] = Access Control @@ -9,10 +11,10 @@ NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/ This directory provides ways to restrict who can access the functions of a contract or when they can do it. +- {Ownable} is a simple mechanism with a single owner "role" that can be assigned to a single account. +This mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. - {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. -- {Ownable} is a simpler mechanism with a single owner "role" that can be assigned to a single account. -This simpler mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. == Authorization @@ -140,7 +142,8 @@ Emitted when the ownership is transferred. use openzeppelin::access::accesscontrol::interface::IAccessControl; ``` -External interface of AccessControl declared to support https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md[SRC5] detection. +External interface of AccessControl declared to support {src5} detection. +The {src5} ID for this interface is `0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f970ca6844500a56ff61751`. [.contract-index] .Functions @@ -178,7 +181,7 @@ Returns `true` if `account` has been granted `role`. Returns the admin role that controls `role`. See {grant_role} and {revoke_role}. -To change a role's admin, use {AccessControl-_setRoleAdmin}. +To change a role's admin, use {_set_role_admin}. [.contract-item] [[IAccessControl-grant_role]] @@ -261,7 +264,6 @@ Emitted when `account` is revoked `role`. :assert_only_role: xref:#AccessControl-assert_only_role :grant_role: xref:#AccessControl-grant_role[grant_role] :revoke_role: xref:#AccessControl-revoke_role[revoke_role] -:set_role_admin: xref:#AccessControl-set_role_admin[set_role_admin] [.hljs-theme-light.nopadding] ```javascript @@ -371,7 +373,7 @@ Initializes the contract by registering the IAccessControl interface ID. [[AccessControl-_set_role_admin]] ==== `[.contract-item-name]#++_set_role_admin++#++(ref self: ContractState, role: felt252, admin_role: felt252)++` [.item-kind]#internal# -Sets `adminRole` as ``role``'s admin role. +Sets `admin_role` as ``role``'s admin role. Emits a {RoleAdminChanged} event. @@ -408,7 +410,7 @@ Returns `true` if `account` has been granted `role`. Returns the admin role that controls `role`. See {grant_role} and {revoke_role}. -To change a role's admin, use {_setRoleAdmin}. +To change a role's admin, use {_set_role_admin}. [.contract-item] [[AccessControl-grant_role_]] From 184b536958d55eb99fc06847aef4c4c1abcd0caa Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 14 Sep 2023 12:22:42 +0200 Subject: [PATCH 64/88] Update docs/modules/ROOT/pages/accounts.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/accounts.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 28cab2ee5..4f026b239 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -78,8 +78,7 @@ In this section we will describe the methods that the protocol uses for abstract are required for enabling accounts to be used for executing transactions. The rest are optional: 1. `\\__validate__` verifies the validity of the transaction to be executed. This is usually used to validate signatures, -but following the account abstraction design, the entrypoint implementation can be customized to feature any -validation mechanism. +but the entrypoint implementation can be customized to feature any validation mechanism https://docs.starknet.io/documentation/architecture_and_concepts/Accounts/validate_and_execute/#validate_limitations[with some limitations]. 2. `\\__execute__` executes the transaction if the validation is successful. From 000672a1542f9a5819c60802eaec52a973ae1b44 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 15 Sep 2023 12:08:29 +0200 Subject: [PATCH 65/88] feat: apply review updates --- docs/modules/ROOT/pages/accounts.adoc | 3 +-- docs/modules/ROOT/pages/api/account.adoc | 2 -- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/docs/modules/ROOT/pages/accounts.adoc b/docs/modules/ROOT/pages/accounts.adoc index 28cab2ee5..128071b73 100644 --- a/docs/modules/ROOT/pages/accounts.adoc +++ b/docs/modules/ROOT/pages/accounts.adoc @@ -88,8 +88,7 @@ meant to declare other contracts. 4. `\\__validate_deploy__` optional entrypoint similar to `\\__validate__` but meant for {counterfactual}. -NOTE: Even though these entrypoints _can_ be called directly at the contract level, they are not designed for that, -but to be called by the Starknet OS in the transaction execution flow. +NOTE: Although these entrypoints are available to the protocol for its regular transaction flow, they can also be called like any other method. == Deploying an account diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 203006599..52ed25191 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -11,7 +11,6 @@ Reference of interfaces, presets, and utilities related to account contracts. [[ISRC6]] === `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/account/interface.cairo#L12[{github-icon},role=heading-link] -[.hljs-theme-light.nopadding] ```javascript use openzeppelin::account::interface::ISRC6; ``` @@ -62,7 +61,6 @@ Returns the short string `'VALID'` if valid, otherwise it reverts. :OwnerAdded: xref:Account-OwnerAdded[OwnerAdded] :OwnerRemoved: xref:Account-OwnerRemoved[OwnerRemoved] -[.hljs-theme-light.nopadding] ```javascript use openzeppelin::account::Account; ``` From cacfc1201b0aa9d7e819ee09ec8eb80f2813c4ad Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 15 Sep 2023 12:24:47 +0200 Subject: [PATCH 66/88] Update docs/modules/ROOT/pages/access.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index a9dcdaa6a..e62108d32 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -385,7 +385,7 @@ Cairo field elements (`felt252`) store a maximum of 252 bits. With this discrepancy, this library maintains an agnostic stance on how contracts should create identifiers. Some ideas to consider: -* Use the {sn_keccak} instead. +* Use {sn_keccak} instead. * Use Cairo friendly hashing algorithms like Poseidon, which are implemented in the https://github.com/starkware-libs/cairo/blob/main/corelib/src/poseidon.cairo[Cairo corelib]. From 285ec60bc171a46a37d1dd6260c5c3f6f38f2f29 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 15 Sep 2023 12:25:02 +0200 Subject: [PATCH 67/88] Update docs/modules/ROOT/pages/access.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index e62108d32..bec092ba4 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -389,7 +389,7 @@ Some ideas to consider: * Use Cairo friendly hashing algorithms like Poseidon, which are implemented in the https://github.com/starkware-libs/cairo/blob/main/corelib/src/poseidon.cairo[Cairo corelib]. -TIP: The `selector!` macro can be used for computing the {sn_keccak} in Cairo. +TIP: The `selector!` macro can be used to compute {sn_keccak} in Cairo. === Interface From f1c86bbdbc2359389392598ecdf65f9d621f00f4 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 15 Sep 2023 12:56:20 +0200 Subject: [PATCH 68/88] Update docs/modules/ROOT/pages/access.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index bec092ba4..b03420f4d 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -174,7 +174,7 @@ CAUTION: Make sure you fully understand how xref:api/access.adoc#AccessControl[A using it on your system, or copy-pasting the examples from this guide. While clear and explicit, this isn't anything we wouldn't have been able to achieve with -xref:api/access.adoc#Ownable[Ownable]. Where `AccessControl` shines is in scenarios where granular +xref:api/access.adoc#Ownable[Ownable]. Where `AccessControl` shines the most is in scenarios where granular permissions are required, which can be implemented by defining _multiple_ roles. Let's augment our ERC20 token example by also defining a 'burner' role, which lets accounts destroy tokens: From 99d1acb327c55d735d29f3c76c8bfc1f0a4b8742 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 15 Sep 2023 13:11:35 +0200 Subject: [PATCH 69/88] feat: apply review updates --- docs/modules/ROOT/pages/access.adoc | 45 +++++++++++-------------- docs/modules/ROOT/pages/api/access.adoc | 39 +++++++++++---------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index a9dcdaa6a..19b00bd0b 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -21,7 +21,7 @@ OpenZeppelin Contracts for Cairo provides {ownable-cairo} for implementing owner Integrating this module into a contract first requires assigning an owner. The implementing contract's constructor should set the initial owner by passing the owner's address to Ownable's -`initializer` like this: +xref:/api/access.adoc#AccessControl-initializer[`initializer`] like this: [,javascript] ---- @@ -49,17 +49,17 @@ To restrict a function's access to the owner only, add in the `assert_only_owner [,javascript] ---- - -use openzeppelin::access::ownable::Ownable; - #[starknet::contract] mod Contract { + use openzeppelin::access::ownable::Ownable; + (...) #[external(v0)] fn foo(ref self: ContractState) { // This function can only be called by the owner - self.assert_only_owner(); + let unsafe_state = Ownable::unsafe_new_contract_state(); + Ownable::InternalImpl::assert_only_owner(@unsafe_state); (...) } @@ -102,7 +102,7 @@ flexibility in this regard. In essence, we will be defining multiple roles, each allowed to perform different sets of actions. An account may have, for example, 'moderator', 'minter' or 'admin' roles, which you will then check for -instead of simply using `assert_only_owner`. This check can be enforced through `assert_only_role`. +instead of simply using xref:/api/access.adoc#Ownable-assert_only_owner[`assert_only_owner`]. This check can be enforced through xref:/api/access.adoc#AccessControl-assert_only_role[`assert_only_role`]. Separately, you will be able to define rules for how accounts can be granted a role, have it revoked, and more. Most software uses access control systems that are role-based: some users are regular users, some may be supervisors @@ -120,8 +120,7 @@ and sets a 'minter' role: [,javascript] ---- // sn_keccak('MINTER_ROLE') -const MINTER_ROLE: felt252 = - 0x32df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6; +const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); #[starknet::contract] mod Contract { @@ -181,12 +180,8 @@ Let's augment our ERC20 token example by also defining a 'burner' role, which le [,javascript] ---- -// sn_keccak('MINTER_ROLE') -const MINTER_ROLE: felt252 = - 0x32df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6; -// sn_keccak('BURNER_ROLE') -const BURNER_ROLE: felt252 = - 0x11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848; +const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); +const BURNER_ROLE: felt252 = selector!('BURNER_ROLE'); #[starknet::contract] mod Contract { @@ -225,7 +220,7 @@ mod Contract { AccessControl::InternalImpl::_grant_role( ref access_state, BURNER_ROLE, - minter + burner ); } @@ -260,13 +255,16 @@ security practice. Note that each account may still have more than one role, if === Granting and revoking roles -The ERC20 token example above uses `_grant_role`, an `internal` function that is useful when programmatically assigning +The ERC20 token example above uses xref:api/access.adoc#AccessControl-_grant_role[`_grant_role`], +an `internal` function that is useful when programmatically assigning roles (such as during construction). But what if we later want to grant the 'minter' role to additional accounts? By default, *accounts with a role cannot grant it or revoke it from other accounts*: all having a role does is making -the `assert_only_role` check pass. To grant and revoke roles dynamically, you will need help from the role's _admin_. +the xref:api/access.adoc#AccessControl-assert_only_role[`assert_only_role`] check pass. To grant and revoke roles dynamically, you will need help from the role's _admin_. -Every role has an associated admin role, which grants permission to call the `grant_role` and `revoke_role` functions. +Every role has an associated admin role, which grants permission to call the +xref:api/access.adoc#AccessControl-grant_role[`grant_role`] and +xref:api/access.adoc#AccessControl-revoke_role[`revoke_role`] functions. A role can be granted or revoked by using these if the calling account has the corresponding admin role. Multiple roles may have the same admin role to make management easier. A role's admin can even be the same role itself, which would cause accounts with that role to be able @@ -275,18 +273,15 @@ to also grant and revoke it. This mechanism can be used to create complex permissioning structures resembling organizational charts, but it also provides an easy way to manage simpler applications. `AccessControl` includes a special role with the role identifier of `0`, called `DEFAULT_ADMIN_ROLE`, which acts as the *default admin role for all roles*. -An account with this role will be able to manage any other role, unless `_set_role_admin` is used to select a new admin role. +An account with this role will be able to manage any other role, unless +xref:api/access.adoc#AccessControl-_set_role_admin[`_set_role_admin`] is used to select a new admin role. Let's take a look at the ERC20 token example, this time taking advantage of the default admin role: [,javascript] ---- -// sn_keccak('MINTER_ROLE') -const MINTER_ROLE: felt252 = - 0x32df0fed2c77648de5860a4cc508cd0818c85b8b8a1ab4ceeef8d981c8956a6; -// sn_keccak('BURNER_ROLE') -const BURNER_ROLE: felt252 = - 0x11d16cbaffd01df69ce1c404f6340ee057498f5f00246190ea54220576a848; +const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); +const BURNER_ROLE: felt252 = selector!('BURNER_ROLE'); #[starknet::contract] mod Contract { diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 02d468373..56e5bdf45 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -22,7 +22,6 @@ assigned each to multiple accounts. [[Ownable]] === `++Ownable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/access/ownable/ownable.cairo[{github-icon},role=heading-link] -[.hljs-theme-light.nopadding] ```javascript use openzeppelin::access::ownable::Ownable; ``` @@ -137,13 +136,17 @@ Emitted when the ownership is transferred. :RoleRevoked: xref:#IAccessControl-RoleRevoked[RoleRevoked] :RoleAdminChanged: xref:#IAccessControl-RoleAdminChanged[RoleAdminChanged] -[.hljs-theme-light.nopadding] ```javascript use openzeppelin::access::accesscontrol::interface::IAccessControl; ``` -External interface of AccessControl declared to support {src5} detection. -The {src5} ID for this interface is `0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f970ca6844500a56ff61751`. +External interface of AccessControl. + +[.contract-index] +.Interface ID +-- +0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f970ca6844500a56ff61751 +-- [.contract-index] .Functions @@ -153,7 +156,6 @@ The {src5} ID for this interface is `0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f * xref:IAccessControl-grant_role[`++grant_role(role, account)++`] * xref:IAccessControl-revoke_role[`++revoke_role(role, account)++`] * xref:IAccessControl-renounce_role[`++renounce_role(role, account)++`] - -- [.contract-index] @@ -265,7 +267,6 @@ Emitted when `account` is revoked `role`. :grant_role: xref:#AccessControl-grant_role[grant_role] :revoke_role: xref:#AccessControl-revoke_role[revoke_role] -[.hljs-theme-light.nopadding] ```javascript use openzeppelin::access::accesscontrol::AccessControl; ``` @@ -313,20 +314,12 @@ accounts that have been granted it. [.contract-index] .Utilities -- -* xref:#AccessControl-assert_only_role[`++InternalImpl::assert_only_role(self: @ContractState, role: felt252)++`] +* xref:#AccessControl-assert_only_role[`++InternalImpl::assert_only_role(self, role)++`] -- [.contract-index] -.Functions +.External Functions -- -[.contract-subindex-inherited] -.InternalImpl - -* xref:#AccessControl-initializer[`++initializer(self)++`] -* xref:#AccessControl-_set_role_admin[`++_set_role_admin(self, role, admin_role)++`] -* xref:#AccessControl-_grant_role[`++_grant_role(self, role, account)++`] -* xref:#AccessControl-_revoke_role[`++_revoke_role(self, role, account)++`] - [.contract-subindex-inherited] .AccessControlImpl @@ -341,6 +334,18 @@ accounts that have been granted it. * xref:#AccessControl-supports_interface[`++supports_interface(self, interface_id: felt252)++`] -- +[.contract-index] +.Internal Functions +-- +[.contract-subindex-inherited] +.InternalImpl + +* xref:#AccessControl-initializer[`++initializer(self)++`] +* xref:#AccessControl-_set_role_admin[`++_set_role_admin(self, role, admin_role)++`] +* xref:#AccessControl-_grant_role[`++_grant_role(self, role, account)++`] +* xref:#AccessControl-_revoke_role[`++_revoke_role(self, role, account)++`] +-- + [.contract-index] .Events -- @@ -413,7 +418,7 @@ Returns the admin role that controls `role`. See {grant_role} and To change a role's admin, use {_set_role_admin}. [.contract-item] -[[AccessControl-grant_role_]] +[[AccessControl-grant_role]] ==== `[.contract-item-name]#++grant_role++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#external# Grants `role` to `account`. From b157eb99b8182f3727b0ad265f8f0d6380ee4105 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Mon, 18 Sep 2023 15:57:01 +0200 Subject: [PATCH 70/88] feat: apply review updates --- docs/modules/ROOT/pages/access.adoc | 7 +- docs/modules/ROOT/pages/api/access.adoc | 121 ++++++++++++------------ 2 files changed, 65 insertions(+), 63 deletions(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index 4e18aa246..fe71a021e 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -410,7 +410,6 @@ trait IAccessControl { } ---- -AccessControl also lets you: - -- `renounce_role` from the calling account. The method expects an account as input as an extra security measure, to -ensure you are not renuncing a role from an unintended account. +`AccessControl` also lets you `renounce_role` from the calling account. +The method expects an account as input as an extra security measure, to ensure you are +not renuncing a role from an unintended account. diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 56e5bdf45..c3483e412 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -2,6 +2,7 @@ :AccessControl: xref:AccessControl[AccessControl] :Ownable: xref:Ownable[Ownable] :src5: https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md[SRC5] +:inner-src5: xref:api/introspection.adoc#ISRC5[SRC5] :_set_role_admin: xref:#AccessControl-_set_role_admin[_set_role_admin] = Access Control @@ -40,21 +41,24 @@ to restrict their use to the owner. -- [.contract-index] -.Functions +.External Functions -- -[.contract-subindex-inherited] -.InternalImpl - -* xref:Ownable-initializer[`++initializer(self, owner)++`] -* xref:Ownable-_transfer_ownership[`++_transfer_ownership(self, new_owner)++`] - [.contract-subindex-inherited] .OwnableImpl * xref:Ownable-owner[`++owner(self)++`] * xref:Ownable-renounce_ownership[`++renounce_ownership(self)++`] * xref:Ownable-transfer_ownership[`++transfer_ownership(self, new_owner)++`] +-- + +[.contract-index] +.Internal Functions +-- +[.contract-subindex-inherited] +.InternalImpl +* xref:Ownable-initializer[`++initializer(self, owner)++`] +* xref:Ownable-_transfer_ownership[`++_transfer_ownership(self, new_owner)++`] -- [.contract-index] @@ -75,23 +79,6 @@ Panics if called by any account other than the owner. [#Ownable-Functions] ==== Functions -[.contract-item] -[[Ownable-initializer]] -==== `[.contract-item-name]#++initializer++#++(ref self: ContractState, owner: ContractAddress)++` [.item-kind]#internal# - -Initializes the contract setting `owner` as the initial owner. - -Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. - -[.contract-item] -[[Ownable-_transfer_ownership]] -==== `[.contract-item-name]#++_transfer_ownership++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#internal# - -Transfers ownership of the contract to a new account (`new_owner`). -Internal function without access restriction. - -Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. - [.contract-item] [[Ownable-owner]] ==== `[.contract-item-name]#++owner++#++(self: @ContractState) → ContractAddress++` [.item-kind]#external# @@ -117,6 +104,23 @@ Can only be called by the current owner. Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. +[.contract-item] +[[Ownable-initializer]] +==== `[.contract-item-name]#++initializer++#++(ref self: ContractState, owner: ContractAddress)++` [.item-kind]#internal# + +Initializes the contract setting `owner` as the initial owner. + +Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. + +[.contract-item] +[[Ownable-_transfer_ownership]] +==== `[.contract-item-name]#++_transfer_ownership++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#internal# + +Transfers ownership of the contract to a new account (`new_owner`). +Internal function without access restriction. + +Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. + [#Ownable-Events] ==== Events @@ -143,7 +147,7 @@ use openzeppelin::access::accesscontrol::interface::IAccessControl; External interface of AccessControl. [.contract-index] -.Interface ID +.{inner-src5} ID -- 0x23700be02858dbe2ac4dc9c9f66d0b6b0ed81ec7f970ca6844500a56ff61751 -- @@ -368,40 +372,6 @@ Panics if called by any account without the given `role`. [#AccessControl-Functions] ==== Functions -[.contract-item] -[[AccessControl-initializer]] -==== `[.contract-item-name]#++initializer++#++(ref self: ContractState)++` [.item-kind]#internal# - -Initializes the contract by registering the IAccessControl interface ID. - -[.contract-item] -[[AccessControl-_set_role_admin]] -==== `[.contract-item-name]#++_set_role_admin++#++(ref self: ContractState, role: felt252, admin_role: felt252)++` [.item-kind]#internal# - -Sets `admin_role` as ``role``'s admin role. - -Emits a {RoleAdminChanged} event. - -[.contract-item] -[[AccessControl-_grant_role]] -==== `[.contract-item-name]#++_grant_role++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#internal# - -Grants `role` to `account`. - -Internal function without access restriction. - -May emit a {RoleGranted} event. - -[.contract-item] -[[AccessControl-_revoke_role]] -==== `[.contract-item-name]#++_revoke_role++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#internal# - -Revokes `role` from `account`. - -Internal function without access restriction. - -May emit a {RoleRevoked} event. - [.contract-item] [[AccessControl-has_role]] ==== `[.contract-item-name]#++has_role++#++(self: @ContractState, role: felt252, account: ContractAddress) → bool++` [.item-kind]#external# @@ -471,6 +441,39 @@ May emit a {RoleRevoked} event. Returns whether a contract implements a given interface or not. +[.contract-item] +[[AccessControl-initializer]] +==== `[.contract-item-name]#++initializer++#++(ref self: ContractState)++` [.item-kind]#internal# + +Initializes the contract by registering the IAccessControl interface ID. + +[.contract-item] +[[AccessControl-_set_role_admin]] +==== `[.contract-item-name]#++_set_role_admin++#++(ref self: ContractState, role: felt252, admin_role: felt252)++` [.item-kind]#internal# + +Sets `admin_role` as ``role``'s admin role. + +Emits a {RoleAdminChanged} event. + +[.contract-item] +[[AccessControl-_grant_role]] +==== `[.contract-item-name]#++_grant_role++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#internal# + +Grants `role` to `account`. + +Internal function without access restriction. + +May emit a {RoleGranted} event. + +[.contract-item] +[[AccessControl-_revoke_role]] +==== `[.contract-item-name]#++_revoke_role++#++(ref self: ContractState, role: felt252, account: ContractAddress)++` [.item-kind]#internal# + +Revokes `role` from `account`. + +Internal function without access restriction. + +May emit a {RoleRevoked} event. [#AccessControl-Events] ==== Events From 01f24143cbccbeffe3860e13b711f8402bb2ae80 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 22 Sep 2023 16:52:44 +0200 Subject: [PATCH 71/88] Update docs/modules/ROOT/pages/api/access.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index c3483e412..bfda414c1 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -12,7 +12,7 @@ NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/ This directory provides ways to restrict who can access the functions of a contract or when they can do it. -- {Ownable} is a simple mechanism with a single owner "role" that can be assigned to a single account. +- {Ownable} is a simple mechanism with a single "owner" role that can be assigned to a single account. This mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. - {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. From b31322f0b47f888ff596a77726d514206b1225c0 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 22 Sep 2023 16:53:13 +0200 Subject: [PATCH 72/88] Update docs/modules/ROOT/pages/api/access.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index bfda414c1..90ec53c9b 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -13,7 +13,7 @@ NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/ This directory provides ways to restrict who can access the functions of a contract or when they can do it. - {Ownable} is a simple mechanism with a single "owner" role that can be assigned to a single account. -This mechanism can be useful for quick tests but projects with production concerns are likely to outgrow it. +This mechanism can be useful in simple scenarios, but fine grained access needs are likely to outgrow it. - {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. From 72d8b8f71d7de1ddd6924404c4f45a341169df98 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 22 Sep 2023 16:53:59 +0200 Subject: [PATCH 73/88] Update docs/modules/ROOT/pages/api/access.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/access.adoc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 90ec53c9b..dbbb17726 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -27,9 +27,8 @@ assigned each to multiple accounts. use openzeppelin::access::ownable::Ownable; ``` -Contract module which provides a basic access control mechanism, where -there is an account (an owner) that can be granted exclusive access to -specific functions. +`Ownable` provides a basic access control mechanism where an account + (an owner) can be granted exclusive access to specific functions. This module provides an internal utility named `assert_only_owner`, which can be applied to your functions to restrict their use to the owner. From 185af3eb05509c7ae0d4c7d39d6f5d6c1cb4faec Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Fri, 22 Sep 2023 16:54:38 +0200 Subject: [PATCH 74/88] Update docs/modules/ROOT/pages/api/access.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/api/access.adoc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index dbbb17726..9cefbfbbd 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -30,8 +30,7 @@ use openzeppelin::access::ownable::Ownable; `Ownable` provides a basic access control mechanism where an account (an owner) can be granted exclusive access to specific functions. -This module provides an internal utility named `assert_only_owner`, which can be applied to your functions -to restrict their use to the owner. +This module includes the `assert_only_owner` internal to restrict a function to be used only by the owner. [.contract-index] .Utilities From a6fad1a822a935b1030516547dbeac801b20b62d Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Sat, 23 Sep 2023 19:10:59 +0200 Subject: [PATCH 75/88] Update docs/modules/ROOT/pages/access.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index fe71a021e..2fd102c44 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -68,7 +68,7 @@ mod Contract { === Interface -This is the full interface a contract must implement to be compliant with the `Ownable` implementation: +This is the full interface of the `Ownable` implementation: [,javascript] ---- From 92269ddfd8c48ab6c17f77c2ca122bf650127be9 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Sat, 23 Sep 2023 19:11:08 +0200 Subject: [PATCH 76/88] Update docs/modules/ROOT/pages/access.adoc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Martín Triay --- docs/modules/ROOT/pages/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index 2fd102c44..276aab39a 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -388,7 +388,7 @@ TIP: The `selector!` macro can be used to compute {sn_keccak} in Cairo. === Interface -This is the full interface a contract must implement to be compliant with the `AccessControl` implementation: +This is the full interface of the `AccessControl` implementation: [,javascript] ---- From 853ca701063bca336e3bdf3febba4b7bff4184ee Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Sat, 23 Sep 2023 19:12:30 +0200 Subject: [PATCH 77/88] feat: apply review updates --- docs/modules/ROOT/pages/access.adoc | 10 +++++----- docs/modules/ROOT/pages/api/access.adoc | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index fe71a021e..753c9d9fb 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -28,7 +28,7 @@ xref:/api/access.adoc#AccessControl-initializer[`initializer`] like this: use openzeppelin::access::ownable::Ownable; #[starknet::contract] -mod Contract { +mod MyContract { use starknet::ContractAddress; use super::Ownable; @@ -50,7 +50,7 @@ To restrict a function's access to the owner only, add in the `assert_only_owner [,javascript] ---- #[starknet::contract] -mod Contract { +mod MyContract { use openzeppelin::access::ownable::Ownable; (...) @@ -123,7 +123,7 @@ and sets a 'minter' role: const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); #[starknet::contract] -mod Contract { +mod MyContract { use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::token::erc20::ERC20; @@ -184,7 +184,7 @@ const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); const BURNER_ROLE: felt252 = selector!('BURNER_ROLE'); #[starknet::contract] -mod Contract { +mod MyContract { use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::token::erc20::ERC20; @@ -284,7 +284,7 @@ const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); const BURNER_ROLE: felt252 = selector!('BURNER_ROLE'); #[starknet::contract] -mod Contract { +mod MyContract { use openzeppelin::access::accesscontrol::AccessControl::InternalImpl::assert_only_role; use openzeppelin::access::accesscontrol::AccessControl; use openzeppelin::access::accesscontrol::DEFAULT_ADMIN_ROLE; diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 694e73c57..99d62a07b 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -39,8 +39,8 @@ This module includes the `assert_only_owner` internal to restrict a function to .OwnableImpl * xref:Ownable-owner[`++owner(self)++`] -* xref:Ownable-renounce_ownership[`++renounce_ownership(self)++`] * xref:Ownable-transfer_ownership[`++transfer_ownership(self, new_owner)++`] +* xref:Ownable-renounce_ownership[`++renounce_ownership(self)++`] -- [.contract-index] @@ -69,6 +69,15 @@ This module includes the `assert_only_owner` internal to restrict a function to Returns the address of the current owner. +[.contract-item] +[[Ownable-transfer_ownership]] +==== `[.contract-item-name]#++transfer_ownership++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#external# + +Transfers ownership of the contract to a new account (`new_owner`). +Can only be called by the current owner. + +Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. + [.contract-item] [[Ownable-renounce_ownership--]] ==== `[.contract-item-name]#++renounce_ownership++#++(ref self: ContractState)++` [.item-kind]#external# @@ -79,15 +88,6 @@ Leaves the contract without owner. It will not be possible to call NOTE: Renouncing ownership will leave the contract without an owner, thereby removing any functionality that is only available to the owner. -[.contract-item] -[[Ownable-transfer_ownership]] -==== `[.contract-item-name]#++transfer_ownership++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#external# - -Transfers ownership of the contract to a new account (`new_owner`). -Can only be called by the current owner. - -Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. - [#Ownable-Internal-Functions] ==== Internal Functions From e08f7b767dcb161ae5a7fdbe33e085c319f59dfe Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Tue, 26 Sep 2023 21:30:51 +0200 Subject: [PATCH 78/88] feat: remove sn_keccak in comments --- docs/modules/ROOT/pages/access.adoc | 1 - docs/modules/ROOT/pages/api/access.adoc | 1 - 2 files changed, 2 deletions(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index 1fb1e262c..e413e4c0a 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -119,7 +119,6 @@ and sets a 'minter' role: [,javascript] ---- -// sn_keccak('MINTER_ROLE') const MINTER_ROLE: felt252 = selector!('MINTER_ROLE'); #[starknet::contract] diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 99d62a07b..6824864b8 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -272,7 +272,6 @@ Contract module that allows children to implement role-based access control mech Roles are referred to by their `felt252` identifier: ```javascript -// sn_keccak('MY_ROLE') const MY_ROLE: felt252 = selector!('MY_ROLE'); ``` From 5d5f924e24b73a29bec383e5f652e41fe579af5f Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 27 Sep 2023 16:23:04 +0200 Subject: [PATCH 79/88] feat: replace cairo-2 with replace-0.7.0 --- docs/modules/ROOT/pages/access.adoc | 2 +- docs/modules/ROOT/pages/api/access.adoc | 4 ++-- docs/modules/ROOT/pages/api/account.adoc | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index e413e4c0a..8c204da9b 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -1,4 +1,4 @@ -:ownable-cairo: link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/access/ownable/ownable.cairo[Ownable] +:ownable-cairo: link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-0.7.0/src/access/ownable/ownable.cairo[Ownable] :sn_keccak: https://docs.starknet.io/documentation/architecture_and_concepts/Cryptography/hash-functions/#starknet_keccak[sn_keccak] :extensibility-pattern: xref:extensibility.adoc#the_pattern diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 6824864b8..12dc81da7 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -21,7 +21,7 @@ assigned each to multiple accounts. [.contract] [[Ownable]] -=== `++Ownable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/access/ownable/ownable.cairo[{github-icon},role=heading-link] +=== `++Ownable++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-0.7.0/src/access/ownable/ownable.cairo[{github-icon},role=heading-link] ```javascript use openzeppelin::access::ownable::Ownable; @@ -258,7 +258,7 @@ Emitted when `account` is revoked `role`. [.contract] [[AccessControl]] -=== `++AccessControl++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/access/accesscontrol/accesscontrol.cairo[{github-icon},role=heading-link] +=== `++AccessControl++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-0.7.0/src/access/accesscontrol/accesscontrol.cairo[{github-icon},role=heading-link] :assert_only_role: xref:#AccessControl-assert_only_role :grant_role: xref:#AccessControl-grant_role[grant_role] diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index 06b1830fd..ab66bc075 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -10,7 +10,7 @@ Reference of interfaces, presets, and utilities related to account contracts. [.contract] [[ISRC6]] -=== `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/account/interface.cairo#L12[{github-icon},role=heading-link] +=== `++ISRC6++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-0.7.0/src/account/interface.cairo#L12[{github-icon},role=heading-link] ```javascript use openzeppelin::account::interface::ISRC6; @@ -63,7 +63,7 @@ Returns the short string `'VALID'` if valid, otherwise it reverts. [.contract] [[Account]] -=== `++Account++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/cairo-2/src/account/account.cairo#L27[{github-icon},role=heading-link] +=== `++Account++` link:https://github.com/OpenZeppelin/cairo-contracts/blob/release-0.7.0/src/account/account.cairo#L27[{github-icon},role=heading-link] :OwnerAdded: xref:Account-OwnerAdded[OwnerAdded] :OwnerRemoved: xref:Account-OwnerRemoved[OwnerRemoved] From c8f493ca4f65db43214efa571745887ffe264b2a Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Wed, 27 Sep 2023 17:02:18 +0200 Subject: [PATCH 80/88] feat: remove grayed-out areas --- docs/modules/ROOT/pages/api/access.adoc | 6 ------ docs/modules/ROOT/pages/api/account.adoc | 5 ----- 2 files changed, 11 deletions(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 12dc81da7..83ae5cccf 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -35,7 +35,6 @@ This module includes the `assert_only_owner` internal to restrict a function to [.contract-index] .External Functions -- -[.contract-subindex-inherited] .OwnableImpl * xref:Ownable-owner[`++owner(self)++`] @@ -46,7 +45,6 @@ This module includes the `assert_only_owner` internal to restrict a function to [.contract-index] .Internal Functions -- -[.contract-subindex-inherited] .InternalImpl * xref:Ownable-initializer[`++initializer(self, owner)++`] @@ -309,7 +307,6 @@ accounts that have been granted it. [.contract-index] .External Functions -- -[.contract-subindex-inherited] .AccessControlImpl * xref:#AccessControl-has_role[`++has_role(self, role, account)++`] @@ -318,7 +315,6 @@ accounts that have been granted it. * xref:#AccessControl-revoke_role[`++revoke_role(self, role, account)++`] * xref:#AccessControl-renounce_role[`++renounce_role(self, role, account)++`] -[.contract-subindex-inherited] .SRC5Impl * xref:#AccessControl-supports_interface[`++supports_interface(self, interface_id: felt252)++`] -- @@ -326,7 +322,6 @@ accounts that have been granted it. [.contract-index] .Internal Functions -- -[.contract-subindex-inherited] .InternalImpl * xref:#AccessControl-initializer[`++initializer(self)++`] @@ -339,7 +334,6 @@ accounts that have been granted it. [.contract-index] .Events -- -[.contract-subindex-inherited] .IAccessControl * xref:#AccessControl-RoleAdminChanged[`++RoleAdminChanged(role, previous_admin_role, new_admin_role)++`] * xref:#AccessControl-RoleGranted[`++RoleGranted(role, account, sender)++`] diff --git a/docs/modules/ROOT/pages/api/account.adoc b/docs/modules/ROOT/pages/api/account.adoc index ab66bc075..942158af4 100644 --- a/docs/modules/ROOT/pages/api/account.adoc +++ b/docs/modules/ROOT/pages/api/account.adoc @@ -84,24 +84,20 @@ Account contract implementation extending xref:ISRC6[`ISRC6`]. -- * xref:#Account-\\__validate_deploy__[`++__validate_deploy__(self, hash, signature)++`] -[.contract-subindex-inherited] .SRC6Impl * xref:#Account-\\__execute__[`++__execute__(self, calls)++`] * xref:#Account-\\__validate__[`++__validate__(self, calls)++`] * xref:#Account-is_valid_signature[`++is_valid_signature(self, hash, signature)++`] -[.contract-subindex-inherited] .SRC5Impl * xref:#Account-supports_interface[`++supports_interface(self, interface_id)++`] -[.contract-subindex-inherited] .DeclarerImpl * xref:#Account-\\__validate_declare__[`++__validate_declare__(self, class_hash)++`] -[.contract-subindex-inherited] .PublicKeyImpl * xref:#Account-set_public_key[`++set_public_key(self, new_public_key)++`] @@ -111,7 +107,6 @@ Account contract implementation extending xref:ISRC6[`ISRC6`]. [.contract-index] .Internal Functions -- -[.contract-subindex-inherited] .InternalImpl * xref:#Account-initializer[`++initializer(self, _public_key)++`] From 05cca281726067ec3111d79bfe7518af7ed390d0 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 28 Sep 2023 15:48:14 +0200 Subject: [PATCH 81/88] Update docs/modules/ROOT/pages/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index 8c204da9b..9df7de509 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -411,4 +411,4 @@ trait IAccessControl { `AccessControl` also lets you `renounce_role` from the calling account. The method expects an account as input as an extra security measure, to ensure you are -not renuncing a role from an unintended account. +not renouncing a role from an unintended account. From ab14853308aa393385c75e31cc6f4ffccc90735d Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 28 Sep 2023 15:48:24 +0200 Subject: [PATCH 82/88] Update docs/modules/ROOT/pages/api/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 83ae5cccf..55f7effc7 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -13,7 +13,7 @@ NOTE: This document is better viewed at https://docs.openzeppelin.com/contracts/ This directory provides ways to restrict who can access the functions of a contract or when they can do it. - {Ownable} is a simple mechanism with a single "owner" role that can be assigned to a single account. -This mechanism can be useful in simple scenarios, but fine grained access needs are likely to outgrow it. +This mechanism can be useful in simple scenarios, but fine-grained access needs are likely to outgrow it. - {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. From a1e30120e4bf1a8bc0b74e3ff85f5ea235bb8e47 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 28 Sep 2023 15:48:32 +0200 Subject: [PATCH 83/88] Update docs/modules/ROOT/pages/api/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 55f7effc7..8627eb9f7 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -14,7 +14,7 @@ This directory provides ways to restrict who can access the functions of a contr - {Ownable} is a simple mechanism with a single "owner" role that can be assigned to a single account. This mechanism can be useful in simple scenarios, but fine-grained access needs are likely to outgrow it. -- {AccessControl} provides a general role based access control mechanism. Multiple hierarchical roles can be created and +- {AccessControl} provides a general role-based access control mechanism. Multiple hierarchical roles can be created and assigned each to multiple accounts. == Authorization From d5184e014f1207f9ae7d2e2bb0080bb0f4756044 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 28 Sep 2023 15:48:39 +0200 Subject: [PATCH 84/88] Update docs/modules/ROOT/pages/api/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 8627eb9f7..476b2f28b 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -93,7 +93,7 @@ thereby removing any functionality that is only available to the owner. [[Ownable-initializer]] ==== `[.contract-item-name]#++initializer++#++(ref self: ContractState, owner: ContractAddress)++` [.item-kind]#internal# -Initializes the contract setting `owner` as the initial owner. +Initializes the contract and sets `owner` as the initial owner. Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. From 4ef4b3c6ae91cb06e92ecbb794ec6306fb0857b0 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 28 Sep 2023 15:49:00 +0200 Subject: [PATCH 85/88] Update docs/modules/ROOT/pages/api/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 476b2f28b..2ad665cda 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -48,8 +48,8 @@ This module includes the `assert_only_owner` internal to restrict a function to .InternalImpl * xref:Ownable-initializer[`++initializer(self, owner)++`] -* xref:Ownable-_transfer_ownership[`++_transfer_ownership(self, new_owner)++`] * xref:Ownable-assert_only_owner[`++assert_only_owner(self)++`] +* xref:Ownable-_transfer_ownership[`++_transfer_ownership(self, new_owner)++`] -- [.contract-index] From bc08af596893e911b8c12341859ad17ccd3a027d Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 28 Sep 2023 15:49:32 +0200 Subject: [PATCH 86/88] Update docs/modules/ROOT/pages/api/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/api/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 2ad665cda..3ded78bb4 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -77,7 +77,7 @@ Can only be called by the current owner. Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. [.contract-item] -[[Ownable-renounce_ownership--]] +[[Ownable-renounce_ownership]] ==== `[.contract-item-name]#++renounce_ownership++#++(ref self: ContractState)++` [.item-kind]#external# Leaves the contract without owner. It will not be possible to call From 131949ea69b918ba122d81e1fe9f975432f34e30 Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 28 Sep 2023 15:55:48 +0200 Subject: [PATCH 87/88] feat: apply review updates --- docs/modules/ROOT/pages/api/access.adoc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/modules/ROOT/pages/api/access.adoc b/docs/modules/ROOT/pages/api/access.adoc index 3ded78bb4..1a00ffa31 100644 --- a/docs/modules/ROOT/pages/api/access.adoc +++ b/docs/modules/ROOT/pages/api/access.adoc @@ -97,6 +97,12 @@ Initializes the contract and sets `owner` as the initial owner. Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. +[.contract-item] +[[Ownable-assert_only_owner]] +==== `[.contract-item-name]#++assert_only_owner++#++(self: @ContractState)++` [.item-kind]#internal# + +Panics if called by any account other than the owner. + [.contract-item] [[Ownable-_transfer_ownership]] ==== `[.contract-item-name]#++_transfer_ownership++#++(ref self: ContractState, new_owner: ContractAddress)++` [.item-kind]#internal# @@ -106,12 +112,6 @@ Internal function without access restriction. Emits an xref:Ownable-OwnershipTransferred[OwnershipTransferred] event. -[.contract-item] -[[Ownable-assert_only_owner]] -==== `[.contract-item-name]#++assert_only_owner++#++(self: @ContractState)++` [.item-kind]#internal# - -Panics if called by any account other than the owner. - [#Ownable-Events] ==== Events @@ -419,7 +419,7 @@ Returns whether a contract implements a given interface or not. [[AccessControl-initializer]] ==== `[.contract-item-name]#++initializer++#++(ref self: ContractState)++` [.item-kind]#internal# -Initializes the contract by registering the IAccessControl interface ID. +Initializes the contract by registering the xref:#IAccessControl[IAccessControl] interface ID. [.contract-item] [[AccessControl-_set_role_admin]] From 8195e0ebbdb59e5e5a934c8514d5c5f9bd8f4fdd Mon Sep 17 00:00:00 2001 From: Eric Nordelo Date: Thu, 28 Sep 2023 18:34:15 +0200 Subject: [PATCH 88/88] Update docs/modules/ROOT/pages/access.adoc Co-authored-by: Andrew Fleming --- docs/modules/ROOT/pages/access.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/access.adoc b/docs/modules/ROOT/pages/access.adoc index 9df7de509..cf9b65989 100644 --- a/docs/modules/ROOT/pages/access.adoc +++ b/docs/modules/ROOT/pages/access.adoc @@ -4,7 +4,7 @@ = Access -Access control--that is, "who is allowed to do this thing"--is incredibly important in the world of smart contracts. +Access control--that is, "who is allowed to do this thing"—is incredibly important in the world of smart contracts. The access control of your contract may govern who can mint tokens, vote on proposals, freeze transfers, and many other things. It is therefore critical to understand how you implement it, lest someone else https://blog.openzeppelin.com/on-the-parity-wallet-multisig-hack-405a8c12e8f7/[steals your whole system].