From ade384f680b6e81b085b637f9264a357d91a7fe3 Mon Sep 17 00:00:00 2001 From: Julio <30329843+julio4@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:37:59 +0700 Subject: [PATCH 01/44] Prepare release 2.8.2 (#257) * dep: fix patch to latest shikijs for cairo hl * fix(app): correct sidebar placement * fix(app): responsive content centering * fix(app): responsive content centering * doc: branch guidelines * fix(app): top section nav links --- CONTRIBUTING.md | 6 + package.json | 8 + patches/vocs.patch | 1416 ++------------------------------------------ pnpm-lock.yaml | 135 +++-- routes.ts | 4 - styles.css | 95 +-- 6 files changed, 183 insertions(+), 1481 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1ac94b34..0543b466 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,6 +4,12 @@ When contributing to this repository, please first discuss the change you wish t Join the telegram channel: https://t.me/StarknetByExample +The release branch is `main`. The development branch is `dev` and is considered stable (but not released yet). +When you want to contribute, please create a new branch from `dev` and open a pull request to merge your changes back into `dev`. +You should never open a pull request to merge your changes directly into `main`. + +The `dev` branch is deployed at https://starknet-by-example-dev.voyager.online/ + Please note we have a code of conduct, please follow it in all your interactions with the project. ## Table of Contents diff --git a/package.json b/package.json index 032ce81a..4d683183 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,14 @@ "pnpm": { "patchedDependencies": { "vocs": "patches/vocs.patch" + }, + "overrides": { + "vocs>shiki": "^1.23.0", + "vocs>@shikijs/core": "^1.23.0", + "vocs>@shikijs/types": "^1.23.0", + "vocs>@shikijs/rehype": "^1.23.0", + "vocs>@shikijs/twoslash": "^1.23.0", + "vocs>@shikijs/transformers": "^1.23.0" } } } diff --git a/patches/vocs.patch b/patches/vocs.patch index 0bd0899a..db1208c9 100644 --- a/patches/vocs.patch +++ b/patches/vocs.patch @@ -1,1394 +1,46 @@ -diff --git a/_lib/vite/plugins/cairo.json b/_lib/vite/plugins/cairo.json -new file mode 100644 -index 0000000000000000000000000000000000000000..9078642c2c1dc8b472469c269619b1898734459c ---- /dev/null -+++ b/_lib/vite/plugins/cairo.json -@@ -0,0 +1,996 @@ -+{ -+ "credits": "Pulled from: https://raw.githubusercontent.com/starkware-libs/cairo/main/vscode-cairo/syntaxes/cairo.tmLanguage.json. This grammar is heavily modified Rust grammar from VSCode repository: https://github.com/microsoft/vscode/blob/11f415d4d77f7739c202905ccd02e27774146b75/extensions/rust/syntaxes/rust.tmLanguage.json", -+ "name": "Cairo", -+ "scopeName": "source.cairo", -+ "patterns": [ -+ { -+ "comment": "boxed slice literal", -+ "begin": "(<)(\\[)", -+ "beginCaptures": { -+ "1": { -+ "name": "punctuation.brackets.angle.cairo" -+ }, -+ "2": { -+ "name": "punctuation.brackets.square.cairo" -+ } -+ }, -+ "end": ">", -+ "endCaptures": { -+ "0": { -+ "name": "punctuation.brackets.angle.cairo" -+ } -+ }, -+ "patterns": [ -+ { -+ "include": "#block-comments" -+ }, -+ { -+ "include": "#comments" -+ }, -+ { -+ "include": "#gtypes" -+ }, -+ { -+ "include": "#lvariables" -+ }, -+ { -+ "include": "#punctuation" -+ }, -+ { -+ "include": "#types" -+ } -+ ] -+ }, -+ { -+ "comment": "modules", -+ "match": "(mod)\\s+([a-z][A-Za-z0-9_]*)", -+ "captures": { -+ "1": { -+ "name": "storage.type.cairo" -+ }, -+ "2": { -+ "name": "entity.name.module.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "use statements", -+ "name": "meta.use.cairo", -+ "begin": "\\b(use)\\s", -+ "beginCaptures": { -+ "1": { -+ "name": "keyword.other.cairo" -+ } -+ }, -+ "end": ";", -+ "endCaptures": { -+ "0": { -+ "name": "punctuation.semi.cairo" -+ } -+ }, -+ "patterns": [ -+ { -+ "include": "#block-comments" -+ }, -+ { -+ "include": "#comments" -+ }, -+ { -+ "include": "#keywords" -+ }, -+ { -+ "include": "#namespaces" -+ }, -+ { -+ "include": "#punctuation" -+ }, -+ { -+ "include": "#types" -+ }, -+ { -+ "include": "#lvariables" -+ } -+ ] -+ }, -+ { -+ "include": "#block-comments" -+ }, -+ { -+ "include": "#comments" -+ }, -+ { -+ "include": "#attributes" -+ }, -+ { -+ "include": "#lvariables" -+ }, -+ { -+ "include": "#constants" -+ }, -+ { -+ "include": "#gtypes" -+ }, -+ { -+ "include": "#functions" -+ }, -+ { -+ "include": "#types" -+ }, -+ { -+ "include": "#keywords" -+ }, -+ { -+ "include": "#macros" -+ }, -+ { -+ "include": "#namespaces" -+ }, -+ { -+ "include": "#punctuation" -+ }, -+ { -+ "include": "#strings" -+ }, -+ { -+ "include": "#variables" -+ } -+ ], -+ "repository": { -+ "comments": { -+ "patterns": [ -+ { -+ "comment": "documentation comments", -+ "name": "comment.line.documentation.cairo", -+ "match": "(///).*$", -+ "captures": { -+ "1": { -+ "name": "punctuation.definition.comment.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "line comments", -+ "name": "comment.line.double-slash.cairo", -+ "match": "(//).*$", -+ "captures": { -+ "1": { -+ "name": "punctuation.definition.comment.cairo" -+ } -+ } -+ } -+ ] -+ }, -+ "block-comments": { -+ "patterns": [ -+ { -+ "comment": "empty block comments", -+ "name": "comment.block.cairo", -+ "match": "/\\*\\*/" -+ }, -+ { -+ "comment": "block documentation comments", -+ "name": "comment.block.documentation.cairo", -+ "begin": "/\\*\\*", -+ "end": "\\*/", -+ "patterns": [ -+ { -+ "include": "#block-comments" -+ } -+ ] -+ }, -+ { -+ "comment": "block comments", -+ "name": "comment.block.cairo", -+ "begin": "/\\*(?!\\*)", -+ "end": "\\*/", -+ "patterns": [ -+ { -+ "include": "#block-comments" -+ } -+ ] -+ } -+ ] -+ }, -+ "constants": { -+ "patterns": [ -+ { -+ "comment": "ALL CAPS constants", -+ "name": "constant.other.caps.cairo", -+ "match": "\\b[A-Z]{2}[A-Z0-9_]*\\b" -+ }, -+ { -+ "comment": "constant declarations", -+ "match": "\\b(const)\\s+([A-Z][A-Za-z0-9_]*)\\b", -+ "captures": { -+ "1": { -+ "name": "storage.type.cairo" -+ }, -+ "2": { -+ "name": "constant.other.caps.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "decimal integers and floats", -+ "name": "constant.numeric.decimal.cairo", -+ "match": "\\b\\d[\\d_]*(\\.?)[\\d_]*(?:(E|e)([+-]?)([\\d_]+))?(f32|f64|i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", -+ "captures": { -+ "1": { -+ "name": "punctuation.separator.dot.decimal.cairo" -+ }, -+ "2": { -+ "name": "keyword.operator.exponent.cairo" -+ }, -+ "3": { -+ "name": "keyword.operator.exponent.sign.cairo" -+ }, -+ "4": { -+ "name": "constant.numeric.decimal.exponent.mantissa.cairo" -+ }, -+ "5": { -+ "name": "entity.name.type.numeric.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "hexadecimal integers", -+ "name": "constant.numeric.hex.cairo", -+ "match": "\\b0x[\\da-fA-F_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", -+ "captures": { -+ "1": { -+ "name": "entity.name.type.numeric.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "octal integers", -+ "name": "constant.numeric.oct.cairo", -+ "match": "\\b0o[0-7_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", -+ "captures": { -+ "1": { -+ "name": "entity.name.type.numeric.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "binary integers", -+ "name": "constant.numeric.bin.cairo", -+ "match": "\\b0b[01_]+(i128|i16|i32|i64|i8|isize|u128|u16|u32|u64|u8|usize)?\\b", -+ "captures": { -+ "1": { -+ "name": "entity.name.type.numeric.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "booleans", -+ "name": "constant.language.bool.cairo", -+ "match": "\\b(true|false)\\b" -+ } -+ ] -+ }, -+ "escapes": { -+ "comment": "escapes: ASCII, byte, Unicode, quote, regex", -+ "name": "constant.character.escape.cairo", -+ "match": "(\\\\)(?:(?:(x[0-7][\\da-fA-F])|(u(\\{)[\\da-fA-F]{4,6}(\\}))|.))", -+ "captures": { -+ "1": { -+ "name": "constant.character.escape.backslash.cairo" -+ }, -+ "2": { -+ "name": "constant.character.escape.bit.cairo" -+ }, -+ "3": { -+ "name": "constant.character.escape.unicode.cairo" -+ }, -+ "4": { -+ "name": "constant.character.escape.unicode.punctuation.cairo" -+ }, -+ "5": { -+ "name": "constant.character.escape.unicode.punctuation.cairo" -+ } -+ } -+ }, -+ "attributes": { -+ "comment": "attributes", -+ "name": "meta.attribute.cairo", -+ "begin": "(#)(\\!?)(\\[)", -+ "beginCaptures": { -+ "1": { -+ "name": "punctuation.definition.attribute.cairo" -+ }, -+ "3": { -+ "name": "punctuation.brackets.attribute.cairo" -+ } -+ }, -+ "end": "\\]", -+ "endCaptures": { -+ "0": { -+ "name": "punctuation.brackets.attribute.cairo" -+ } -+ }, -+ "patterns": [ -+ { -+ "include": "#block-comments" -+ }, -+ { -+ "include": "#comments" -+ }, -+ { -+ "include": "#keywords" -+ }, -+ { -+ "include": "#punctuation" -+ }, -+ { -+ "include": "#strings" -+ }, -+ { -+ "include": "#gtypes" -+ }, -+ { -+ "include": "#types" -+ } -+ ] -+ }, -+ "functions": { -+ "patterns": [ -+ { -+ "comment": "pub as a function", -+ "match": "\\b(pub)(\\()", -+ "captures": { -+ "1": { -+ "name": "keyword.other.cairo" -+ }, -+ "2": { -+ "name": "punctuation.brackets.round.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "function definition", -+ "name": "meta.function.definition.cairo", -+ "begin": "\\b(fn)\\s+([A-Za-z0-9_]+)((\\()|(<))", -+ "beginCaptures": { -+ "1": { -+ "name": "keyword.other.fn.cairo" -+ }, -+ "2": { -+ "name": "entity.name.function.cairo" -+ }, -+ "4": { -+ "name": "punctuation.brackets.round.cairo" -+ }, -+ "5": { -+ "name": "punctuation.brackets.angle.cairo" -+ } -+ }, -+ "end": "\\{|;", -+ "endCaptures": { -+ "0": { -+ "name": "punctuation.brackets.curly.cairo" -+ } -+ }, -+ "patterns": [ -+ { -+ "include": "#block-comments" -+ }, -+ { -+ "include": "#comments" -+ }, -+ { -+ "include": "#keywords" -+ }, -+ { -+ "include": "#lvariables" -+ }, -+ { -+ "include": "#constants" -+ }, -+ { -+ "include": "#gtypes" -+ }, -+ { -+ "include": "#functions" -+ }, -+ { -+ "include": "#macros" -+ }, -+ { -+ "include": "#namespaces" -+ }, -+ { -+ "include": "#punctuation" -+ }, -+ { -+ "include": "#strings" -+ }, -+ { -+ "include": "#types" -+ }, -+ { -+ "include": "#variables" -+ } -+ ] -+ }, -+ { -+ "comment": "function/method calls, chaining", -+ "name": "meta.function.call.cairo", -+ "begin": "([A-Za-z0-9_]+)(\\()", -+ "beginCaptures": { -+ "1": { -+ "name": "entity.name.function.cairo" -+ }, -+ "2": { -+ "name": "punctuation.brackets.round.cairo" -+ } -+ }, -+ "end": "\\)", -+ "endCaptures": { -+ "0": { -+ "name": "punctuation.brackets.round.cairo" -+ } -+ }, -+ "patterns": [ -+ { -+ "include": "#block-comments" -+ }, -+ { -+ "include": "#comments" -+ }, -+ { -+ "include": "#attributes" -+ }, -+ { -+ "include": "#keywords" -+ }, -+ { -+ "include": "#lvariables" -+ }, -+ { -+ "include": "#constants" -+ }, -+ { -+ "include": "#gtypes" -+ }, -+ { -+ "include": "#functions" -+ }, -+ { -+ "include": "#macros" -+ }, -+ { -+ "include": "#namespaces" -+ }, -+ { -+ "include": "#punctuation" -+ }, -+ { -+ "include": "#strings" -+ }, -+ { -+ "include": "#types" -+ }, -+ { -+ "include": "#variables" -+ } -+ ] -+ }, -+ { -+ "comment": "function/method calls with turbofish", -+ "name": "meta.function.call.cairo", -+ "begin": "([A-Za-z0-9_]+)(?=::<.*>\\()", -+ "beginCaptures": { -+ "1": { -+ "name": "entity.name.function.cairo" -+ } -+ }, -+ "end": "\\)", -+ "endCaptures": { -+ "0": { -+ "name": "punctuation.brackets.round.cairo" -+ } -+ }, -+ "patterns": [ -+ { -+ "include": "#block-comments" -+ }, -+ { -+ "include": "#comments" -+ }, -+ { -+ "include": "#attributes" -+ }, -+ { -+ "include": "#keywords" -+ }, -+ { -+ "include": "#lvariables" -+ }, -+ { -+ "include": "#constants" -+ }, -+ { -+ "include": "#gtypes" -+ }, -+ { -+ "include": "#functions" -+ }, -+ { -+ "include": "#lifetimes" -+ }, -+ { -+ "include": "#macros" -+ }, -+ { -+ "include": "#namespaces" -+ }, -+ { -+ "include": "#punctuation" -+ }, -+ { -+ "include": "#strings" -+ }, -+ { -+ "include": "#types" -+ }, -+ { -+ "include": "#variables" -+ } -+ ] -+ } -+ ] -+ }, -+ "keywords": { -+ "patterns": [ -+ { -+ "comment": "control flow keywords", -+ "name": "keyword.control.cairo", -+ "match": "\\b(break|continue|do|else|for|if|loop|match|return|try|while|yield)\\b" -+ }, -+ { -+ "comment": "storage keywords", -+ "name": "keyword.other.cairo storage.type.cairo", -+ "match": "\\b(extern|let|macro|mod)\\b" -+ }, -+ { -+ "comment": "const keyword", -+ "name": "storage.modifier.cairo", -+ "match": "\\b(const)\\b" -+ }, -+ { -+ "comment": "type keyword", -+ "name": "keyword.declaration.type.cairo storage.type.cairo", -+ "match": "\\b(type)\\b" -+ }, -+ { -+ "comment": "enum keyword", -+ "name": "keyword.declaration.enum.cairo storage.type.cairo", -+ "match": "\\b(enum)\\b" -+ }, -+ { -+ "comment": "trait keyword", -+ "name": "keyword.declaration.trait.cairo storage.type.cairo", -+ "match": "\\b(trait)\\b" -+ }, -+ { -+ "comment": "struct keyword", -+ "name": "keyword.declaration.struct.cairo storage.type.cairo", -+ "match": "\\b(struct)\\b" -+ }, -+ { -+ "comment": "storage modifiers", -+ "name": "storage.modifier.cairo", -+ "match": "\\b(ref|static)\\b" -+ }, -+ { -+ "comment": "other keywords", -+ "name": "keyword.other.cairo", -+ "match": "\\b(as|dyn|move|impl|implicits|in|nopanic|of|priv|pub|static_assert|typeof|unsafe|use|where|with)\\b" -+ }, -+ { -+ "comment": "fn", -+ "name": "keyword.other.fn.cairo", -+ "match": "\\bfn\\b" -+ }, -+ { -+ "comment": "crate", -+ "name": "keyword.other.crate.cairo", -+ "match": "\\bcrate\\b" -+ }, -+ { -+ "comment": "mut", -+ "name": "storage.modifier.mut.cairo", -+ "match": "\\bmut\\b" -+ }, -+ { -+ "comment": "logical operators", -+ "name": "keyword.operator.logical.cairo", -+ "match": "(\\^|\\||\\|\\||&&|<<|>>|!)(?!=)" -+ }, -+ { -+ "comment": "logical AND, borrow references", -+ "name": "keyword.operator.borrow.and.cairo", -+ "match": "&(?![&=])" -+ }, -+ { -+ "comment": "assignment operators", -+ "name": "keyword.operator.assignment.cairo", -+ "match": "(\\+=|-=|\\*=|/=|%=|\\^=|&=|\\|=|<<=|>>=)" -+ }, -+ { -+ "comment": "single equal", -+ "name": "keyword.operator.assignment.equal.cairo", -+ "match": "(?])=(?!=|>)" -+ }, -+ { -+ "comment": "comparison operators", -+ "name": "keyword.operator.comparison.cairo", -+ "match": "(=(=)?(?!>)|!=|<=|(?=)" -+ }, -+ { -+ "comment": "math operators", -+ "name": "keyword.operator.math.cairo", -+ "match": "(([+%]|(\\*(?!\\w)))(?!=))|(-(?!>))|(/(?!/))" -+ }, -+ { -+ "comment": "less than, greater than (special case)", -+ "match": "(?:\\b|(?:(\\))|(\\])|(\\})))[ \\t]+([<>])[ \\t]+(?:\\b|(?:(\\()|(\\[)|(\\{)))", -+ "captures": { -+ "1": { -+ "name": "punctuation.brackets.round.cairo" -+ }, -+ "2": { -+ "name": "punctuation.brackets.square.cairo" -+ }, -+ "3": { -+ "name": "punctuation.brackets.curly.cairo" -+ }, -+ "4": { -+ "name": "keyword.operator.comparison.cairo" -+ }, -+ "5": { -+ "name": "punctuation.brackets.round.cairo" -+ }, -+ "6": { -+ "name": "punctuation.brackets.square.cairo" -+ }, -+ "7": { -+ "name": "punctuation.brackets.curly.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "namespace operator", -+ "name": "keyword.operator.namespace.cairo", -+ "match": "::" -+ }, -+ { -+ "comment": "desnap", -+ "match": "(\\*)(?=\\w+)", -+ "captures": { -+ "1": { -+ "name": "keyword.operator.desnap.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "snap", -+ "name": "keyword.operator.snap.cairo", -+ "match": "@" -+ }, -+ { -+ "comment": "dot access", -+ "name": "keyword.operator.access.dot.cairo", -+ "match": "\\.(?!\\.)" -+ }, -+ { -+ "comment": "ranges, range patterns", -+ "name": "keyword.operator.range.cairo", -+ "match": "\\.{2}(=|\\.)?" -+ }, -+ { -+ "comment": "colon", -+ "name": "keyword.operator.key-value.cairo", -+ "match": ":(?!:)" -+ }, -+ { -+ "comment": "dashrocket, skinny arrow", -+ "name": "keyword.operator.arrow.skinny.cairo", -+ "match": "->" -+ }, -+ { -+ "comment": "hashrocket, fat arrow", -+ "name": "keyword.operator.arrow.fat.cairo", -+ "match": "=>" -+ }, -+ { -+ "comment": "dollar macros", -+ "name": "keyword.operator.macro.dollar.cairo", -+ "match": "\\$" -+ }, -+ { -+ "comment": "question mark operator, questionably sized, macro kleene matcher", -+ "name": "keyword.operator.question.cairo", -+ "match": "\\?" -+ } -+ ] -+ }, -+ "interpolations": { -+ "comment": "curly brace interpolations", -+ "name": "meta.interpolation.cairo", -+ "match": "({)[^\"{}]*(})", -+ "captures": { -+ "1": { -+ "name": "punctuation.definition.interpolation.cairo" -+ }, -+ "2": { -+ "name": "punctuation.definition.interpolation.cairo" -+ } -+ } -+ }, -+ "macros": { -+ "patterns": [ -+ { -+ "comment": "macros", -+ "name": "meta.macro.cairo", -+ "match": "(([a-z_][A-Za-z0-9_]*!)|([A-Z_][A-Za-z0-9_]*!))", -+ "captures": { -+ "2": { -+ "name": "entity.name.function.macro.cairo" -+ }, -+ "3": { -+ "name": "entity.name.type.macro.cairo" -+ } -+ } -+ } -+ ] -+ }, -+ "namespaces": { -+ "patterns": [ -+ { -+ "comment": "namespace (non-type, non-function path segment)", -+ "match": "(?", -+ "endCaptures": { -+ "0": { -+ "name": "punctuation.brackets.angle.cairo" -+ } -+ }, -+ "patterns": [ -+ { -+ "include": "#block-comments" -+ }, -+ { -+ "include": "#comments" -+ }, -+ { -+ "include": "#keywords" -+ }, -+ { -+ "include": "#lvariables" -+ }, -+ { -+ "include": "#punctuation" -+ }, -+ { -+ "include": "#types" -+ }, -+ { -+ "include": "#variables" -+ } -+ ] -+ }, -+ { -+ "comment": "primitive types", -+ "name": "entity.name.type.primitive.cairo", -+ "match": "\\b(bool|never)\\b" -+ }, -+ { -+ "comment": "trait declarations", -+ "match": "\\b(trait)\\s+(_?[A-Z][A-Za-z0-9_]*)\\b", -+ "captures": { -+ "1": { -+ "name": "keyword.declaration.trait.cairo storage.type.cairo" -+ }, -+ "2": { -+ "name": "entity.name.type.trait.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "struct declarations", -+ "match": "\\b(struct)\\s+(_?[A-Z][A-Za-z0-9_]*)\\b", -+ "captures": { -+ "1": { -+ "name": "keyword.declaration.struct.cairo storage.type.cairo" -+ }, -+ "2": { -+ "name": "entity.name.type.struct.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "enum declarations", -+ "match": "\\b(enum)\\s+(_?[A-Z][A-Za-z0-9_]*)\\b", -+ "captures": { -+ "1": { -+ "name": "keyword.declaration.enum.cairo storage.type.cairo" -+ }, -+ "2": { -+ "name": "entity.name.type.enum.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "type declarations", -+ "match": "\\b(type)\\s+(_?[A-Z][A-Za-z0-9_]*)\\b", -+ "captures": { -+ "1": { -+ "name": "keyword.declaration.type.cairo storage.type.cairo" -+ }, -+ "2": { -+ "name": "entity.name.type.declaration.cairo" -+ } -+ } -+ }, -+ { -+ "comment": "types", -+ "name": "entity.name.type.cairo", -+ "match": "\\b_?[A-Z][A-Za-z0-9_]*\\b(?!!)" -+ } -+ ] -+ }, -+ "gtypes": { -+ "patterns": [ -+ { -+ "comment": "option types", -+ "name": "entity.name.type.option.cairo", -+ "match": "\\b(Some|None)\\b" -+ }, -+ { -+ "comment": "result types", -+ "name": "entity.name.type.result.cairo", -+ "match": "\\b(Ok|Err)\\b" -+ } -+ ] -+ }, -+ "punctuation": { -+ "patterns": [ -+ { -+ "comment": "comma", -+ "name": "punctuation.comma.cairo", -+ "match": "," -+ }, -+ { -+ "comment": "curly braces", -+ "name": "punctuation.brackets.curly.cairo", -+ "match": "[{}]" -+ }, -+ { -+ "comment": "parentheses, round brackets", -+ "name": "punctuation.brackets.round.cairo", -+ "match": "[()]" -+ }, -+ { -+ "comment": "semicolon", -+ "name": "punctuation.semi.cairo", -+ "match": ";" -+ }, -+ { -+ "comment": "square brackets", -+ "name": "punctuation.brackets.square.cairo", -+ "match": "[\\[\\]]" -+ }, -+ { -+ "comment": "angle brackets", -+ "name": "punctuation.brackets.angle.cairo", -+ "match": "(?]" -+ } -+ ] -+ }, -+ "strings": { -+ "patterns": [ -+ { -+ "comment": "double-quoted byte array strings", -+ "name": "string.quoted.double.cairo", -+ "begin": "(\")", -+ "beginCaptures": { -+ "1": { -+ "name": "punctuation.definition.string.bytearray.cairo" -+ } -+ }, -+ "end": "\"", -+ "endCaptures": { -+ "0": { -+ "name": "punctuation.definition.string.bytearray.cairo" -+ } -+ }, -+ "patterns": [ -+ { -+ "include": "#escapes" -+ }, -+ { -+ "include": "#interpolations" -+ } -+ ] -+ }, -+ { -+ "comment": "single-quoted short strings", -+ "name": "string.quoted.single.cairo", -+ "begin": "(')", -+ "beginCaptures": { -+ "1": { -+ "name": "punctuation.definition.string.short.cairo" -+ } -+ }, -+ "end": "'", -+ "endCaptures": { -+ "0": { -+ "name": "punctuation.definition.string.short.cairo" -+ } -+ }, -+ "patterns": [ -+ { -+ "include": "#escapes" -+ }, -+ { -+ "include": "#interpolations" -+ } -+ ] -+ } -+ ] -+ }, -+ "lvariables": { -+ "patterns": [ -+ { -+ "comment": "super", -+ "name": "variable.language.super.cairo", -+ "match": "\\bsuper\\b" -+ } -+ ] -+ }, -+ "variables": { -+ "patterns": [ -+ { -+ "comment": "variables", -+ "name": "variable.other.cairo", -+ "match": "\\b(? [ -- remarkDirective, -- remarkInferFrontmatter, -- remarkFrontmatter, -- remarkMdxFrontmatter, -- remarkGfm, -- remarkLinks, -- remarkBlogPosts, -- remarkCallout, -- remarkCode, -- remarkCodeGroup, -- remarkDetails, -- remarkFilename, -- remarkSponsors, -- remarkSteps, -- remarkStrongBlock, -- remarkSubheading, -- remarkTwoslash, -- remarkAuthors, -- ...(markdown?.remarkPlugins || []), -+ remarkDirective, -+ remarkInferFrontmatter, -+ remarkFrontmatter, -+ remarkMdxFrontmatter, -+ remarkGfm, -+ remarkLinks, -+ remarkBlogPosts, -+ remarkCallout, -+ remarkCode, -+ remarkCodeGroup, -+ remarkDetails, -+ remarkFilename, -+ remarkSponsors, -+ remarkSteps, -+ remarkStrongBlock, -+ remarkSubheading, -+ remarkTwoslash, -+ remarkAuthors, -+ ...(markdown?.remarkPlugins || []), - ]; - const defaultThemes = { -- dark: 'github-dark-dimmed', -- light: 'github-light', -+ dark: "github-dark-dimmed", -+ light: "github-light", - }; --export const getRehypePlugins = ({ markdown, rootDir = '', twoslash = {}, } = {}) => [ -- rehypeSlug, -- [ -- rehypeShiki, -- { -- transformers: [ -- transformerLineNumbers(), -- transformerNotationDiff(), -- transformerNotationFocus(), -- transformerNotationHighlight(), -- transformerNotationWordHighlight(), -- transformerNotationInclude({ rootDir }), -- transformerEmptyLine(), -- transformerTagLine(), -- transformerTitle(), -- twoslash !== false -- ? transformerTwoslash({ -- explicitTrigger: true, -- renderer: twoslashRenderer(), -- twoslasher, -- twoslashOptions: { -- ...twoslash, -- customTags: [ -- 'allowErrors', -- ...(defaultTwoslashOptions.customTags ?? []), -- ...(twoslash.customTags ?? []), -- ], -- compilerOptions: { -- ...(twoslash.compilerOptions ?? {}), -- ...defaultTwoslashOptions.compilerOptions, -- }, -- }, -- }) -- : null, -- transformerSplitIdentifiers(), -- ].filter(Boolean), -- themes: defaultThemes, -- ...markdown?.code, -- }, -- ], -- [ -- rehypeInlineShiki, -- { -- themes: defaultThemes, -- ...markdown?.code, -- }, -- ], -- rehypeShikiDisplayNotation, -- [ -- rehypeAutolinkHeadings, -- { -- behavior: 'append', -- content() { -- return [h('div', { dataAutolinkIcon: true })]; -- }, -- }, -- ], -- ...(markdown?.rehypePlugins || []), -+export const getRehypePlugins = ({ -+ markdown, -+ rootDir = "", -+ twoslash = {}, -+} = {}) => [ -+ rehypeSlug, -+ [ -+ // Patch -+ rehypeShikiFromHighlighter, -+ highlighter, -+ // Patch end -+ { -+ transformers: [ -+ transformerLineNumbers(), -+ transformerNotationDiff(), -+ transformerNotationFocus(), -+ transformerNotationHighlight(), -+ transformerNotationWordHighlight(), -+ transformerNotationInclude({ rootDir }), -+ transformerEmptyLine(), -+ transformerTagLine(), -+ transformerTitle(), -+ twoslash !== false -+ ? transformerTwoslash({ -+ explicitTrigger: true, -+ renderer: twoslashRenderer(), -+ twoslasher, -+ twoslashOptions: { -+ ...twoslash, -+ customTags: [ -+ "allowErrors", -+ ...(defaultTwoslashOptions.customTags ?? []), -+ ...(twoslash.customTags ?? []), -+ ], -+ compilerOptions: { -+ ...(twoslash.compilerOptions ?? {}), -+ ...defaultTwoslashOptions.compilerOptions, -+ }, -+ }, -+ }) -+ : null, -+ transformerSplitIdentifiers(), -+ ].filter(Boolean), -+ themes: defaultThemes, -+ ...markdown?.code, -+ }, -+ ], -+ [ -+ rehypeInlineShiki, -+ { -+ langs, -+ themes: defaultThemes, -+ ...markdown?.code, -+ }, -+ ], -+ rehypeShikiDisplayNotation, -+ [ -+ rehypeAutolinkHeadings, -+ { -+ behavior: "append", -+ content() { -+ return [h("div", { dataAutolinkIcon: true })]; -+ }, -+ }, -+ ], -+ ...(markdown?.rehypePlugins || []), - ]; - export async function mdx() { -- const { config } = await resolveVocsConfig(); -- const { markdown, rootDir, twoslash } = config; -- const remarkPlugins = getRemarkPlugins({ markdown }); -- const rehypePlugins = getRehypePlugins({ markdown, rootDir, twoslash }); -- return [ -- mdxPlugin({ -- providerImportSource: 'vocs/mdx-react', -- remarkPlugins, -- rehypePlugins, -- }), -- ]; -+ const { config } = await resolveVocsConfig(); -+ const { markdown, rootDir, twoslash } = config; -+ const remarkPlugins = getRemarkPlugins({ markdown }); -+ const rehypePlugins = getRehypePlugins({ markdown, rootDir, twoslash }); -+ return [ -+ mdxPlugin({ -+ providerImportSource: "vocs/mdx-react", -+ remarkPlugins, -+ rehypePlugins, -+ }), -+ ]; - } - //# sourceMappingURL=mdx.js.map diff --git a/_lib/vite/plugins/rehype/inline-shiki.js b/_lib/vite/plugins/rehype/inline-shiki.js -index 1e2a7426a5a80afa1bdff24388a8849b49e04f2e..20332be7836e5ca932f59747c3de697430b1d711 100644 +index 1e2a7426a5a80afa1bdff24388a8849b49e04f2e..a8394cddd3968f6c153eed58481a80fb5a8e1b09 100644 --- a/_lib/vite/plugins/rehype/inline-shiki.js +++ b/_lib/vite/plugins/rehype/inline-shiki.js -@@ -1,30 +1,51 @@ --import { bundledLanguages, getSingletonHighlighter } from 'shiki'; --import { visit } from 'unist-util-visit'; -+import { bundledLanguages, getSingletonHighlighter } from "shiki"; -+import { visit } from "unist-util-visit"; - const inlineShikiRegex = /(.*){:(.*)}$/; - let promise; - export const rehypeInlineShiki = function (options = {}) { -- const themeNames = ('themes' in options ? Object.values(options.themes) : [options.theme]).filter(Boolean); -- const langs = options.langs || Object.keys(bundledLanguages); -- return async function (tree) { -- if (!promise) -- promise = getSingletonHighlighter({ -- themes: themeNames, -- langs, -- }); -- const highlighter = await promise; -- return visit(tree, 'element', (node, index, parent) => { +@@ -13,16 +13,33 @@ export const rehypeInlineShiki = function (options = {}) { + }); + const highlighter = await promise; + return visit(tree, 'element', (node, index, parent) => { - if (node.tagName !== 'code') - return; -- const match = node.children[0]?.value?.match(inlineShikiRegex); ++ if (node.tagName !== "code") return; ++ // ignore math ++ const classes = Array.isArray(node.properties.className) ++ ? node.properties.className ++ : []; ++ const languageMath = classes.includes("language-math"); ++ const mathDisplay = classes.includes("math-display"); ++ const mathInline = classes.includes("math-inline"); ++ if (languageMath || mathDisplay || mathInline) { ++ return; ++ } ++ + const match = node.children[0]?.value?.match(inlineShikiRegex); - if (!match) - return; - const [, code, lang] = match; - const hast = highlighter.codeToHast(code, { ...options, lang }); -- const inlineCode = hast.children[0].children[0]; ++ let hast; ++ if (match) { ++ const [, code, lang] = match; ++ hast = highlighter.codeToHast(code, { ...options, lang }); ++ } else { ++ if (!node.children[0] || node.children[0].type !== "text") return; ++ const code = node.children[0].value; ++ hast = highlighter.codeToHast(code, { ++ ...options, ++ lang: "cairo", ++ }); ++ } + const inlineCode = hast.children[0].children[0]; - if (!inlineCode) - return; -- parent?.children.splice(index ?? 0, 1, inlineCode); -+ const themeNames = ( -+ "themes" in options ? Object.values(options.themes) : [options.theme] -+ ).filter(Boolean); -+ const langs = options.langs || Object.keys(bundledLanguages); -+ return async function (tree) { -+ if (!promise) -+ promise = getSingletonHighlighter({ -+ themes: themeNames, -+ langs, -+ }); -+ const highlighter = await promise; -+ return visit(tree, "element", (node, index, parent) => { -+ if (node.tagName !== "code") return; -+ // ignore math -+ const classes = Array.isArray(node.properties.className) -+ ? node.properties.className -+ : []; -+ const languageMath = classes.includes("language-math"); -+ const mathDisplay = classes.includes("math-display"); -+ const mathInline = classes.includes("math-inline"); -+ if (languageMath || mathDisplay || mathInline) { -+ return; -+ } -+ -+ const match = node.children[0]?.value?.match(inlineShikiRegex); -+ if (match) { -+ const [, code, lang] = match; -+ const hast = highlighter.codeToHast(code, { ...options, lang }); -+ const inlineCode = hast.children[0].children[0]; -+ if (!inlineCode) return; -+ parent?.children.splice(index ?? 0, 1, inlineCode); -+ } else { -+ if (!node.children[0] || node.children[0].type !== "text") return; -+ const code = node.children[0].value; -+ const hast = highlighter.codeToHast(code, { -+ ...options, -+ lang: "Cairo", ++ if (!inlineCode) return; + parent?.children.splice(index ?? 0, 1, inlineCode); }); -- }; -+ const inlineCode = hast.children[0].children[0]; -+ if (!inlineCode) return; -+ parent?.children.splice(index ?? 0, 1, inlineCode); -+ } -+ }); -+ }; - }; - //# sourceMappingURL=inline-shiki.js.map + }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7c6d19f9..575a437a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,9 +4,17 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + vocs>shiki: ^1.23.0 + vocs>@shikijs/core: ^1.23.0 + vocs>@shikijs/types: ^1.23.0 + vocs>@shikijs/rehype: ^1.23.0 + vocs>@shikijs/twoslash: ^1.23.0 + vocs>@shikijs/transformers: ^1.23.0 + patchedDependencies: vocs: - hash: p6z7kxjkom4q2uemolyyrxbtiy + hash: 7wumpnts656yvepr4seo2mjn34 path: patches/vocs.patch importers: @@ -33,7 +41,7 @@ importers: version: 5.6.3 vocs: specifier: 1.0.0-alpha.62 - version: 1.0.0-alpha.62(patch_hash=p6z7kxjkom4q2uemolyyrxbtiy)(@types/node@22.8.6)(@types/react-dom@18.3.1)(@types/react@18.3.12)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.24.3)(typescript@5.6.3) + version: 1.0.0-alpha.62(patch_hash=7wumpnts656yvepr4seo2mjn34)(@types/node@22.8.6)(@types/react-dom@18.3.1)(@types/react@18.3.12)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.24.3)(typescript@5.6.3) devDependencies: '@types/react-dom': specifier: ^18.3.1 @@ -981,26 +989,26 @@ packages: cpu: [x64] os: [win32] - '@shikijs/core@1.22.2': - resolution: {integrity: sha512-bvIQcd8BEeR1yFvOYv6HDiyta2FFVePbzeowf5pPS1avczrPK+cjmaxxh0nx5QzbON7+Sv0sQfQVciO7bN72sg==} + '@shikijs/core@1.23.1': + resolution: {integrity: sha512-NuOVgwcHgVC6jBVH5V7iblziw6iQbWWHrj5IlZI3Fqu2yx9awH7OIQkXIcsHsUmY19ckwSgUMgrqExEyP5A0TA==} - '@shikijs/engine-javascript@1.22.2': - resolution: {integrity: sha512-iOvql09ql6m+3d1vtvP8fLCVCK7BQD1pJFmHIECsujB0V32BJ0Ab6hxk1ewVSMFA58FI0pR2Had9BKZdyQrxTw==} + '@shikijs/engine-javascript@1.23.1': + resolution: {integrity: sha512-i/LdEwT5k3FVu07SiApRFwRcSJs5QM9+tod5vYCPig1Ywi8GR30zcujbxGQFJHwYD7A5BUqagi8o5KS+LEVgBg==} - '@shikijs/engine-oniguruma@1.22.2': - resolution: {integrity: sha512-GIZPAGzQOy56mGvWMoZRPggn0dTlBf1gutV5TdceLCZlFNqWmuc7u+CzD0Gd9vQUTgLbrt0KLzz6FNprqYAxlA==} + '@shikijs/engine-oniguruma@1.23.1': + resolution: {integrity: sha512-KQ+lgeJJ5m2ISbUZudLR1qHeH3MnSs2mjFg7bnencgs5jDVPeJ2NVDJ3N5ZHbcTsOIh0qIueyAJnwg7lg7kwXQ==} - '@shikijs/rehype@1.22.2': - resolution: {integrity: sha512-A0RHgiYR5uiHvddwHehBN9j8PhOvfT6/GebSTWrapur6M+fD/4i3mlfUv7aFK4b+4GQ1R42L8fC5N98whZjNcg==} + '@shikijs/rehype@1.23.1': + resolution: {integrity: sha512-PH5bpMDEc4nBP62Ci3lUqkxBWRTm8cdE+eY9er5QD50jAWQxhXcc1Aeax1AlyrASrtjTwCkI22M6N9iSn5p+bQ==} - '@shikijs/transformers@1.22.2': - resolution: {integrity: sha512-8f78OiBa6pZDoZ53lYTmuvpFPlWtevn23bzG+azpPVvZg7ITax57o/K3TC91eYL3OMJOO0onPbgnQyZjRos8XQ==} + '@shikijs/transformers@1.23.1': + resolution: {integrity: sha512-yQ2Cn0M9i46p30KwbyIzLvKDk+dQNU+lj88RGO0XEj54Hn4Cof1bZoDb9xBRWxFE4R8nmK63w7oHnJwvOtt0NQ==} - '@shikijs/twoslash@1.22.2': - resolution: {integrity: sha512-4R3A7aH/toZgtlveXHKk01nIsvn8hjAfPJ1aT550zcV4qK6vK/tfaEyYtaljOaY1wig2l5+8sKjNSEz3PcSiEw==} + '@shikijs/twoslash@1.23.1': + resolution: {integrity: sha512-Qj/+CGAF6TdcRjPDQn1bxyKD8ejnV7VJLqCHzob1uCbwQlJTI5z0gUVAgpqS55z4vdV1Mrx2IpCTl9glhC0l3A==} - '@shikijs/types@1.22.2': - resolution: {integrity: sha512-NCWDa6LGZqTuzjsGfXOBWfjS/fDIbDdmVDug+7ykVe1IKT4c1gakrvlfFYp5NhAXH/lyqLM8wsAPo5wNy73Feg==} + '@shikijs/types@1.23.1': + resolution: {integrity: sha512-98A5hGyEhzzAgQh2dAeHKrWW4HfCMeoFER2z16p5eJ+vmPeF6lZ/elEne6/UCU551F/WqkopqRsr1l2Yu6+A0g==} '@shikijs/vscode-textmate@9.3.0': resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==} @@ -1375,6 +1383,9 @@ packages: electron-to-chromium@1.5.50: resolution: {integrity: sha512-eMVObiUQ2LdgeO1F/ySTXsvqvxb6ZH2zPGaMYsWzRDdOddUa77tdmI0ltg+L16UpbWdhPmuF3wIQYyQq65WfZw==} + emoji-regex-xs@1.0.0: + resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} + emoji-regex@10.4.0: resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} @@ -2042,8 +2053,8 @@ packages: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} - oniguruma-to-js@0.4.3: - resolution: {integrity: sha512-X0jWUcAlxORhOqqBREgPMgnshB7ZGYszBNspP+tS9hPD3l13CdaXcHbgImoHUHlrvGx/7AvFEkTRhAGYh+jzjQ==} + oniguruma-to-es@0.4.1: + resolution: {integrity: sha512-rNcEohFz095QKGRovP/yqPIKc+nP+Sjs4YTHMv33nMePGKrq/r2eu9Yh4646M5XluGJsUnmwoXuiXE69KDs+fQ==} ora@7.0.1: resolution: {integrity: sha512-0TUxTiFJWv+JnjWm4o9yvuskpEJLXTcng8MJuKd+SzAzp2o+OP3HWqNhB4OdJRt1Vsd9/mR0oyaEYlOnL7XIRw==} @@ -2282,8 +2293,14 @@ packages: regenerator-runtime@0.14.1: resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - regex@4.4.0: - resolution: {integrity: sha512-uCUSuobNVeqUupowbdZub6ggI5/JZkYyJdDogddJr60L764oxC2pMZov1fQ3wM9bdyzUILDG+Sqx6NAKAz9rKQ==} + regex-recursion@4.2.1: + resolution: {integrity: sha512-QHNZyZAeKdndD1G3bKAbBEKOSSK4KOHQrAJ01N1LJeb0SoH4DJIeFhp0uUpETgONifS4+P3sOgoA1dhzgrQvhA==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@5.0.2: + resolution: {integrity: sha512-/pczGbKIQgfTMRV0XjABvc5RzLqQmwqxLHdQao2RTXPk+pmTXB2P0IaUHYdYyk412YLwUIkaeMd5T+RzVgTqnQ==} rehype-autolink-headings@7.1.0: resolution: {integrity: sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==} @@ -2379,8 +2396,8 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shiki@1.22.2: - resolution: {integrity: sha512-3IZau0NdGKXhH2bBlUk4w1IHNxPh6A5B2sUpyY+8utLu2j/h1QpFkAaUA1bAMxOWWGtTWcAh531vnS4NJKS/lA==} + shiki@1.23.1: + resolution: {integrity: sha512-8kxV9TH4pXgdKGxNOkrSMydn1Xf6It8lsle0fiqxf7a1149K1WGtdOu3Zb91T5r1JpvRPxqxU3C2XdZZXQnrig==} signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -3489,49 +3506,49 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.24.3': optional: true - '@shikijs/core@1.22.2': + '@shikijs/core@1.23.1': dependencies: - '@shikijs/engine-javascript': 1.22.2 - '@shikijs/engine-oniguruma': 1.22.2 - '@shikijs/types': 1.22.2 + '@shikijs/engine-javascript': 1.23.1 + '@shikijs/engine-oniguruma': 1.23.1 + '@shikijs/types': 1.23.1 '@shikijs/vscode-textmate': 9.3.0 '@types/hast': 3.0.4 hast-util-to-html: 9.0.3 - '@shikijs/engine-javascript@1.22.2': + '@shikijs/engine-javascript@1.23.1': dependencies: - '@shikijs/types': 1.22.2 + '@shikijs/types': 1.23.1 '@shikijs/vscode-textmate': 9.3.0 - oniguruma-to-js: 0.4.3 + oniguruma-to-es: 0.4.1 - '@shikijs/engine-oniguruma@1.22.2': + '@shikijs/engine-oniguruma@1.23.1': dependencies: - '@shikijs/types': 1.22.2 + '@shikijs/types': 1.23.1 '@shikijs/vscode-textmate': 9.3.0 - '@shikijs/rehype@1.22.2': + '@shikijs/rehype@1.23.1': dependencies: - '@shikijs/types': 1.22.2 + '@shikijs/types': 1.23.1 '@types/hast': 3.0.4 hast-util-to-string: 3.0.1 - shiki: 1.22.2 + shiki: 1.23.1 unified: 11.0.5 unist-util-visit: 5.0.0 - '@shikijs/transformers@1.22.2': + '@shikijs/transformers@1.23.1': dependencies: - shiki: 1.22.2 + shiki: 1.23.1 - '@shikijs/twoslash@1.22.2(typescript@5.6.3)': + '@shikijs/twoslash@1.23.1(typescript@5.6.3)': dependencies: - '@shikijs/core': 1.22.2 - '@shikijs/types': 1.22.2 + '@shikijs/core': 1.23.1 + '@shikijs/types': 1.23.1 twoslash: 0.2.12(typescript@5.6.3) transitivePeerDependencies: - supports-color - typescript - '@shikijs/types@1.22.2': + '@shikijs/types@1.23.1': dependencies: '@shikijs/vscode-textmate': 9.3.0 '@types/hast': 3.0.4 @@ -3929,6 +3946,8 @@ snapshots: electron-to-chromium@1.5.50: {} + emoji-regex-xs@1.0.0: {} + emoji-regex@10.4.0: {} emoji-regex@8.0.0: {} @@ -5011,9 +5030,11 @@ snapshots: dependencies: mimic-fn: 2.1.0 - oniguruma-to-js@0.4.3: + oniguruma-to-es@0.4.1: dependencies: - regex: 4.4.0 + emoji-regex-xs: 1.0.0 + regex: 5.0.2 + regex-recursion: 4.2.1 ora@7.0.1: dependencies: @@ -5260,7 +5281,15 @@ snapshots: regenerator-runtime@0.14.1: {} - regex@4.4.0: {} + regex-recursion@4.2.1: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@5.0.2: + dependencies: + regex-utilities: 2.3.0 rehype-autolink-headings@7.1.0: dependencies: @@ -5467,12 +5496,12 @@ snapshots: shebang-regex@3.0.0: {} - shiki@1.22.2: + shiki@1.23.1: dependencies: - '@shikijs/core': 1.22.2 - '@shikijs/engine-javascript': 1.22.2 - '@shikijs/engine-oniguruma': 1.22.2 - '@shikijs/types': 1.22.2 + '@shikijs/core': 1.23.1 + '@shikijs/engine-javascript': 1.23.1 + '@shikijs/engine-oniguruma': 1.23.1 + '@shikijs/types': 1.23.1 '@shikijs/vscode-textmate': 9.3.0 '@types/hast': 3.0.4 @@ -5766,7 +5795,7 @@ snapshots: '@types/node': 22.8.6 fsevents: 2.3.3 - vocs@1.0.0-alpha.62(patch_hash=p6z7kxjkom4q2uemolyyrxbtiy)(@types/node@22.8.6)(@types/react-dom@18.3.1)(@types/react@18.3.12)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.24.3)(typescript@5.6.3): + vocs@1.0.0-alpha.62(patch_hash=7wumpnts656yvepr4seo2mjn34)(@types/node@22.8.6)(@types/react-dom@18.3.1)(@types/react@18.3.12)(acorn@8.14.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)(rollup@4.24.3)(typescript@5.6.3): dependencies: '@floating-ui/react': 0.26.27(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@hono/node-server': 1.13.4(hono@3.12.12) @@ -5781,9 +5810,9 @@ snapshots: '@radix-ui/react-navigation-menu': 1.2.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-popover': 1.1.2(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-tabs': 1.1.1(@types/react-dom@18.3.1)(@types/react@18.3.12)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@shikijs/rehype': 1.22.2 - '@shikijs/transformers': 1.22.2 - '@shikijs/twoslash': 1.22.2(typescript@5.6.3) + '@shikijs/rehype': 1.23.1 + '@shikijs/transformers': 1.23.1 + '@shikijs/twoslash': 1.23.1(typescript@5.6.3) '@vanilla-extract/css': 1.16.0 '@vanilla-extract/dynamic': 2.1.2 '@vanilla-extract/vite-plugin': 3.9.5(@types/node@22.8.6)(vite@5.4.10(@types/node@22.8.6)) @@ -5823,7 +5852,7 @@ snapshots: remark-mdx-frontmatter: 4.0.0 remark-parse: 11.0.0 serve-static: 1.16.2 - shiki: 1.22.2 + shiki: 1.23.1 tailwindcss: 3.4.14 toml: 3.0.0 twoslash: 0.2.12(typescript@5.6.3) diff --git a/routes.ts b/routes.ts index 21a70023..5eed00f6 100644 --- a/routes.ts +++ b/routes.ts @@ -7,7 +7,6 @@ const config: Sidebar = [ }, { text: "Getting Started", - link: "/getting-started/basics/storage", items: [ // { // text: "Local environment setup" @@ -98,7 +97,6 @@ const config: Sidebar = [ }, { text: "Components", - link: "/components/how_to", items: [ { text: "Components How-To", @@ -120,7 +118,6 @@ const config: Sidebar = [ }, { text: "Applications", - link: "/applications/upgradeable_contract", items: [ { text: " Upgradeable Contract", @@ -174,7 +171,6 @@ const config: Sidebar = [ }, { text: "Advanced concepts", - link: "/advanced-concepts/write_to_any_slot", items: [ { text: "Writing to any storage slot", diff --git a/styles.css b/styles.css index 2ba7b331..4aeb1128 100644 --- a/styles.css +++ b/styles.css @@ -60,48 +60,47 @@ section.vocs_Sidebar_level } /* Make sidebar collapsible */ -.vocs_DocsLayout_gutterLeft { - top: 0; - left: 0; - bottom: 0; -} -.vocs_DocsLayout_gutterLeft { - margin-left: 0; - transition: margin 0.3s ease; -} -.sidebar_hidden .vocs_DocsLayout_gutterLeft { - margin-left: calc(var(--vocs_DocsLayout_leftGutterWidth) * -1); -}; - -.vocs_DocsLayout_content_withSidebar { - margin-left: var(--vocs_DocsLayout_leftGutterWidth) -} -.sidebar_hidden .vocs_DocsLayout_content_withSidebar { - margin-left: 0 !important; -} -.vocs_DocsLayout_content_withSidebar { - transition: margin 300ms ease !important; - max-width: unset; -} - -.vocs_DesktopTopNav_logo a { - margin-top: 2px !important; -} - -.vocs_Sidebar_logo { - padding-top: 0px !important; -} - -.sidebar_toggle { - position: absolute; - top: 0; - right: calc(var(--vocs-topNav_height) * -1); - height: var(--vocs-topNav_height); - width: var(--vocs-topNav_height); -} - -.sidebar_toggle button { - padding: var(--vocs-space_8); +@media screen and (min-width: 1080px) { + .vocs_DocsLayout_gutterLeft { + margin-left: 0; + transition: margin 0.3s ease; + width: var(--vocs-sidebar_width); + } + .sidebar_hidden .vocs_DocsLayout_gutterLeft { + margin-left: calc(var(--vocs-sidebar_width) * -1); + } + + .vocs_DocsLayout_content_withSidebar { + margin-left: var(--vocs-sidebar_width); + } + .sidebar_hidden .vocs_DocsLayout_content_withSidebar { + margin-left: 0 !important; + } + .vocs_DocsLayout_content_withSidebar { + margin-left: var(--vocs-sidebar_width); + transition: margin 300ms ease !important; + max-width: unset; + } + + .vocs_DesktopTopNav_logo a { + margin-top: 2px !important; + } + + .vocs_Sidebar_logo { + padding-top: 0px !important; + } + + .sidebar_toggle { + position: absolute; + top: 0; + right: calc(var(--vocs-topNav_height) * -1); + height: var(--vocs-topNav_height); + width: var(--vocs-topNav_height); + } + + .sidebar_toggle button { + padding: var(--vocs-space_8); + } } /* END sidebar */ @@ -120,3 +119,15 @@ section.vocs_Sidebar_level font-size: var(--vocs-fontSize_20); padding-bottom: 0.875em; } + +.vocs_DesktopTopNav_logoWrapper { + left: 22px; + justify-content: start; +} + +/* Force show theme switcher */ +@media screen and (max-width: 1280px) { + .vocs_DesktopTopNav_hideCompact { + display: block; + } +} From 7229cb74cd686a021c9f234fe16efc53b8793995 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:06:54 +0700 Subject: [PATCH 02/44] fix(app): correct sidebar placement --- styles.css | 7 ------- 1 file changed, 7 deletions(-) diff --git a/styles.css b/styles.css index 4aeb1128..742942b0 100644 --- a/styles.css +++ b/styles.css @@ -124,10 +124,3 @@ section.vocs_Sidebar_level left: 22px; justify-content: start; } - -/* Force show theme switcher */ -@media screen and (max-width: 1280px) { - .vocs_DesktopTopNav_hideCompact { - display: block; - } -} From 5f3513ede5910150db8e9ca0ded2fc220f59db02 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:51:08 +0700 Subject: [PATCH 03/44] fix(app): responsive content centering --- styles.css | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/styles.css b/styles.css index 742942b0..e4e1cbe7 100644 --- a/styles.css +++ b/styles.css @@ -60,27 +60,31 @@ section.vocs_Sidebar_level } /* Make sidebar collapsible */ -@media screen and (min-width: 1080px) { - .vocs_DocsLayout_gutterLeft { - margin-left: 0; - transition: margin 0.3s ease; - width: var(--vocs-sidebar_width); - } - .sidebar_hidden .vocs_DocsLayout_gutterLeft { - margin-left: calc(var(--vocs-sidebar_width) * -1); - } +.vocs_DocsLayout_gutterLeft { + top: 0; + left: 0; + bottom: 0; +} +.vocs_DocsLayout_gutterLeft { + margin-left: 0; + transition: margin 0.3s ease; + width: var(--vocs-sidebar_width); +} +.sidebar_hidden .vocs_DocsLayout_gutterLeft { + margin-left: calc(var(--vocs-sidebar_width) * -1); +}; - .vocs_DocsLayout_content_withSidebar { - margin-left: var(--vocs-sidebar_width); - } - .sidebar_hidden .vocs_DocsLayout_content_withSidebar { - margin-left: 0 !important; - } - .vocs_DocsLayout_content_withSidebar { - margin-left: var(--vocs-sidebar_width); - transition: margin 300ms ease !important; - max-width: unset; - } +.vocs_DocsLayout_content_withSidebar { + margin-left: var(--vocs-sidebar_width); +} +.sidebar_hidden .vocs_DocsLayout_content_withSidebar { + margin-left: 0 !important; +} +.vocs_DocsLayout_content_withSidebar { + margin-left: var(--vocs-sidebar_width); + transition: margin 300ms ease !important; + max-width: unset; +} .vocs_DesktopTopNav_logo a { margin-top: 2px !important; From c6f7e7c7c00b0aced3fb6b1b70f6f82fcb533b32 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:25:05 +0700 Subject: [PATCH 04/44] fix(app): responsive content centering --- styles.css | 51 +++++++++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/styles.css b/styles.css index e4e1cbe7..4aeb1128 100644 --- a/styles.css +++ b/styles.css @@ -60,31 +60,27 @@ section.vocs_Sidebar_level } /* Make sidebar collapsible */ -.vocs_DocsLayout_gutterLeft { - top: 0; - left: 0; - bottom: 0; -} -.vocs_DocsLayout_gutterLeft { - margin-left: 0; - transition: margin 0.3s ease; - width: var(--vocs-sidebar_width); -} -.sidebar_hidden .vocs_DocsLayout_gutterLeft { - margin-left: calc(var(--vocs-sidebar_width) * -1); -}; +@media screen and (min-width: 1080px) { + .vocs_DocsLayout_gutterLeft { + margin-left: 0; + transition: margin 0.3s ease; + width: var(--vocs-sidebar_width); + } + .sidebar_hidden .vocs_DocsLayout_gutterLeft { + margin-left: calc(var(--vocs-sidebar_width) * -1); + } -.vocs_DocsLayout_content_withSidebar { - margin-left: var(--vocs-sidebar_width); -} -.sidebar_hidden .vocs_DocsLayout_content_withSidebar { - margin-left: 0 !important; -} -.vocs_DocsLayout_content_withSidebar { - margin-left: var(--vocs-sidebar_width); - transition: margin 300ms ease !important; - max-width: unset; -} + .vocs_DocsLayout_content_withSidebar { + margin-left: var(--vocs-sidebar_width); + } + .sidebar_hidden .vocs_DocsLayout_content_withSidebar { + margin-left: 0 !important; + } + .vocs_DocsLayout_content_withSidebar { + margin-left: var(--vocs-sidebar_width); + transition: margin 300ms ease !important; + max-width: unset; + } .vocs_DesktopTopNav_logo a { margin-top: 2px !important; @@ -128,3 +124,10 @@ section.vocs_Sidebar_level left: 22px; justify-content: start; } + +/* Force show theme switcher */ +@media screen and (max-width: 1280px) { + .vocs_DesktopTopNav_hideCompact { + display: block; + } +} From 75d68e219b82d9715c454e1e608d4d2752734832 Mon Sep 17 00:00:00 2001 From: Julio <30329843+julio4@users.noreply.github.com> Date: Fri, 6 Dec 2024 17:14:12 +0700 Subject: [PATCH 05/44] Update issue templates, Close #273 close #273 --- .github/ISSUE_TEMPLATE/bug_report.md | 23 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature-request.md | 16 ++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature-request.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..7c8cc313 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,23 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Checklist:** +- Using the correct tooling versions, from https://github.com/NethermindEth/StarknetByExample/blob/dev/.tool-versions diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 00000000..36b7339b --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,16 @@ +--- +name: Feature request +about: Suggest an idea of example or concept to showcase +title: '' +labels: enhancement +assignees: '' + +--- + +**Describe the concept/idea you would like to see** + +**Is it a new example or a modification/extension of a current one** +If you consider editing some content, explain exactly why and what. + +**Additional context** +Add any other context or screenshots about the request here. From 1aa137b54475dd6231a85ff8d3fa667132c8eaab Mon Sep 17 00:00:00 2001 From: Julio <30329843+julio4@users.noreply.github.com> Date: Tue, 17 Dec 2024 15:27:46 +0700 Subject: [PATCH 06/44] Feat: add logos (#278) * fix #276 * feat: updated logo --- components/ThemeImage.tsx | 27 ++++++++++++++++ components/useTheme.tsx | 32 +++++++++++++++++++ .../testing/contract-testing.md | 3 -- pages/index.mdx | 9 ++++++ public/svg/Horizontal_Dark.svg | 29 +++++++++++++++++ public/svg/Horizontal_Light.svg | 29 +++++++++++++++++ public/svg/Icon_Dark.svg | 12 +++++++ public/svg/Icon_Light.svg | 12 +++++++ public/svg/Vertical_Dark.svg | 29 +++++++++++++++++ public/svg/Vertical_Light.svg | 29 +++++++++++++++++ routes.ts | 1 - vocs.config.ts | 13 ++++++-- 12 files changed, 219 insertions(+), 6 deletions(-) create mode 100644 components/ThemeImage.tsx create mode 100644 components/useTheme.tsx create mode 100644 public/svg/Horizontal_Dark.svg create mode 100644 public/svg/Horizontal_Light.svg create mode 100644 public/svg/Icon_Dark.svg create mode 100644 public/svg/Icon_Light.svg create mode 100644 public/svg/Vertical_Dark.svg create mode 100644 public/svg/Vertical_Light.svg diff --git a/components/ThemeImage.tsx b/components/ThemeImage.tsx new file mode 100644 index 00000000..d8e57e06 --- /dev/null +++ b/components/ThemeImage.tsx @@ -0,0 +1,27 @@ +import { useEffect, useState } from "react"; +import { useTheme } from "./useTheme"; + +export const ThemeImage = ({ + light, + dark, + alt, + ...props +}: { + light: string; + dark: string; + alt: string; + [key: string]: any; +}) => { + const [mounted, setMounted] = useState(false); + const theme = useTheme(); + + useEffect(() => { + setMounted(true); + }, []); + if (!mounted) { + return {alt}; + } + + // Client-side rendering after hydrating + return {alt}; +}; diff --git a/components/useTheme.tsx b/components/useTheme.tsx new file mode 100644 index 00000000..a2aa12d2 --- /dev/null +++ b/components/useTheme.tsx @@ -0,0 +1,32 @@ +import { useEffect, useState } from "react"; + +export function useTheme() { + const [theme, setTheme] = useState<"dark" | "light">(() => { + if (typeof window === "undefined") return "light"; + return document.documentElement.classList.contains("dark") + ? "dark" + : "light"; + }); + + useEffect(() => { + const handleThemeChange = () => { + const newTheme = document.documentElement.classList.contains("dark") + ? "dark" + : "light"; + setTheme(newTheme); + }; + + // Watch for class changes on documentElement + const observer = new MutationObserver(handleThemeChange); + observer.observe(document.documentElement, { + attributes: true, + attributeFilter: ["class"], + }); + + return () => { + observer.disconnect(); + }; + }, []); + + return theme; +} diff --git a/pages/getting-started/testing/contract-testing.md b/pages/getting-started/testing/contract-testing.md index 21805f6b..2deff011 100644 --- a/pages/getting-started/testing/contract-testing.md +++ b/pages/getting-started/testing/contract-testing.md @@ -30,9 +30,6 @@ Now, let's move on to the testing process: - Use `assert` to verify that the contract behaves as expected in the given context - You can also use assertion macros: `assert_eq!`, `assert_ne!`, `assert_gt!`, `assert_ge!`, `assert_lt!`, `assert_le!` -If you haven't noticed yet, every example in this book has hidden tests, you can see them by clicking the "Show hidden lines" (eyes icon) on the top right of code blocks. -You can also find a detailed explanation of testing in Cairo in [The Cairo Book](https://book.cairo-lang.org/ch10-00-testing-cairo-programs.html). - ## Using the contract state You can use the `Contract::contract_state_for_testing` function to access the contract state. This function is only available in the test environment and allows you to mutate and read the contract state directly. diff --git a/pages/index.mdx b/pages/index.mdx index 75576b25..fa8cde31 100644 --- a/pages/index.mdx +++ b/pages/index.mdx @@ -1,4 +1,13 @@ import { Sponsors } from "vocs/components"; +import { ThemeImage } from "../components/ThemeImage"; + +
+ +
# Introduction diff --git a/public/svg/Horizontal_Dark.svg b/public/svg/Horizontal_Dark.svg new file mode 100644 index 00000000..368ecd63 --- /dev/null +++ b/public/svg/Horizontal_Dark.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/svg/Horizontal_Light.svg b/public/svg/Horizontal_Light.svg new file mode 100644 index 00000000..671fff8f --- /dev/null +++ b/public/svg/Horizontal_Light.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/svg/Icon_Dark.svg b/public/svg/Icon_Dark.svg new file mode 100644 index 00000000..1b45fb36 --- /dev/null +++ b/public/svg/Icon_Dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/svg/Icon_Light.svg b/public/svg/Icon_Light.svg new file mode 100644 index 00000000..01643c89 --- /dev/null +++ b/public/svg/Icon_Light.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/svg/Vertical_Dark.svg b/public/svg/Vertical_Dark.svg new file mode 100644 index 00000000..c3535199 --- /dev/null +++ b/public/svg/Vertical_Dark.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/svg/Vertical_Light.svg b/public/svg/Vertical_Light.svg new file mode 100644 index 00000000..e8028a49 --- /dev/null +++ b/public/svg/Vertical_Light.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/routes.ts b/routes.ts index 5eed00f6..53ec16c0 100644 --- a/routes.ts +++ b/routes.ts @@ -317,7 +317,6 @@ const generateSidebarConfig = (sidebar: SidebarItem[]): Sidebar => { // Configure for all top-level routes getTopLevelRoutes(sidebar).forEach(([route, sectionName]) => { - // console.log(`config["${route}"] = sidebarFocusOn(sidebar, "${sectionName}", true)`) config[`/${route}`] = sidebarFocusOn(sidebar, sectionName, true); }); diff --git a/vocs.config.ts b/vocs.config.ts index ce39fd02..b26ef120 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -8,6 +8,15 @@ import rehypeKatex from "rehype-katex"; // This require custom highlighter, and patch of vocs to remove initial shiki instance export default defineConfig({ + iconUrl: "/svg/Icon_Light.svg", + // iconUrl: { + // light: "/svg/Icon_Light.svg", + // dark: "/svg/Icon_Dark.svg", + // }, + logoUrl: { + light: "/svg/Horizontal_Light.svg", + dark: "/svg/Horizontal_Dark.svg", + }, title: "Starknet by Example", rootDir: ".", sidebar: routes, @@ -89,8 +98,8 @@ export default defineConfig({ // Theme configuration theme: { accentColor: { - dark: "#F69D50", - light: "#ff4b01", + dark: "#ff3000", + light: "#ff3000", }, }, font: { From 1ea13879bbc61bb35b1cc13b9cd8c44d9af2e7ac Mon Sep 17 00:00:00 2001 From: Julio <30329843+julio4@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:06:39 +0700 Subject: [PATCH 07/44] Feat: upgrade to `2.9.2` (#280) * chore: update 2.9.2 * chore: apply fmt * fix: hide AA for upcoming fixes * fix: github edit link * fix: starknet book deadlink * fix #279 * small improvement: increase footer bottom padding * fix #275 * fix: minor * fix: remove print from cairo_cheatsheet --- .tool-versions | 4 +- Scarb.lock | 79 +++++++++----- Scarb.toml | 12 +-- footer.tsx | 2 +- .../commit_reveal/src/commit_reveal.cairo | 7 +- .../src/ecdsa_verification.cairo | 14 +-- .../hash_trait/src/hash_trait.cairo | 13 ++- .../library_calls/src/tests.cairo | 7 +- .../simple_account/src/simple_account.cairo | 12 +-- .../store_using_packing/src/contract.cairo | 4 +- .../store_using_packing/src/tests.cairo | 5 +- .../struct_as_mapping_key/src/test.cairo | 5 +- .../write_to_any_slot/src/contract.cairo | 9 +- .../write_to_any_slot/src/tests.cairo | 2 +- .../advanced_factory/src/contract.cairo | 18 ++-- .../advanced_factory/src/tests.cairo | 42 ++++---- .../applications/coin_flip/src/contract.cairo | 18 ++-- .../coin_flip/src/mock_randomness.cairo | 22 ++-- .../applications/coin_flip/src/tests.cairo | 70 ++++++------ .../components/src/countable.cairo | 9 +- .../src/others/switch_collision.cairo | 8 +- .../applications/components/src/ownable.cairo | 30 +++--- .../components/src/switchable.cairo | 11 +- .../src/contract_countable.cairo | 9 +- .../src/contract_countable_switchable.cairo | 9 +- ...ntract_countable_switchable_internal.cairo | 9 +- .../src/countable_dep_switch.cairo | 7 +- .../src/countable_internal_dep_switch.cairo | 8 +- .../constant_product_amm/src/contracts.cairo | 16 +-- .../constant_product_amm/src/tests.cairo | 6 +- .../crowdfunding/src/campaign.cairo | 10 +- .../src/campaign/pledgeable.cairo | 6 +- .../crowdfunding/src/mock_upgrade.cairo | 10 +- .../applications/crowdfunding/src/tests.cairo | 100 +++++++++--------- listings/applications/erc20/src/token.cairo | 100 +++++++++--------- .../merkle_tree/src/contract.cairo | 10 +- .../applications/merkle_tree/src/tests.cairo | 18 ++-- .../nft_dutch_auction/src/erc721.cairo | 28 ++--- .../src/nft_dutch_auction.cairo | 30 +++--- .../src/storage.cairo | 2 +- listings/applications/simple_vault/Scarb.toml | 1 + .../applications/simple_vault/src/lib.cairo | 3 - .../simple_vault/src/simple_vault.cairo | 31 +++--- .../applications/simple_vault/src/tests.cairo | 2 - .../applications/staking/src/contract.cairo | 8 +- .../staking/src/tests/staking_tests.cairo | 59 ++++++----- .../staking/src/tests/tokens.cairo | 4 +- .../applications/timelock/src/erc721.cairo | 2 +- .../timelock/src/tests/timelock.cairo | 54 +++++----- .../timelock/src/tests/utils.cairo | 2 +- .../applications/timelock/src/timelock.cairo | 14 +-- .../upgradeable_contract/src/tests.cairo | 21 ++-- .../src/upgradeable_contract_v0.cairo | 5 +- .../src/upgradeable_contract_v1.cairo | 7 +- listings/cairo_cheatsheet/Scarb.toml | 1 - .../cairo_cheatsheet/src/enum_example.cairo | 18 ++-- .../cairo_cheatsheet/src/if_let_example.cairo | 12 +-- .../src/mapping_example.cairo | 10 +- .../cairo_cheatsheet/src/match_example.cairo | 2 +- .../cairo_cheatsheet/src/struct_example.cairo | 2 +- .../src/while_let_example.cairo | 2 - .../bytearray/src/bytearray.cairo | 2 +- .../calling_other_contracts/src/caller.cairo | 14 +-- .../constructor/src/constructor.cairo | 6 +- .../getting-started/counter/src/counter.cairo | 6 +- .../custom_type_serde/src/contract.cairo | 10 +- .../errors/src/custom_errors.cairo | 8 +- .../errors/src/simple_errors.cairo | 6 +- .../errors/src/vault_errors.cairo | 8 +- .../getting-started/events/src/counter.cairo | 24 ++--- .../factory/src/simple_factory.cairo | 16 +-- .../interfaces_traits/src/explicit.cairo | 10 +- .../interfaces_traits/src/implicit.cairo | 8 +- .../src/implicit_internal.cairo | 13 ++- .../mappings/src/mappings.cairo | 6 +- .../storage/src/contract.cairo | 8 +- .../storage/src/minimal_contract.cairo | 6 +- .../storing_custom_types/src/contract.cairo | 6 +- .../testing_how_to/src/contract.cairo | 14 +-- .../variables/src/global_variables.cairo | 6 +- .../variables/src/local_variables.cairo | 8 +- .../variables/src/storage_variables.cairo | 10 +- .../visibility/src/visibility.cairo | 8 +- pages/components/collisions.md | 2 +- pages/getting-started/basics/storage.md | 2 +- pages/getting-started/basics/syscalls.md | 2 +- pages/index.mdx | 2 +- routes.ts | 31 +++--- vocs.config.ts | 2 +- 89 files changed, 645 insertions(+), 640 deletions(-) delete mode 100644 listings/applications/simple_vault/src/tests.cairo diff --git a/.tool-versions b/.tool-versions index aac540e2..c69b5af8 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -scarb 2.8.2 -starknet-foundry 0.30.0 +scarb 2.9.2 +starknet-foundry 0.35.0 diff --git a/Scarb.lock b/Scarb.lock index 4589d79a..f401f76d 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -136,105 +136,126 @@ dependencies = [ [[package]] name = "openzeppelin" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:5dc87a71f0f5d045e02e5bc5ea7a9b0360bbbc3f388b846006280d266feac192" +checksum = "sha256:05fd9365be85a4a3e878135d5c52229f760b3861ce4ed314cb1e75b178b553da" dependencies = [ + "openzeppelin_access", + "openzeppelin_account", + "openzeppelin_finance", + "openzeppelin_governance", + "openzeppelin_introspection", "openzeppelin_merkle_tree", "openzeppelin_presets", "openzeppelin_security", "openzeppelin_token", "openzeppelin_upgrades", + "openzeppelin_utils", ] [[package]] name = "openzeppelin_access" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:b9139449e53d715992b2d9e887c0c723d886419bee7ceb5561648c70bd6d3174" +checksum = "sha256:7734901a0ca7a7065e69416fea615dd1dc586c8dc9e76c032f25ee62e8b2a06c" dependencies = [ "openzeppelin_introspection", - "openzeppelin_utils", ] [[package]] name = "openzeppelin_account" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:841bb881adbe98b64fee1dc1329f6e3fbabdfbd9fa65c66ffb54c55f13764bce" +checksum = "sha256:1aa3a71e2f40f66f98d96aa9bf9f361f53db0fd20fa83ef7df04426a3c3a926a" dependencies = [ "openzeppelin_introspection", "openzeppelin_utils", ] +[[package]] +name = "openzeppelin_finance" +version = "0.20.0" +source = "registry+https://scarbs.xyz/" +checksum = "sha256:f0c507fbff955e4180ea3fa17949c0ff85518c40101f4948948d9d9a74143d6c" +dependencies = [ + "openzeppelin_access", + "openzeppelin_token", +] + [[package]] name = "openzeppelin_governance" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:a9d9c983cfd4369e7bbb69433fb264edf376805ed873b1f70a287825a6bd1eaf" +checksum = "sha256:c0fb60fad716413d537fabd5fcbb2c499ca6beb95af5f0d1699955ecec4c6f63" dependencies = [ "openzeppelin_access", + "openzeppelin_account", "openzeppelin_introspection", + "openzeppelin_token", + "openzeppelin_utils", ] [[package]] name = "openzeppelin_introspection" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:312bc2e531f036480ad7392dbb31042c38d875ef9dbb5578ea8de5c05e35b7d8" +checksum = "sha256:13e04a2190684e6804229a77a6c56de7d033db8b9ef519e5e8dee400a70d8a3d" [[package]] name = "openzeppelin_merkle_tree" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:8e264c8d5f0591262a235a445b8ca78dd5580c251707b218b829b6b4d6f84a34" +checksum = "sha256:039608900e92f3dcf479bf53a49a1fd76452acd97eb86e390d1eb92cacdaf3af" [[package]] name = "openzeppelin_presets" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:7bc9db7563e434535ebd06c7598ba0f8494e791c5f80401389b356a3ebd65a08" +checksum = "sha256:5c07a8de32e5d9abe33988c7927eaa8b5f83bc29dc77302d9c8c44c898611042" dependencies = [ "openzeppelin_access", "openzeppelin_account", + "openzeppelin_finance", "openzeppelin_introspection", "openzeppelin_token", "openzeppelin_upgrades", + "openzeppelin_utils", ] [[package]] name = "openzeppelin_security" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:b7497f5e55c6d9f1d7606ad0d12719e3c04765e266fb91fb72740e0af41d03f3" +checksum = "sha256:27155597019ecf971c48d7bfb07fa58cdc146d5297745570071732abca17f19f" [[package]] name = "openzeppelin_token" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:7074c23fbc300b3cccff1037264dfdbe976fb11ae42ce687f4a8ce469adc552a" +checksum = "sha256:4452f449dc6c1ea97cf69d1d9182749abd40e85bd826cd79652c06a627eafd91" dependencies = [ + "openzeppelin_access", "openzeppelin_account", - "openzeppelin_governance", "openzeppelin_introspection", + "openzeppelin_utils", ] [[package]] name = "openzeppelin_upgrades" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:4de95a7fb8955e63711f34bb954676f6cef127b44b570c0535d7781297821b44" +checksum = "sha256:15fdd63f6b50a0fda7b3f8f434120aaf7637bcdfe6fd8d275ad57343d5ede5e1" [[package]] name = "openzeppelin_utils" -version = "0.16.0" +version = "0.20.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:a494aeb5f1371db7f22e922196aa41d1d1698877a766a838350c0b6ffe49fda2" +checksum = "sha256:44f32d242af1e43982decc49c563e613a9b67ade552f5c3d5cde504e92f74607" [[package]] name = "pragma_lib" version = "1.0.0" -source = "git+https://github.com/astraly-labs/pragma-lib#86d7ccdc15b349b8b48d9796fc8464c947bea6e1" +source = "git+https://github.com/astraly-labs/pragma-lib?tag=2.9.1#ee1f3f7e9276cf64e19e267832de380d84c04d28" [[package]] name = "simple_account" @@ -256,15 +277,15 @@ dependencies = [ [[package]] name = "snforge_scarb_plugin" -version = "0.2.0" +version = "0.35.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:2e4ce3ebe3f49548bd26908391b5d78537a765d827df0d96c32aeb88941d0d67" +checksum = "sha256:20bd6a488fda7201ce2a5fd680d8e715b10e3545147b276747ad079c96c3d5d2" [[package]] name = "snforge_std" -version = "0.30.0" +version = "0.35.0" source = "registry+https://scarbs.xyz/" -checksum = "sha256:2f3c4846881813ac0f5d1460981249c9f5e2a6831e752beedf9b70975495b4ec" +checksum = "sha256:fe4e1b1526c815441183baed7f93e73bc76a6393d23e1f9c34fbe227bfaedfd6" dependencies = [ "snforge_scarb_plugin", ] diff --git a/Scarb.toml b/Scarb.toml index eca997b2..37e6b8f1 100644 --- a/Scarb.toml +++ b/Scarb.toml @@ -12,13 +12,13 @@ test = "$(git rev-parse --show-toplevel)/scripts/test_resolver.sh" [workspace.tool.snforge] [workspace.dependencies] -starknet = "2.8.2" -cairo_test = "2.8.2" -assert_macros = "2.8.2" -snforge_std = "0.30.0" -openzeppelin = "0.16.0" +starknet = "2.9.2" +cairo_test = "2.9.2" +assert_macros = "2.9.2" +snforge_std = "0.35.0" +openzeppelin = "0.20.0" components = { path = "listings/applications/components" } -pragma_lib = { git = "https://github.com/astraly-labs/pragma-lib" } +pragma_lib = { git = "https://github.com/astraly-labs/pragma-lib", tag = "2.9.1" } [workspace.package] description = "Collection of examples of how to use the Cairo programming language to create smart contracts on Starknet." diff --git a/footer.tsx b/footer.tsx index 41212213..70d07b30 100644 --- a/footer.tsx +++ b/footer.tsx @@ -1,6 +1,6 @@ export default function Footer() { return ( -
+
ICommitmentRevealTraitDispatcher { let (contract_address, _) = deploy_syscall( - CommitmentRevealTraits::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + CommitmentRevealTraits::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); ICommitmentRevealTraitDispatcher { contract_address } } diff --git a/listings/advanced-concepts/ecdsa_verification/src/ecdsa_verification.cairo b/listings/advanced-concepts/ecdsa_verification/src/ecdsa_verification.cairo index 5321a85e..c6f601ad 100644 --- a/listings/advanced-concepts/ecdsa_verification/src/ecdsa_verification.cairo +++ b/listings/advanced-concepts/ecdsa_verification/src/ecdsa_verification.cairo @@ -9,12 +9,12 @@ use starknet::secp256_trait::{Signature}; // 3. Sign the hash (off chain, keep your private key secret) #[starknet::interface] trait IVerifySignature { - fn get_signature(self: @TContractState, r: u256, s: u256, v: u32,) -> Signature; + fn get_signature(self: @TContractState, r: u256, s: u256, v: u32) -> Signature; fn verify_eth_signature( self: @TContractState, eth_address: EthAddress, msg_hash: u256, r: u256, s: u256, v: u32, ); fn recover_public_key( - self: @TContractState, eth_address: EthAddress, msg_hash: u256, r: u256, s: u256, v: u32 + self: @TContractState, eth_address: EthAddress, msg_hash: u256, r: u256, s: u256, v: u32, ); } @@ -23,7 +23,7 @@ mod verifySignature { use super::IVerifySignature; use core::starknet::eth_address::EthAddress; use starknet::secp256k1::Secp256k1Point; - use starknet::secp256_trait::{Signature, signature_from_vrs, recover_public_key,}; + use starknet::secp256_trait::{Signature, signature_from_vrs, recover_public_key}; use starknet::eth_signature::{verify_eth_signature, public_key_point_to_eth_address}; #[storage] @@ -46,7 +46,7 @@ mod verifySignature { /// # Returns /// /// * `Signature` - The signature struct. - fn get_signature(self: @ContractState, r: u256, s: u256, v: u32,) -> Signature { + fn get_signature(self: @ContractState, r: u256, s: u256, v: u32) -> Signature { // Create a Signature object from the given v, r, and s values. let signature: Signature = signature_from_vrs(v, r, s); signature @@ -62,7 +62,7 @@ mod verifySignature { /// * `s` - The S component of the signature. /// * `v` - The V component of the signature. fn verify_eth_signature( - self: @ContractState, eth_address: EthAddress, msg_hash: u256, r: u256, s: u256, v: u32 + self: @ContractState, eth_address: EthAddress, msg_hash: u256, r: u256, s: u256, v: u32, ) { let signature = self.get_signature(r, s, v); verify_eth_signature(:msg_hash, :signature, :eth_address); @@ -79,7 +79,7 @@ mod verifySignature { /// * `s` - The S component of the signature. /// * `v` - The V component of the signature. fn recover_public_key( - self: @ContractState, eth_address: EthAddress, msg_hash: u256, r: u256, s: u256, v: u32 + self: @ContractState, eth_address: EthAddress, msg_hash: u256, r: u256, s: u256, v: u32, ) { let signature = self.get_signature(r, s, v); let public_key_point = recover_public_key::(msg_hash, signature) @@ -93,7 +93,7 @@ mod verifySignature { #[cfg(test)] mod tests { - use starknet::secp256_trait::{Signature, signature_from_vrs, recover_public_key,}; + use starknet::secp256_trait::{Signature, signature_from_vrs, recover_public_key}; use starknet::EthAddress; use starknet::secp256k1::{Secp256k1Point}; use starknet::eth_signature::{verify_eth_signature, public_key_point_to_eth_address}; diff --git a/listings/advanced-concepts/hash_trait/src/hash_trait.cairo b/listings/advanced-concepts/hash_trait/src/hash_trait.cairo index 88fde919..ee8b9fb6 100644 --- a/listings/advanced-concepts/hash_trait/src/hash_trait.cairo +++ b/listings/advanced-concepts/hash_trait/src/hash_trait.cairo @@ -1,10 +1,10 @@ #[starknet::interface] pub trait IHashTrait { fn save_user_with_poseidon( - ref self: T, id: felt252, username: felt252, password: felt252 + ref self: T, id: felt252, username: felt252, password: felt252, ) -> felt252; fn save_user_with_pedersen( - ref self: T, id: felt252, username: felt252, password: felt252 + ref self: T, id: felt252, username: felt252, password: felt252, ) -> felt252; } @@ -36,7 +36,7 @@ pub mod HashTraits { #[abi(embed_v0)] impl HashTrait of super::IHashTrait { fn save_user_with_poseidon( - ref self: ContractState, id: felt252, username: felt252, password: felt252 + ref self: ContractState, id: felt252, username: felt252, password: felt252, ) -> felt252 { let login = LoginDetails { username, password }; let user = UserDetails { id, login }; @@ -48,7 +48,7 @@ pub mod HashTraits { } fn save_user_with_pedersen( - ref self: ContractState, id: felt252, username: felt252, password: felt252 + ref self: ContractState, id: felt252, username: felt252, password: felt252, ) -> felt252 { let login = LoginDetails { username, password }; let user = UserDetails { id, login }; @@ -64,16 +64,15 @@ pub mod HashTraits { #[cfg(test)] mod tests { - use starknet::SyscallResultTrait; use super::{HashTraits, IHashTraitDispatcher, IHashTraitDispatcherTrait}; use starknet::syscalls::deploy_syscall; fn deploy() -> IHashTraitDispatcher { let mut calldata = array![]; let (address, _) = deploy_syscall( - HashTraits::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false + HashTraits::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false, ) - .unwrap_syscall(); + .unwrap(); IHashTraitDispatcher { contract_address: address } } diff --git a/listings/advanced-concepts/library_calls/src/tests.cairo b/listings/advanced-concepts/library_calls/src/tests.cairo index 6458ef4d..90c2707e 100644 --- a/listings/advanced-concepts/library_calls/src/tests.cairo +++ b/listings/advanced-concepts/library_calls/src/tests.cairo @@ -1,8 +1,7 @@ mod tests { use starknet::syscalls::deploy_syscall; - use starknet::SyscallResultTrait; use library_calls::library_call::{ - MathUtils, MathUtilsLibraryCall, IMathUtilsDispatcher, IMathUtilsDispatcherTrait + MathUtils, MathUtilsLibraryCall, IMathUtilsDispatcher, IMathUtilsDispatcherTrait, }; #[test] @@ -12,9 +11,9 @@ mod tests { .unwrap(); let mut calldata: Array = array![]; let (address, _) = deploy_syscall( - MathUtilsLibraryCall::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false + MathUtilsLibraryCall::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false, ) - .unwrap_syscall(); + .unwrap(); let mut contract = IMathUtilsDispatcher { contract_address: address }; contract.set_class_hash(math_utils_class_hash); diff --git a/listings/advanced-concepts/simple_account/src/simple_account.cairo b/listings/advanced-concepts/simple_account/src/simple_account.cairo index 6de72c81..f1e1386b 100644 --- a/listings/advanced-concepts/simple_account/src/simple_account.cairo +++ b/listings/advanced-concepts/simple_account/src/simple_account.cairo @@ -5,7 +5,7 @@ trait ISRC6 { fn execute_calls(self: @TContractState, calls: Array) -> Array>; fn validate_calls(self: @TContractState, calls: Array) -> felt252; fn is_valid_signature( - self: @TContractState, hash: felt252, signature: Array + self: @TContractState, hash: felt252, signature: Array, ) -> felt252; } @@ -30,7 +30,7 @@ mod simpleAccount { struct Storage { #[substorage(v0)] src5: SRC5Component::Storage, - public_key: felt252 + public_key: felt252, } #[constructor] @@ -43,7 +43,7 @@ mod simpleAccount { #[derive(Drop, starknet::Event)] enum Event { #[flat] - SRC5Event: SRC5Component::Event + SRC5Event: SRC5Component::Event, } #[abi(embed_v0)] @@ -68,7 +68,7 @@ mod simpleAccount { } fn is_valid_signature( - self: @ContractState, hash: felt252, signature: Array + self: @ContractState, hash: felt252, signature: Array, ) -> felt252 { if self._is_valid_signature(hash, signature.span()) { starknet::VALIDATED @@ -81,10 +81,10 @@ mod simpleAccount { #[generate_trait] impl SignatureVerificationImpl of SignatureVerification { fn _is_valid_signature( - self: @ContractState, hash: felt252, signature: Span + self: @ContractState, hash: felt252, signature: Span, ) -> bool { check_ecdsa_signature( - hash, self.public_key.read(), *signature.at(0_u32), *signature.at(1_u32) + hash, self.public_key.read(), *signature.at(0_u32), *signature.at(1_u32), ) } } diff --git a/listings/advanced-concepts/store_using_packing/src/contract.cairo b/listings/advanced-concepts/store_using_packing/src/contract.cairo index 8ef6b2db..e1611a22 100644 --- a/listings/advanced-concepts/store_using_packing/src/contract.cairo +++ b/listings/advanced-concepts/store_using_packing/src/contract.cairo @@ -1,7 +1,7 @@ #[derive(Copy, Serde, Drop)] pub struct Time { pub hour: u8, - pub minute: u8 + pub minute: u8, } #[starknet::interface] @@ -18,7 +18,7 @@ pub mod TimeContract { #[storage] struct Storage { - time: Time + time: Time, } impl TimePackable of StorePacking { diff --git a/listings/advanced-concepts/store_using_packing/src/tests.cairo b/listings/advanced-concepts/store_using_packing/src/tests.cairo index eb888025..3bb290d4 100644 --- a/listings/advanced-concepts/store_using_packing/src/tests.cairo +++ b/listings/advanced-concepts/store_using_packing/src/tests.cairo @@ -1,5 +1,4 @@ mod tests { - use starknet::SyscallResultTrait; use store_using_packing::contract::{TimeContract, Time, ITimeDispatcher, ITimeDispatcherTrait}; use starknet::syscalls::deploy_syscall; @@ -9,9 +8,9 @@ mod tests { // Set up. let mut calldata: Array = array![]; let (address0, _) = deploy_syscall( - TimeContract::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false + TimeContract::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false, ) - .unwrap_syscall(); + .unwrap(); let mut contract = ITimeDispatcher { contract_address: address0 }; // Store a Time struct. diff --git a/listings/advanced-concepts/struct_as_mapping_key/src/test.cairo b/listings/advanced-concepts/struct_as_mapping_key/src/test.cairo index 34ebdf26..7fef6c87 100644 --- a/listings/advanced-concepts/struct_as_mapping_key/src/test.cairo +++ b/listings/advanced-concepts/struct_as_mapping_key/src/test.cairo @@ -1,5 +1,4 @@ mod tests { - use starknet::SyscallResultTrait; use struct_as_mapping_key::contract::{PetRegistry, Pet}; use starknet::syscalls::deploy_syscall; @@ -14,9 +13,9 @@ mod tests { // Set up. let mut calldata: Array = array![]; let (address0, _) = deploy_syscall( - PetRegistry::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false + PetRegistry::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false, ) - .unwrap_syscall(); + .unwrap(); let mut contract = IPetRegistryDispatcher { contract_address: address0 }; let pet = Pet { name: 'Cute Labrador', age: 5, owner: 'Louis' }; diff --git a/listings/advanced-concepts/write_to_any_slot/src/contract.cairo b/listings/advanced-concepts/write_to_any_slot/src/contract.cairo index 1e7d4922..e5673412 100644 --- a/listings/advanced-concepts/write_to_any_slot/src/contract.cairo +++ b/listings/advanced-concepts/write_to_any_slot/src/contract.cairo @@ -7,7 +7,6 @@ pub trait IWriteToAnySlots { #[starknet::contract] pub mod WriteToAnySlot { use starknet::syscalls::{storage_read_syscall, storage_write_syscall}; - use starknet::SyscallResultTrait; use core::poseidon::poseidon_hash_span; use starknet::StorageAddress; @@ -19,15 +18,11 @@ pub mod WriteToAnySlot { #[abi(embed_v0)] impl WriteToAnySlot of super::IWriteToAnySlots { fn write_slot(ref self: ContractState, value: u32) { - storage_write_syscall(0, get_address_from_name(SLOT_NAME), value.into()) - .unwrap_syscall(); + storage_write_syscall(0, get_address_from_name(SLOT_NAME), value.into()).unwrap(); } fn read_slot(self: @ContractState) -> u32 { - storage_read_syscall(0, get_address_from_name(SLOT_NAME)) - .unwrap_syscall() - .try_into() - .unwrap() + storage_read_syscall(0, get_address_from_name(SLOT_NAME)).unwrap().try_into().unwrap() } } pub fn get_address_from_name(variable_name: felt252) -> StorageAddress { diff --git a/listings/advanced-concepts/write_to_any_slot/src/tests.cairo b/listings/advanced-concepts/write_to_any_slot/src/tests.cairo index 6428a6eb..42c6528d 100644 --- a/listings/advanced-concepts/write_to_any_slot/src/tests.cairo +++ b/listings/advanced-concepts/write_to_any_slot/src/tests.cairo @@ -16,7 +16,7 @@ mod tests { // Set up. let mut calldata: Array = array![]; let (address0, _) = deploy_syscall( - WriteToAnySlot::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false + WriteToAnySlot::TEST_CLASS_HASH.try_into().unwrap(), 0, calldata.span(), false, ) .unwrap(); let mut contract = IWriteToAnySlotDispatcher { contract_address: address0 }; diff --git a/listings/applications/advanced_factory/src/contract.cairo b/listings/applications/advanced_factory/src/contract.cairo index ff81f715..f8436ead 100644 --- a/listings/applications/advanced_factory/src/contract.cairo +++ b/listings/applications/advanced_factory/src/contract.cairo @@ -10,26 +10,24 @@ pub trait ICampaignFactory { goal: u256, start_time: u64, end_time: u64, - token_address: ContractAddress + token_address: ContractAddress, ) -> ContractAddress; fn get_campaign_class_hash(self: @TContractState) -> ClassHash; fn update_campaign_class_hash(ref self: TContractState, new_class_hash: ClassHash); fn upgrade_campaign( - ref self: TContractState, campaign_address: ContractAddress, new_end_time: Option + ref self: TContractState, campaign_address: ContractAddress, new_end_time: Option, ); } #[starknet::contract] pub mod CampaignFactory { use core::num::traits::Zero; - use starknet::{ - ContractAddress, ClassHash, SyscallResultTrait, syscalls::deploy_syscall, get_caller_address - }; + use starknet::{ContractAddress, ClassHash, syscalls::deploy_syscall, get_caller_address}; use crowdfunding::campaign::{ICampaignDispatcher, ICampaignDispatcherTrait}; use components::ownable::ownable_component; use starknet::storage::{ Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess + StoragePointerWriteAccess, }; component!(path: ownable_component, storage: ownable, event: OwnableEvent); @@ -71,7 +69,7 @@ pub mod CampaignFactory { #[derive(Drop, starknet::Event)] pub struct CampaignCreated { pub creator: ContractAddress, - pub contract_address: ContractAddress + pub contract_address: ContractAddress, } pub mod Errors { @@ -109,9 +107,9 @@ pub mod CampaignFactory { // Contract deployment let (contract_address, _) = deploy_syscall( - self.campaign_class_hash.read(), 0, constructor_calldata.span(), false + self.campaign_class_hash.read(), 0, constructor_calldata.span(), false, ) - .unwrap_syscall(); + .unwrap(); // track new campaign instance self.campaigns.write((creator, contract_address), self.campaign_class_hash.read()); @@ -135,7 +133,7 @@ pub mod CampaignFactory { } fn upgrade_campaign( - ref self: ContractState, campaign_address: ContractAddress, new_end_time: Option + ref self: ContractState, campaign_address: ContractAddress, new_end_time: Option, ) { assert(campaign_address.is_non_zero(), Errors::ZERO_ADDRESS); diff --git a/listings/applications/advanced_factory/src/tests.cairo b/listings/applications/advanced_factory/src/tests.cairo index 4b2b3bf5..31352aaa 100644 --- a/listings/applications/advanced_factory/src/tests.cairo +++ b/listings/applications/advanced_factory/src/tests.cairo @@ -1,11 +1,11 @@ use advanced_factory::contract::{ - CampaignFactory, ICampaignFactoryDispatcher, ICampaignFactoryDispatcherTrait + CampaignFactory, ICampaignFactoryDispatcher, ICampaignFactoryDispatcherTrait, }; use crowdfunding::campaign::Campaign; use starknet::{ClassHash, get_block_timestamp, contract_address_const}; use snforge_std::{ declare, start_cheat_caller_address, stop_cheat_caller_address, spy_events, DeclareResultTrait, - ContractClassTrait, get_class_hash, EventSpyAssertionsTrait + ContractClassTrait, get_class_hash, EventSpyAssertionsTrait, }; // Define a goal contract to deploy @@ -88,11 +88,11 @@ fn test_create_campaign() { factory.contract_address, CampaignFactory::Event::CampaignCreated( CampaignFactory::CampaignCreated { - creator: campaign_creator, contract_address: campaign_address - } - ) - ) - ] + creator: campaign_creator, contract_address: campaign_address, + }, + ), + ), + ], ); } @@ -111,7 +111,7 @@ fn test_upgrade_campaign_class_hash() { start_cheat_caller_address(factory.contract_address, pending_campaign_creator); let pending_campaign = factory .create_campaign( - "title 1", "description 1", 10000, start_time_pending, end_time_pending, token + "title 1", "description 1", 10000, start_time_pending, end_time_pending, token, ); assert_eq!(old_class_hash, get_class_hash(pending_campaign)); @@ -123,7 +123,7 @@ fn test_upgrade_campaign_class_hash() { start_cheat_caller_address(factory.contract_address, active_campaign_creator); let active_campaign = factory .create_campaign( - "title 2", "description 2", 20000, start_time_active, end_time_active, token + "title 2", "description 2", 20000, start_time_active, end_time_active, token, ); assert_eq!(old_class_hash, get_class_hash(active_campaign)); @@ -145,10 +145,10 @@ fn test_upgrade_campaign_class_hash() { ( factory.contract_address, CampaignFactory::Event::ClassHashUpdated( - CampaignFactory::ClassHashUpdated { new_class_hash } - ) - ) - ] + CampaignFactory::ClassHashUpdated { new_class_hash }, + ), + ), + ], ); // upgrade pending campaign @@ -163,9 +163,11 @@ fn test_upgrade_campaign_class_hash() { @array![ ( pending_campaign, - Campaign::Event::Upgraded(Campaign::Upgraded { implementation: new_class_hash }) - ) - ] + Campaign::Event::Upgraded( + Campaign::Upgraded { implementation: new_class_hash }, + ), + ), + ], ); // upgrade active campaign @@ -180,8 +182,10 @@ fn test_upgrade_campaign_class_hash() { @array![ ( active_campaign, - Campaign::Event::Upgraded(Campaign::Upgraded { implementation: new_class_hash }) - ) - ] + Campaign::Event::Upgraded( + Campaign::Upgraded { implementation: new_class_hash }, + ), + ), + ], ); } diff --git a/listings/applications/coin_flip/src/contract.cairo b/listings/applications/coin_flip/src/contract.cairo index cefe052e..74fec7b3 100644 --- a/listings/applications/coin_flip/src/contract.cairo +++ b/listings/applications/coin_flip/src/contract.cairo @@ -13,16 +13,16 @@ pub trait IPragmaVRF { requestor_address: ContractAddress, request_id: u64, random_words: Span, - calldata: Array + calldata: Array, ); } #[starknet::contract] pub mod CoinFlip { use core::num::traits::zero::Zero; - use starknet::{ContractAddress, get_caller_address, get_contract_address,}; + use starknet::{ContractAddress, get_caller_address, get_contract_address}; use starknet::storage::{ - Map, StoragePointerReadAccess, StoragePathEntry, StoragePointerWriteAccess + Map, StoragePointerReadAccess, StoragePathEntry, StoragePointerWriteAccess, }; use pragma_lib::abi::{IRandomnessDispatcher, IRandomnessDispatcherTrait}; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; @@ -52,7 +52,7 @@ pub mod CoinFlip { pub struct Landed { pub flip_id: u64, pub flipper: ContractAddress, - pub side: Side + pub side: Side, } #[derive(Drop, Debug, PartialEq, Serde)] @@ -79,7 +79,7 @@ pub mod CoinFlip { fn constructor( ref self: ContractState, randomness_contract_address: ContractAddress, - eth_address: ContractAddress + eth_address: ContractAddress, ) { assert(randomness_contract_address.is_non_zero(), Errors::INVALID_ADDRESS); assert(eth_address.is_non_zero(), Errors::INVALID_ADDRESS); @@ -106,11 +106,11 @@ pub mod CoinFlip { requestor_address: ContractAddress, request_id: u64, random_words: Span, - calldata: Array + calldata: Array, ) { let caller = get_caller_address(); assert( - caller == self.randomness_contract_address.read(), Errors::CALLER_NOT_RANDOMNESS + caller == self.randomness_contract_address.read(), Errors::CALLER_NOT_RANDOMNESS, ); let this = get_contract_address(); @@ -125,7 +125,7 @@ pub mod CoinFlip { fn _request_my_randomness(ref self: ContractState) -> u64 { let randomness_contract_address = self.randomness_contract_address.read(); let randomness_dispatcher = IRandomnessDispatcher { - contract_address: randomness_contract_address + contract_address: randomness_contract_address, }; let this = get_contract_address(); @@ -139,7 +139,7 @@ pub mod CoinFlip { // Request the randomness to be used to construct the winning combination let request_id = randomness_dispatcher .request_random( - nonce, this, CALLBACK_FEE_LIMIT, PUBLISH_DELAY, NUM_OF_WORDS, array![] + nonce, this, CALLBACK_FEE_LIMIT, PUBLISH_DELAY, NUM_OF_WORDS, array![], ); self.nonce.write(nonce + 1); diff --git a/listings/applications/coin_flip/src/mock_randomness.cairo b/listings/applications/coin_flip/src/mock_randomness.cairo index 54f2f327..493be34a 100644 --- a/listings/applications/coin_flip/src/mock_randomness.cairo +++ b/listings/applications/coin_flip/src/mock_randomness.cairo @@ -4,7 +4,7 @@ pub mod MockRandomness { use pragma_lib::types::RequestStatus; use starknet::{ContractAddress, ClassHash, get_caller_address, get_contract_address}; use starknet::storage::{ - Map, StoragePointerReadAccess, StoragePathEntry, StoragePointerWriteAccess + Map, StoragePointerReadAccess, StoragePathEntry, StoragePointerWriteAccess, }; use core::num::traits::zero::Zero; use coin_flip::contract::{IPragmaVRFDispatcher, IPragmaVRFDispatcherTrait}; @@ -41,7 +41,7 @@ pub mod MockRandomness { callback_fee_limit: u128, publish_delay: u64, num_words: u64, - calldata: Array + calldata: Array, ) -> u64 { let caller = get_caller_address(); let this = get_contract_address(); @@ -70,7 +70,7 @@ pub mod MockRandomness { callback_fee: u128, random_words: Span, proof: Span, - calldata: Array + calldata: Array, ) { let requestor = IPragmaVRFDispatcher { contract_address: callback_address }; requestor.receive_random_words(requestor_address, request_id, random_words, calldata); @@ -81,7 +81,7 @@ pub mod MockRandomness { } fn get_total_fees( - self: @ContractState, caller_address: ContractAddress, request_id: u64 + self: @ContractState, caller_address: ContractAddress, request_id: u64, ) -> u256 { self.total_fees.entry((caller_address, request_id)).read() } @@ -94,7 +94,7 @@ pub mod MockRandomness { ref self: ContractState, requestor_address: ContractAddress, request_id: u64, - new_status: RequestStatus + new_status: RequestStatus, ) { panic!("unimplemented") } @@ -107,24 +107,24 @@ pub mod MockRandomness { minimum_block_number: u64, callback_address: ContractAddress, callback_fee_limit: u128, - num_words: u64 + num_words: u64, ) { panic!("unimplemented") } fn get_pending_requests( - self: @ContractState, requestor_address: ContractAddress, offset: u64, max_len: u64 + self: @ContractState, requestor_address: ContractAddress, offset: u64, max_len: u64, ) -> Span { panic!("unimplemented") } fn get_request_status( - self: @ContractState, requestor_address: ContractAddress, request_id: u64 + self: @ContractState, requestor_address: ContractAddress, request_id: u64, ) -> RequestStatus { panic!("unimplemented") } fn requestor_current_index( - self: @ContractState, requestor_address: ContractAddress + self: @ContractState, requestor_address: ContractAddress, ) -> u64 { panic!("unimplemented") } @@ -141,7 +141,7 @@ pub mod MockRandomness { panic!("unimplemented") } fn refund_operation( - ref self: ContractState, caller_address: ContractAddress, request_id: u64 + ref self: ContractState, caller_address: ContractAddress, request_id: u64, ) { panic!("unimplemented") } @@ -156,7 +156,7 @@ pub mod MockRandomness { fn get_contract_balance(self: @ContractState) -> u256 { panic!("unimplemented") } - fn get_admin_address(self: @ContractState,) -> ContractAddress { + fn get_admin_address(self: @ContractState) -> ContractAddress { panic!("unimplemented") } fn set_admin_address(ref self: ContractState, new_admin_address: ContractAddress) { diff --git a/listings/applications/coin_flip/src/tests.cairo b/listings/applications/coin_flip/src/tests.cairo index bdaa0466..74bb63e9 100644 --- a/listings/applications/coin_flip/src/tests.cairo +++ b/listings/applications/coin_flip/src/tests.cairo @@ -4,7 +4,7 @@ use coin_flip::contract::{ use starknet::{ContractAddress, contract_address_const}; use snforge_std::{ declare, start_cheat_caller_address, stop_cheat_caller_address, spy_events, - EventSpyAssertionsTrait, DeclareResultTrait, ContractClassTrait + EventSpyAssertionsTrait, DeclareResultTrait, ContractClassTrait, }; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use pragma_lib::abi::{IRandomnessDispatcher, IRandomnessDispatcherTrait}; @@ -63,9 +63,7 @@ fn test_all_relevant_random_words() { (1001, Side::Tails, 8), (12345654321, Side::Tails, 9), ]; - for ( - random_word, expected_side, expected_request_id - ) in random_words { + for (random_word, expected_side, expected_request_id) in random_words { _flip_request( coin_flip, randomness, @@ -74,7 +72,7 @@ fn test_all_relevant_random_words() { expected_request_id, CALLBACK_FEE_LIMIT / 5 * 3, random_word, - expected_side + expected_side, ); } } @@ -89,7 +87,7 @@ fn test_multiple_flips() { stop_cheat_caller_address(eth.contract_address); _flip_request( - coin_flip, randomness, eth, deployer, 0, CALLBACK_FEE_LIMIT / 5 * 3, 123456789, Side::Tails + coin_flip, randomness, eth, deployer, 0, CALLBACK_FEE_LIMIT / 5 * 3, 123456789, Side::Tails, ); _flip_request( coin_flip, @@ -99,7 +97,7 @@ fn test_multiple_flips() { 1, CALLBACK_FEE_LIMIT / 4 * 3, 12345654321, - Side::Tails + Side::Tails, ); _flip_request(coin_flip, randomness, eth, deployer, 2, CALLBACK_FEE_LIMIT, 3, Side::Tails); } @@ -112,7 +110,7 @@ fn _flip_request( expected_request_id: u64, expected_callback_fee: u128, random_word: felt252, - expected_side: Side + expected_side: Side, ) { let original_balance = eth.balance_of(coin_flip.contract_address); @@ -128,17 +126,17 @@ fn _flip_request( ( coin_flip.contract_address, CoinFlip::Event::Flipped( - CoinFlip::Flipped { flip_id: expected_request_id, flipper: deployer } - ) - ) - ] + CoinFlip::Flipped { flip_id: expected_request_id, flipper: deployer }, + ), + ), + ], ); let post_flip_balance = eth.balance_of(coin_flip.contract_address); assert_eq!( post_flip_balance, original_balance - - randomness.get_total_fees(coin_flip.contract_address, expected_request_id) + - randomness.get_total_fees(coin_flip.contract_address, expected_request_id), ); randomness @@ -152,7 +150,7 @@ fn _flip_request( expected_callback_fee, array![random_word].span(), array![].span(), - array![] + array![], ); spy @@ -162,16 +160,16 @@ fn _flip_request( coin_flip.contract_address, CoinFlip::Event::Landed( CoinFlip::Landed { - flip_id: expected_request_id, flipper: deployer, side: expected_side - } - ) - ) - ] + flip_id: expected_request_id, flipper: deployer, side: expected_side, + }, + ), + ), + ], ); assert_eq!( eth.balance_of(coin_flip.contract_address), - post_flip_balance + (CALLBACK_FEE_LIMIT - expected_callback_fee).into() + post_flip_balance + (CALLBACK_FEE_LIMIT - expected_callback_fee).into(), ); } @@ -201,15 +199,15 @@ fn test_two_consecutive_flips() { @array![ ( coin_flip.contract_address, - CoinFlip::Event::Flipped(CoinFlip::Flipped { flip_id: 0, flipper: deployer }) + CoinFlip::Event::Flipped(CoinFlip::Flipped { flip_id: 0, flipper: deployer }), ), ( coin_flip.contract_address, CoinFlip::Event::Flipped( - CoinFlip::Flipped { flip_id: 1, flipper: other_flipper } - ) - ) - ] + CoinFlip::Flipped { flip_id: 1, flipper: other_flipper }, + ), + ), + ], ); let post_flip_balance = eth.balance_of(coin_flip.contract_address); @@ -234,7 +232,7 @@ fn test_two_consecutive_flips() { expected_callback_fee, array![random_word_deployer].span(), array![].span(), - array![] + array![], ); randomness .submit_random( @@ -247,7 +245,7 @@ fn test_two_consecutive_flips() { expected_callback_fee, array![random_word_other_flipper].span(), array![].span(), - array![] + array![], ); spy @@ -257,24 +255,24 @@ fn test_two_consecutive_flips() { coin_flip.contract_address, CoinFlip::Event::Landed( CoinFlip::Landed { - flip_id: 0, flipper: deployer, side: expected_side_deployer - } - ) + flip_id: 0, flipper: deployer, side: expected_side_deployer, + }, + ), ), ( coin_flip.contract_address, CoinFlip::Event::Landed( CoinFlip::Landed { - flip_id: 1, flipper: other_flipper, side: expected_side_other_flipper - } - ) - ) - ] + flip_id: 1, flipper: other_flipper, side: expected_side_other_flipper, + }, + ), + ), + ], ); assert_eq!( eth.balance_of(coin_flip.contract_address), - post_flip_balance + (CALLBACK_FEE_LIMIT - expected_callback_fee).into() * 2 + post_flip_balance + (CALLBACK_FEE_LIMIT - expected_callback_fee).into() * 2, ); } diff --git a/listings/applications/components/src/countable.cairo b/listings/applications/components/src/countable.cairo index 7a470909..36e905f8 100644 --- a/listings/applications/components/src/countable.cairo +++ b/listings/applications/components/src/countable.cairo @@ -16,7 +16,7 @@ pub mod countable_component { #[embeddable_as(Countable)] impl CountableImpl< - TContractState, +HasComponent + TContractState, +HasComponent, > of super::ICountable> { fn get(self: @ComponentState) -> u32 { self.countable_value.read() @@ -44,7 +44,7 @@ mod CountableContract { #[event] #[derive(Drop, starknet::Event)] enum Event { - CountableEvent: countable_component::Event + CountableEvent: countable_component::Event, } #[abi(embed_v0)] @@ -57,13 +57,12 @@ mod test { use super::CountableContract; use super::{ICountableDispatcher, ICountableDispatcherTrait}; use starknet::syscalls::deploy_syscall; - use starknet::SyscallResultTrait; fn deploy_countable() -> ICountableDispatcher { let (address, _) = deploy_syscall( - CountableContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + CountableContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); ICountableDispatcher { contract_address: address } } diff --git a/listings/applications/components/src/others/switch_collision.cairo b/listings/applications/components/src/others/switch_collision.cairo index fbb554a1..8db6e2a9 100644 --- a/listings/applications/components/src/others/switch_collision.cairo +++ b/listings/applications/components/src/others/switch_collision.cairo @@ -19,6 +19,7 @@ pub mod SwitchCollisionContract { // [!region storage] #[storage] + #[allow(starknet::colliding_storage_paths)] struct Storage { switchable_value: bool, #[substorage(v0)] @@ -53,16 +54,15 @@ pub mod SwitchCollisionContract { mod switch_collision_tests { use components::switchable::{ISwitchableDispatcher, ISwitchableDispatcherTrait}; use super::{ - SwitchCollisionContract, ISwitchCollisionDispatcher, ISwitchCollisionDispatcherTrait + SwitchCollisionContract, ISwitchCollisionDispatcher, ISwitchCollisionDispatcherTrait, }; - use starknet::SyscallResultTrait; use starknet::syscalls::deploy_syscall; fn deploy() -> (ISwitchCollisionDispatcher, ISwitchableDispatcher) { let (contract_address, _) = deploy_syscall( - SwitchCollisionContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + SwitchCollisionContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); ( ISwitchCollisionDispatcher { contract_address }, diff --git a/listings/applications/components/src/ownable.cairo b/listings/applications/components/src/ownable.cairo index cd3698d9..accb3e19 100644 --- a/listings/applications/components/src/ownable.cairo +++ b/listings/applications/components/src/ownable.cairo @@ -29,24 +29,24 @@ pub mod ownable_component { #[derive(Drop, Debug, PartialEq, starknet::Event)] pub struct OwnershipTransferredEvent { pub previous: ContractAddress, - pub new: ContractAddress + pub new: ContractAddress, } #[derive(Drop, Debug, PartialEq, starknet::Event)] pub struct OwnershipRenouncedEvent { - pub previous: ContractAddress + pub previous: ContractAddress, } #[event] #[derive(Drop, Debug, PartialEq, starknet::Event)] pub enum Event { OwnershipTransferredEvent: OwnershipTransferredEvent, - OwnershipRenouncedEvent: OwnershipRenouncedEvent + OwnershipRenouncedEvent: OwnershipRenouncedEvent, } #[embeddable_as(Ownable)] pub impl OwnableImpl< - TContractState, +HasComponent + TContractState, +HasComponent, > of super::IOwnable> { fn owner(self: @ComponentState) -> ContractAddress { self.ownable_owner.read() @@ -65,7 +65,7 @@ pub mod ownable_component { #[generate_trait] pub impl OwnableInternalImpl< - TContractState, +HasComponent + TContractState, +HasComponent, > of OwnableInternalTrait { fn _assert_only_owner(self: @ComponentState) { let caller = get_caller_address(); @@ -84,7 +84,7 @@ pub mod ownable_component { self.ownable_owner.write(new); self .emit( - Event::OwnershipTransferredEvent(OwnershipTransferredEvent { previous, new }) + Event::OwnershipTransferredEvent(OwnershipTransferredEvent { previous, new }), ); } @@ -132,15 +132,15 @@ mod test { use super::ownable_component::{OwnershipRenouncedEvent, OwnershipTransferredEvent}; use super::{IOwnableDispatcher, IOwnableDispatcherTrait}; use starknet::ContractAddress; - use starknet::{syscalls::deploy_syscall, SyscallResultTrait, contract_address_const}; + use starknet::{syscalls::deploy_syscall, contract_address_const}; use starknet::testing::{set_contract_address}; use core::num::traits::Zero; fn deploy() -> (IOwnableDispatcher, ContractAddress) { let (contract_address, _) = deploy_syscall( - OwnedContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + OwnedContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); (IOwnableDispatcher { contract_address }, contract_address) } @@ -167,9 +167,9 @@ mod test { starknet::testing::pop_log(address), Option::Some( OwnedContract::Event::OwnableEvent( - OwnershipTransferredEvent { previous: contract_address, new: new_owner }.into() - ) - ) + OwnershipTransferredEvent { previous: contract_address, new: new_owner }.into(), + ), + ), ); } @@ -204,9 +204,9 @@ mod test { starknet::testing::pop_log(address), Option::Some( OwnedContract::Event::OwnableEvent( - OwnershipRenouncedEvent { previous: contract_address }.into() - ) - ) + OwnershipRenouncedEvent { previous: contract_address }.into(), + ), + ), ); } diff --git a/listings/applications/components/src/switchable.cairo b/listings/applications/components/src/switchable.cairo index a6dcd4fd..71f89f5b 100644 --- a/listings/applications/components/src/switchable.cairo +++ b/listings/applications/components/src/switchable.cairo @@ -27,7 +27,7 @@ pub mod switchable_component { #[embeddable_as(Switchable)] impl SwitchableImpl< - TContractState, +HasComponent + TContractState, +HasComponent, > of super::ISwitchable> { fn is_on(self: @ComponentState) -> bool { self.switchable_value.read() @@ -41,7 +41,7 @@ pub mod switchable_component { #[generate_trait] pub impl SwitchableInternalImpl< - TContractState, +HasComponent + TContractState, +HasComponent, > of SwitchableInternalTrait { fn _off(ref self: ComponentState) { self.switchable_value.write(false); @@ -90,13 +90,12 @@ mod test { use super::switchable_component::SwitchEvent; use super::{ISwitchableDispatcher, ISwitchableDispatcherTrait}; use starknet::{syscalls::deploy_syscall, ContractAddress}; - use starknet::SyscallResultTrait; fn deploy() -> (ISwitchableDispatcher, ContractAddress) { let (address, _) = deploy_syscall( - SwitchContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + SwitchContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); (ISwitchableDispatcher { contract_address: address }, address) } @@ -113,7 +112,7 @@ mod test { assert_eq!(switchable.is_on(), true); assert_eq!( starknet::testing::pop_log(contract_address), - Option::Some(SwitchContract::Event::SwitchableEvent(SwitchEvent {}.into())) + Option::Some(SwitchContract::Event::SwitchableEvent(SwitchEvent {}.into())), ); } diff --git a/listings/applications/components_dependencies/src/contract_countable.cairo b/listings/applications/components_dependencies/src/contract_countable.cairo index 42f1d76a..7de2ec71 100644 --- a/listings/applications/components_dependencies/src/contract_countable.cairo +++ b/listings/applications/components_dependencies/src/contract_countable.cairo @@ -14,7 +14,7 @@ mod CountableContract { struct Storage { #[substorage(v0)] counter: countable_component::Storage, - switch: bool + switch: bool, } // Implementation of the dependency: @@ -48,16 +48,15 @@ mod tests { use components::countable::{ICountableDispatcher, ICountableDispatcherTrait}; use components::switchable::{ISwitchableDispatcher, ISwitchableDispatcherTrait}; - use starknet::SyscallResultTrait; use starknet::syscalls::deploy_syscall; fn deploy() -> (ICountableDispatcher, ISwitchableDispatcher) { let (contract_address, _) = deploy_syscall( - CountableContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + CountableContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); - (ICountableDispatcher { contract_address }, ISwitchableDispatcher { contract_address },) + (ICountableDispatcher { contract_address }, ISwitchableDispatcher { contract_address }) } #[test] diff --git a/listings/applications/components_dependencies/src/contract_countable_switchable.cairo b/listings/applications/components_dependencies/src/contract_countable_switchable.cairo index d190e997..b8aa72f9 100644 --- a/listings/applications/components_dependencies/src/contract_countable_switchable.cairo +++ b/listings/applications/components_dependencies/src/contract_countable_switchable.cairo @@ -18,7 +18,7 @@ mod CountableContract { #[substorage(v0)] counter: countable_component::Storage, #[substorage(v0)] - switch: switchable_component::Storage + switch: switchable_component::Storage, } #[constructor] @@ -41,16 +41,15 @@ mod tests { use components::countable::{ICountableDispatcher, ICountableDispatcherTrait}; use components::switchable::{ISwitchableDispatcher, ISwitchableDispatcherTrait}; - use starknet::SyscallResultTrait; use starknet::syscalls::deploy_syscall; fn deploy() -> (ICountableDispatcher, ISwitchableDispatcher) { let (contract_address, _) = deploy_syscall( - CountableContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + CountableContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); - (ICountableDispatcher { contract_address }, ISwitchableDispatcher { contract_address },) + (ICountableDispatcher { contract_address }, ISwitchableDispatcher { contract_address }) } #[test] diff --git a/listings/applications/components_dependencies/src/contract_countable_switchable_internal.cairo b/listings/applications/components_dependencies/src/contract_countable_switchable_internal.cairo index b79592aa..2768495b 100644 --- a/listings/applications/components_dependencies/src/contract_countable_switchable_internal.cairo +++ b/listings/applications/components_dependencies/src/contract_countable_switchable_internal.cairo @@ -18,7 +18,7 @@ pub mod CountableContract { #[substorage(v0)] counter: countable_component::Storage, #[substorage(v0)] - switch: switchable_component::Storage + switch: switchable_component::Storage, } #[constructor] @@ -41,16 +41,15 @@ mod tests { use components::countable::{ICountableDispatcher, ICountableDispatcherTrait}; use components::switchable::{ISwitchableDispatcher, ISwitchableDispatcherTrait}; - use starknet::SyscallResultTrait; use starknet::syscalls::deploy_syscall; fn deploy() -> (ICountableDispatcher, ISwitchableDispatcher) { let (contract_address, _) = deploy_syscall( - CountableContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + CountableContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); - (ICountableDispatcher { contract_address }, ISwitchableDispatcher { contract_address },) + (ICountableDispatcher { contract_address }, ISwitchableDispatcher { contract_address }) } #[test] diff --git a/listings/applications/components_dependencies/src/countable_dep_switch.cairo b/listings/applications/components_dependencies/src/countable_dep_switch.cairo index ec59fa0d..3d8a7dce 100644 --- a/listings/applications/components_dependencies/src/countable_dep_switch.cairo +++ b/listings/applications/components_dependencies/src/countable_dep_switch.cairo @@ -13,7 +13,7 @@ pub mod countable_component { // [!region impl] #[embeddable_as(Countable)] impl CountableImpl< - TContractState, +HasComponent, +ISwitchable + TContractState, +HasComponent, +ISwitchable, > of ICountable> { fn get(self: @ComponentState) -> u32 { self.countable_value.read() @@ -68,13 +68,12 @@ mod test { use super::MockContract; use components::countable::{ICountableDispatcher, ICountableDispatcherTrait}; use starknet::syscalls::deploy_syscall; - use starknet::SyscallResultTrait; fn deploy_countable() -> ICountableDispatcher { let (contract_address, _) = deploy_syscall( - MockContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + MockContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); ICountableDispatcher { contract_address: contract_address } } diff --git a/listings/applications/components_dependencies/src/countable_internal_dep_switch.cairo b/listings/applications/components_dependencies/src/countable_internal_dep_switch.cairo index c6c82ac6..d055128c 100644 --- a/listings/applications/components_dependencies/src/countable_internal_dep_switch.cairo +++ b/listings/applications/components_dependencies/src/countable_internal_dep_switch.cairo @@ -19,17 +19,17 @@ pub mod countable_component { TContractState, +HasComponent, +switchable_component::HasComponent, - +Drop + +Drop, > of GetSwitchableTrait { fn get_switchable( - self: @ComponentState + self: @ComponentState, ) -> @switchable_component::ComponentState { let contract = self.get_contract(); switchable_component::HasComponent::::get_component(contract) } fn get_switchable_mut( - ref self: ComponentState + ref self: ComponentState, ) -> switchable_component::ComponentState { let mut contract = self.get_contract_mut(); switchable_component::HasComponent::::get_component_mut(ref contract) @@ -42,7 +42,7 @@ pub mod countable_component { +HasComponent, +ISwitchable, +switchable_component::HasComponent, - +Drop + +Drop, > of ICountable> { fn get(self: @ComponentState) -> u32 { self.countable_value.read() diff --git a/listings/applications/constant_product_amm/src/contracts.cairo b/listings/applications/constant_product_amm/src/contracts.cairo index b5649115..9b203a8a 100644 --- a/listings/applications/constant_product_amm/src/contracts.cairo +++ b/listings/applications/constant_product_amm/src/contracts.cairo @@ -31,7 +31,7 @@ pub mod ConstantProductAmm { #[constructor] fn constructor( - ref self: ContractState, token0: ContractAddress, token1: ContractAddress, fee: u16 + ref self: ContractState, token0: ContractAddress, token1: ContractAddress, fee: u16, ) { // assert(fee <= 1000, 'fee > 1000'); self.token0.write(IERC20Dispatcher { contract_address: token0 }); @@ -61,7 +61,7 @@ pub mod ConstantProductAmm { assert( token == self.token0.read().contract_address || token == self.token1.read().contract_address, - 'invalid token' + 'invalid token', ); token == self.token0.read().contract_address } @@ -83,11 +83,11 @@ pub mod ConstantProductAmm { let is_token0: bool = self.select_token(token_in); let (token0, token1): (IERC20Dispatcher, IERC20Dispatcher) = ( - self.token0.read(), self.token1.read() + self.token0.read(), self.token1.read(), ); let (reserve0, reserve1): (u256, u256) = (self.reserve0.read(), self.reserve1.read()); let ( - token_in, token_out, reserve_in, reserve_out + token_in, token_out, reserve_in, reserve_out, ): (IERC20Dispatcher, IERC20Dispatcher, u256, u256) = if (is_token0) { (token0, token1, reserve0, reserve1) @@ -121,7 +121,7 @@ pub mod ConstantProductAmm { let caller = get_caller_address(); let this = get_contract_address(); let (token0, token1): (IERC20Dispatcher, IERC20Dispatcher) = ( - self.token0.read(), self.token1.read() + self.token0.read(), self.token1.read(), ); token0.transfer_from(caller, this, amount0); @@ -196,7 +196,7 @@ pub mod ConstantProductAmm { (amount0 * amount1).sqrt().into() } else { PrivateFunctions::min( - amount0 * total_supply / reserve0, amount1 * total_supply / reserve1 + amount0 * total_supply / reserve0, amount1 * total_supply / reserve1, ) }; assert(shares > 0, 'shares = 0'); @@ -210,7 +210,7 @@ pub mod ConstantProductAmm { let caller = get_caller_address(); let this = get_contract_address(); let (token0, token1): (IERC20Dispatcher, IERC20Dispatcher) = ( - self.token0.read(), self.token1.read() + self.token0.read(), self.token1.read(), ); // Claim @@ -251,7 +251,7 @@ pub mod ConstantProductAmm { let total_supply = self.total_supply.read(); let (amount0, amount1): (u256, u256) = ( - (shares * bal0) / total_supply, (shares * bal1) / total_supply + (shares * bal0) / total_supply, (shares * bal1) / total_supply, ); assert(amount0 > 0 && amount1 > 0, 'amount0 or amount1 = 0'); diff --git a/listings/applications/constant_product_amm/src/tests.cairo b/listings/applications/constant_product_amm/src/tests.cairo index 7a87e616..e1d1970a 100644 --- a/listings/applications/constant_product_amm/src/tests.cairo +++ b/listings/applications/constant_product_amm/src/tests.cairo @@ -13,14 +13,14 @@ pub mod ERC20Token { #[storage] struct Storage { #[substorage(v0)] - erc20: ERC20Component::Storage + erc20: ERC20Component::Storage, } #[event] #[derive(Drop, starknet::Event)] enum Event { #[flat] - ERC20Event: ERC20Component::Event + ERC20Event: ERC20Component::Event, } #[constructor] @@ -29,7 +29,7 @@ pub mod ERC20Token { initial_supply: u256, recipient: ContractAddress, name: ByteArray, - symbol: ByteArray + symbol: ByteArray, ) { self.erc20.initializer(name, symbol); self.erc20.mint(recipient, initial_supply); diff --git a/listings/applications/crowdfunding/src/campaign.cairo b/listings/applications/crowdfunding/src/campaign.cairo index 607eae69..684093f7 100644 --- a/listings/applications/crowdfunding/src/campaign.cairo +++ b/listings/applications/crowdfunding/src/campaign.cairo @@ -37,8 +37,7 @@ pub mod Campaign { use core::num::traits::Zero; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use starknet::{ - ClassHash, ContractAddress, SyscallResultTrait, get_block_timestamp, get_caller_address, - get_contract_address + ClassHash, ContractAddress, get_block_timestamp, get_caller_address, get_contract_address, }; use components::ownable::ownable_component; use super::pledgeable::pledgeable_component; @@ -125,7 +124,7 @@ pub mod Campaign { #[derive(Drop, starknet::Event)] pub struct Upgraded { - pub implementation: ClassHash + pub implementation: ClassHash, } pub mod Errors { @@ -296,14 +295,15 @@ pub mod Campaign { if let Option::Some(end_time) = new_end_time { assert(end_time >= get_block_timestamp(), Errors::END_BEFORE_NOW); assert( - end_time <= get_block_timestamp() + NINETY_DAYS, Errors::END_BIGGER_THAN_MAX + end_time <= get_block_timestamp() + NINETY_DAYS, + Errors::END_BIGGER_THAN_MAX, ); self.end_time.write(end_time); }; self._refund_all("contract upgraded"); } - starknet::syscalls::replace_class_syscall(impl_hash).unwrap_syscall(); + starknet::syscalls::replace_class_syscall(impl_hash).unwrap(); self.emit(Event::Upgraded(Upgraded { implementation: impl_hash })); } diff --git a/listings/applications/crowdfunding/src/campaign/pledgeable.cairo b/listings/applications/crowdfunding/src/campaign/pledgeable.cairo index 06ffbe5c..2b90459a 100644 --- a/listings/applications/crowdfunding/src/campaign/pledgeable.cairo +++ b/listings/applications/crowdfunding/src/campaign/pledgeable.cairo @@ -18,7 +18,7 @@ pub mod pledgeable_component { use starknet::ContractAddress; use starknet::storage::{ Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess + StoragePointerWriteAccess, }; #[storage] @@ -39,7 +39,7 @@ pub mod pledgeable_component { #[embeddable_as(Pledgeable)] pub impl PledgeableImpl< - TContractState, +HasComponent + TContractState, +HasComponent, > of super::IPledgeable> { fn add(ref self: ComponentState, pledger: ContractAddress, amount: u256) { let old_amount: u256 = self.pledger_to_amount.read(pledger); @@ -134,7 +134,7 @@ mod tests { #[event] #[derive(Drop, starknet::Event)] enum Event { - PledgeableEvent: pledgeable_component::Event + PledgeableEvent: pledgeable_component::Event, } #[abi(embed_v0)] diff --git a/listings/applications/crowdfunding/src/mock_upgrade.cairo b/listings/applications/crowdfunding/src/mock_upgrade.cairo index de4c5e60..ee89427c 100644 --- a/listings/applications/crowdfunding/src/mock_upgrade.cairo +++ b/listings/applications/crowdfunding/src/mock_upgrade.cairo @@ -5,8 +5,7 @@ pub mod MockUpgrade { use core::num::traits::Zero; use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use starknet::{ - ClassHash, ContractAddress, SyscallResultTrait, get_block_timestamp, get_caller_address, - get_contract_address + ClassHash, ContractAddress, get_block_timestamp, get_caller_address, get_contract_address, }; use components::ownable::ownable_component; use crowdfunding::campaign::pledgeable::pledgeable_component; @@ -93,7 +92,7 @@ pub mod MockUpgrade { #[derive(Drop, starknet::Event)] pub struct Upgraded { - pub implementation: ClassHash + pub implementation: ClassHash, } const NINETY_DAYS: u64 = 90 * 24 * 60 * 60; @@ -237,14 +236,15 @@ pub mod MockUpgrade { if let Option::Some(end_time) = new_end_time { assert(end_time >= get_block_timestamp(), Errors::END_BEFORE_NOW); assert( - end_time <= get_block_timestamp() + NINETY_DAYS, Errors::END_BIGGER_THAN_MAX + end_time <= get_block_timestamp() + NINETY_DAYS, + Errors::END_BIGGER_THAN_MAX, ); self.end_time.write(end_time); }; self._refund_all("contract upgraded"); } - starknet::syscalls::replace_class_syscall(impl_hash).unwrap_syscall(); + starknet::syscalls::replace_class_syscall(impl_hash).unwrap(); self.emit(Event::Upgraded(Upgraded { implementation: impl_hash })); } diff --git a/listings/applications/crowdfunding/src/tests.cairo b/listings/applications/crowdfunding/src/tests.cairo index 11f2aaa5..57f0ecec 100644 --- a/listings/applications/crowdfunding/src/tests.cairo +++ b/listings/applications/crowdfunding/src/tests.cairo @@ -1,8 +1,8 @@ -use starknet::{ContractAddress, get_block_timestamp, contract_address_const,}; +use starknet::{ContractAddress, get_block_timestamp, contract_address_const}; use snforge_std::{ declare, ContractClass, ContractClassTrait, start_cheat_caller_address, stop_cheat_caller_address, spy_events, EventSpyAssertionsTrait, get_class_hash, - DeclareResultTrait, start_cheat_block_timestamp_global + DeclareResultTrait, start_cheat_block_timestamp_global, }; use crowdfunding::campaign::{Campaign, ICampaignDispatcher, ICampaignDispatcherTrait}; @@ -17,7 +17,7 @@ fn deploy( goal: u256, start_time: u64, end_time: u64, - token: ContractAddress + token: ContractAddress, ) -> ICampaignDispatcher { let creator = contract_address_const::<'creator'>(); let mut calldata: Array:: = array![]; @@ -35,7 +35,7 @@ fn deploy( } fn deploy_with_token( - contract: ContractClass, token: ContractClass + contract: ContractClass, token: ContractClass, ) -> (ICampaignDispatcher, IERC20Dispatcher) { // define ERC20 data let token_name: ByteArray = "My Token"; @@ -65,7 +65,7 @@ fn deploy_with_token( let start_time = get_block_timestamp(); let end_time = start_time + 60; let campaign_dispatcher = deploy( - contract, "title 1", "description 1", 10000, start_time, end_time, token_address + contract, "title 1", "description 1", 10000, start_time, end_time, token_address, ); // approve the pledges for each pledger @@ -96,7 +96,7 @@ fn test_deploy() { 10000, start_time, end_time, - contract_address_const::<'token'>() + contract_address_const::<'token'>(), ); let details = campaign.get_details(); @@ -143,10 +143,10 @@ fn test_successful_campaign() { ( campaign.contract_address, Campaign::Event::PledgeMade( - Campaign::PledgeMade { pledger: pledger_1, amount: 3000 } - ) - ) - ] + Campaign::PledgeMade { pledger: pledger_1, amount: 3000 }, + ), + ), + ], ); // 2nd donation @@ -163,10 +163,10 @@ fn test_successful_campaign() { ( campaign.contract_address, Campaign::Event::PledgeMade( - Campaign::PledgeMade { pledger: pledger_2, amount: 500 } - ) - ) - ] + Campaign::PledgeMade { pledger: pledger_2, amount: 500 }, + ), + ), + ], ); // 3rd donation @@ -183,10 +183,10 @@ fn test_successful_campaign() { ( campaign.contract_address, Campaign::Event::PledgeMade( - Campaign::PledgeMade { pledger: pledger_3, amount: 7000 } - ) - ) - ] + Campaign::PledgeMade { pledger: pledger_3, amount: 7000 }, + ), + ), + ], ); // claim @@ -202,9 +202,9 @@ fn test_successful_campaign() { @array![ ( campaign.contract_address, - Campaign::Event::Claimed(Campaign::Claimed { amount: 10500 }) - ) - ] + Campaign::Event::Claimed(Campaign::Claimed { amount: 10500 }), + ), + ], ); } @@ -230,9 +230,11 @@ fn test_upgrade_class_hash() { @array![ ( campaign.contract_address, - Campaign::Event::Upgraded(Campaign::Upgraded { implementation: new_class_hash }) - ) - ] + Campaign::Event::Upgraded( + Campaign::Upgraded { implementation: new_class_hash }, + ), + ), + ], ); // test active campaign @@ -268,15 +270,17 @@ fn test_upgrade_class_hash() { @array![ ( campaign.contract_address, - Campaign::Event::Upgraded(Campaign::Upgraded { implementation: new_class_hash }) + Campaign::Event::Upgraded( + Campaign::Upgraded { implementation: new_class_hash }, + ), ), ( campaign.contract_address, Campaign::Event::RefundedAll( - Campaign::RefundedAll { reason: "contract upgraded" } - ) - ) - ] + Campaign::RefundedAll { reason: "contract upgraded" }, + ), + ), + ], ); } @@ -325,13 +329,13 @@ fn test_cancel() { @array![ ( campaign.contract_address, - Campaign::Event::RefundedAll(Campaign::RefundedAll { reason: "testing" }) + Campaign::Event::RefundedAll(Campaign::RefundedAll { reason: "testing" }), ), ( campaign.contract_address, - Campaign::Event::Canceled(Campaign::Canceled { reason: "testing" }) - ) - ] + Campaign::Event::Canceled(Campaign::Canceled { reason: "testing" }), + ), + ], ); // test failed campaign @@ -376,13 +380,13 @@ fn test_cancel() { @array![ ( campaign.contract_address, - Campaign::Event::RefundedAll(Campaign::RefundedAll { reason: "testing" }) + Campaign::Event::RefundedAll(Campaign::RefundedAll { reason: "testing" }), ), ( campaign.contract_address, - Campaign::Event::Canceled(Campaign::Canceled { reason: "testing" }) - ) - ] + Campaign::Event::Canceled(Campaign::Canceled { reason: "testing" }), + ), + ], ); } @@ -391,7 +395,7 @@ fn test_refund() { // setup let (campaign, token) = deploy_with_token( *declare("Campaign").unwrap().contract_class(), - *declare("ERC20Upgradeable").unwrap().contract_class() + *declare("ERC20Upgradeable").unwrap().contract_class(), ); let mut spy = spy_events(); let creator = contract_address_const::<'creator'>(); @@ -430,11 +434,11 @@ fn test_refund() { campaign.contract_address, Campaign::Event::Refunded( Campaign::Refunded { - pledger: pledger_1, amount: amount_1, reason: "testing" - } - ) - ) - ] + pledger: pledger_1, amount: amount_1, reason: "testing", + }, + ), + ), + ], ); } @@ -443,7 +447,7 @@ fn test_unpledge() { // setup let (campaign, token) = deploy_with_token( *declare("Campaign").unwrap().contract_class(), - *declare("ERC20Upgradeable").unwrap().contract_class() + *declare("ERC20Upgradeable").unwrap().contract_class(), ); let mut spy = spy_events(); let pledger = contract_address_const::<'pledger_1'>(); @@ -469,9 +473,9 @@ fn test_unpledge() { ( campaign.contract_address, Campaign::Event::Unpledged( - Campaign::Unpledged { pledger, amount, reason: "testing" } - ) - ) - ] + Campaign::Unpledged { pledger, amount, reason: "testing" }, + ), + ), + ], ); } diff --git a/listings/applications/erc20/src/token.cairo b/listings/applications/erc20/src/token.cairo index 467e6e85..4baa0e43 100644 --- a/listings/applications/erc20/src/token.cairo +++ b/listings/applications/erc20/src/token.cairo @@ -9,19 +9,19 @@ pub trait IERC20 { fn get_total_supply(self: @TContractState) -> felt252; fn balance_of(self: @TContractState, account: ContractAddress) -> felt252; fn allowance( - self: @TContractState, owner: ContractAddress, spender: ContractAddress + self: @TContractState, owner: ContractAddress, spender: ContractAddress, ) -> felt252; fn transfer(ref self: TContractState, recipient: ContractAddress, amount: felt252); fn transfer_from( ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, - amount: felt252 + amount: felt252, ); fn approve(ref self: TContractState, spender: ContractAddress, amount: felt252); fn increase_allowance(ref self: TContractState, spender: ContractAddress, added_value: felt252); fn decrease_allowance( - ref self: TContractState, spender: ContractAddress, subtracted_value: felt252 + ref self: TContractState, spender: ContractAddress, subtracted_value: felt252, ); } // [!endregion interface] @@ -35,7 +35,7 @@ pub mod erc20 { use starknet::ContractAddress; use starknet::storage::{ Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess + StoragePointerWriteAccess, }; #[storage] @@ -83,7 +83,7 @@ pub mod erc20 { name: felt252, decimals: u8, initial_supply: felt252, - symbol: felt252 + symbol: felt252, ) { self.name.write(name); self.symbol.write(symbol); @@ -114,7 +114,7 @@ pub mod erc20 { } fn allowance( - self: @ContractState, owner: ContractAddress, spender: ContractAddress + self: @ContractState, owner: ContractAddress, spender: ContractAddress, ) -> felt252 { self.allowances.read((owner, spender)) } @@ -128,7 +128,7 @@ pub mod erc20 { ref self: ContractState, sender: ContractAddress, recipient: ContractAddress, - amount: felt252 + amount: felt252, ) { let caller = get_caller_address(); self.spend_allowance(sender, caller, amount); @@ -141,22 +141,22 @@ pub mod erc20 { } fn increase_allowance( - ref self: ContractState, spender: ContractAddress, added_value: felt252 + ref self: ContractState, spender: ContractAddress, added_value: felt252, ) { let caller = get_caller_address(); self .approve_helper( - caller, spender, self.allowances.read((caller, spender)) + added_value + caller, spender, self.allowances.read((caller, spender)) + added_value, ); } fn decrease_allowance( - ref self: ContractState, spender: ContractAddress, subtracted_value: felt252 + ref self: ContractState, spender: ContractAddress, subtracted_value: felt252, ) { let caller = get_caller_address(); self .approve_helper( - caller, spender, self.allowances.read((caller, spender)) - subtracted_value + caller, spender, self.allowances.read((caller, spender)) - subtracted_value, ); } } @@ -167,7 +167,7 @@ pub mod erc20 { ref self: ContractState, sender: ContractAddress, recipient: ContractAddress, - amount: felt252 + amount: felt252, ) { assert(sender.is_non_zero(), Errors::TRANSFER_FROM_ZERO); assert(recipient.is_non_zero(), Errors::TRANSFER_TO_ZERO); @@ -180,7 +180,7 @@ pub mod erc20 { ref self: ContractState, owner: ContractAddress, spender: ContractAddress, - amount: felt252 + amount: felt252, ) { let allowance = self.allowances.read((owner, spender)); self.allowances.write((owner, spender), allowance - amount); @@ -190,7 +190,7 @@ pub mod erc20 { ref self: ContractState, owner: ContractAddress, spender: ContractAddress, - amount: felt252 + amount: felt252, ) { assert(spender.is_non_zero(), Errors::APPROVE_TO_ZERO); self.allowances.write((owner, spender), amount); @@ -207,9 +207,9 @@ pub mod erc20 { .emit( Event::Transfer( Transfer { - from: contract_address_const::<0>(), to: recipient, value: amount - } - ) + from: contract_address_const::<0>(), to: recipient, value: amount, + }, + ), ); } } @@ -220,9 +220,7 @@ pub mod erc20 { mod tests { use super::{erc20, IERC20Dispatcher, IERC20DispatcherTrait, erc20::{Event, Transfer, Approval}}; - use starknet::{ - ContractAddress, SyscallResultTrait, syscalls::deploy_syscall, contract_address_const - }; + use starknet::{ContractAddress, syscalls::deploy_syscall, contract_address_const}; use core::num::traits::Zero; use starknet::testing::set_contract_address; @@ -239,16 +237,16 @@ mod tests { erc20::TEST_CLASS_HASH.try_into().unwrap(), recipient.into(), array![recipient.into(), token_name, decimals.into(), initial_supply, symbols].span(), - false + false, ) - .unwrap_syscall(); + .unwrap(); (IERC20Dispatcher { contract_address }, contract_address) } #[test] - #[should_panic(expected: ('ERC20: mint to 0', 'CONSTRUCTOR_FAILED'))] + #[should_panic] fn test_deploy_when_recipient_is_address_zero() { let recipient: ContractAddress = Zero::zero(); @@ -256,9 +254,9 @@ mod tests { erc20::TEST_CLASS_HASH.try_into().unwrap(), recipient.into(), array![recipient.into(), token_name, decimals.into(), initial_supply, symbols].span(), - false + false, ) - .unwrap_syscall(); + .unwrap(); } #[test] fn test_deploy_success() { @@ -268,9 +266,9 @@ mod tests { starknet::testing::pop_log(contract_address), Option::Some( Event::Transfer( - Transfer { from: Zero::zero(), to: recipient, value: initial_supply } - ) - ) + Transfer { from: Zero::zero(), to: recipient, value: initial_supply }, + ), + ), ); } @@ -305,7 +303,7 @@ mod tests { let recipient = contract_address_const::<'initialized_recipient'>(); let (dispatcher, _) = deploy(); assert( - dispatcher.balance_of(recipient) == initial_supply, 'incorrect balance of recipient' + dispatcher.balance_of(recipient) == initial_supply, 'incorrect balance of recipient', ); } @@ -353,14 +351,14 @@ mod tests { starknet::testing::pop_log(contract_address), Option::Some( Event::Transfer( - Transfer { from: Zero::zero(), to: recipient, value: initial_supply } - ) - ) + Transfer { from: Zero::zero(), to: recipient, value: initial_supply }, + ), + ), ); assert_eq!( starknet::testing::pop_log(contract_address), - Option::Some(Event::Approval(Approval { owner: caller, spender, value })) + Option::Some(Event::Approval(Approval { owner: caller, spender, value })), ); } @@ -386,7 +384,7 @@ mod tests { set_contract_address(caller); dispatcher.increase_allowance(spender, 100); assert( - dispatcher.allowance(caller, spender) == amount + 100, 'incorrect increased allowance' + dispatcher.allowance(caller, spender) == amount + 100, 'incorrect increased allowance', ); // emits one transfer event and two approval events @@ -395,19 +393,19 @@ mod tests { starknet::testing::pop_log(contract_address), Option::Some( Event::Transfer( - Transfer { from: Zero::zero(), to: recipient, value: initial_supply } - ) - ) + Transfer { from: Zero::zero(), to: recipient, value: initial_supply }, + ), + ), ); assert_eq!( starknet::testing::pop_log(contract_address), - Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount })) + Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount })), ); assert_eq!( starknet::testing::pop_log(contract_address), - Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount + 100 })) + Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount + 100 })), ); } @@ -434,7 +432,7 @@ mod tests { set_contract_address(caller); dispatcher.decrease_allowance(spender, 90); assert( - dispatcher.allowance(caller, spender) == amount - 90, 'incorrect decreased allowance' + dispatcher.allowance(caller, spender) == amount - 90, 'incorrect decreased allowance', ); // emits one transfer event and two approval events @@ -443,19 +441,19 @@ mod tests { starknet::testing::pop_log(contract_address), Option::Some( Event::Transfer( - Transfer { from: Zero::zero(), to: recipient, value: initial_supply } - ) - ) + Transfer { from: Zero::zero(), to: recipient, value: initial_supply }, + ), + ), ); assert_eq!( starknet::testing::pop_log(contract_address), - Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount })) + Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount })), ); assert_eq!( starknet::testing::pop_log(contract_address), - Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount - 90 })) + Option::Some(Event::Approval(Approval { owner: caller, spender, value: amount - 90 })), ); } @@ -494,13 +492,13 @@ mod tests { assert_eq!( starknet::testing::pop_log(contract_address), Option::Some( - Event::Transfer(Transfer { from: Zero::zero(), to: caller, value: initial_supply }) - ) + Event::Transfer(Transfer { from: Zero::zero(), to: caller, value: initial_supply }), + ), ); assert_eq!( starknet::testing::pop_log(contract_address), - Option::Some(Event::Transfer(Transfer { from: caller, to: receiver, value: amount })) + Option::Some(Event::Transfer(Transfer { from: caller, to: receiver, value: amount })), ); } @@ -543,13 +541,13 @@ mod tests { assert_eq!( starknet::testing::pop_log(contract_address), Option::Some( - Event::Transfer(Transfer { from: Zero::zero(), to: caller, value: initial_supply }) - ) + Event::Transfer(Transfer { from: Zero::zero(), to: caller, value: initial_supply }), + ), ); assert_eq!( starknet::testing::pop_log(contract_address), - Option::Some(Event::Transfer(Transfer { from: caller, to: receiver, value: amount })) + Option::Some(Event::Transfer(Transfer { from: caller, to: receiver, value: amount })), ); } } diff --git a/listings/applications/merkle_tree/src/contract.cairo b/listings/applications/merkle_tree/src/contract.cairo index bc5a2d67..e26e1d03 100644 --- a/listings/applications/merkle_tree/src/contract.cairo +++ b/listings/applications/merkle_tree/src/contract.cairo @@ -14,7 +14,7 @@ pub trait IMerkleTree { fn get_root(self: @TContractState) -> felt252; // function to verify if leaf node exists in the merkle tree fn verify( - self: @TContractState, proof: Array, root: felt252, leaf: felt252, index: usize + self: @TContractState, proof: Array, root: felt252, leaf: felt252, index: usize, ) -> bool; } @@ -28,19 +28,19 @@ pub mod MerkleTree { use core::poseidon::PoseidonTrait; use core::hash::{HashStateTrait, HashStateExTrait}; use starknet::storage::{ - StoragePointerWriteAccess, StoragePointerReadAccess, Vec, MutableVecTrait, VecTrait + StoragePointerWriteAccess, StoragePointerReadAccess, Vec, MutableVecTrait, VecTrait, }; use super::ByteArrayHashTrait; #[storage] struct Storage { - pub hashes: Vec + pub hashes: Vec, } #[derive(Drop, Serde, Copy)] struct Vec2 { x: u32, - y: u32 + y: u32, } #[abi(embed_v0)] @@ -96,7 +96,7 @@ pub mod MerkleTree { mut proof: Array, root: felt252, leaf: felt252, - mut index: usize + mut index: usize, ) -> bool { let mut current_hash = leaf; diff --git a/listings/applications/merkle_tree/src/tests.cairo b/listings/applications/merkle_tree/src/tests.cairo index 9188cea3..65904224 100644 --- a/listings/applications/merkle_tree/src/tests.cairo +++ b/listings/applications/merkle_tree/src/tests.cairo @@ -1,7 +1,7 @@ use merkle_tree::contract::IMerkleTreeDispatcherTrait; use merkle_tree::contract::{IMerkleTreeDispatcher, MerkleTree, ByteArrayHashTrait}; +use starknet::ContractAddress; use starknet::syscalls::deploy_syscall; -use starknet::{ContractAddress, SyscallResultTrait}; use starknet::testing::set_contract_address; use core::poseidon::PoseidonTrait; use core::hash::{HashStateTrait, HashStateExTrait}; @@ -9,7 +9,7 @@ use starknet::storage::{VecTrait, StoragePointerReadAccess}; fn deploy_util(class_hash: felt252, calldata: Array) -> ContractAddress { let (address, _) = deploy_syscall(class_hash.try_into().unwrap(), 0, calldata.span(), false) - .unwrap_syscall(); + .unwrap(); address } @@ -83,11 +83,9 @@ fn build_tree_succeeds() { assert_eq!(state.hashes.len(), expected_hashes.len().into()); - for i in 0 - ..expected_hashes - .len() { - assert_eq!(state.hashes.at(i.into()).read(), *expected_hashes.at(i)); - } + for i in 0..expected_hashes.len() { + assert_eq!(state.hashes.at(i.into()).read(), *expected_hashes.at(i)); + } } #[test] @@ -173,9 +171,9 @@ fn verify_leaf_fails() { let res = deploy .verify( wrong_proof, // proof - *hashes.at(6), // root - data_3.hash(), // leaf - 2 // leaf index + *hashes.at(6), // root + data_3.hash(), // leaf + 2 // leaf index ); assert(!res, '2- Leaf should NOT be in tree'); } diff --git a/listings/applications/nft_dutch_auction/src/erc721.cairo b/listings/applications/nft_dutch_auction/src/erc721.cairo index b18c6a05..3802a797 100644 --- a/listings/applications/nft_dutch_auction/src/erc721.cairo +++ b/listings/applications/nft_dutch_auction/src/erc721.cairo @@ -9,12 +9,12 @@ pub trait IERC721 { fn owner_of(self: @TContractState, token_id: u256) -> ContractAddress; fn get_approved(self: @TContractState, token_id: u256) -> ContractAddress; fn is_approved_for_all( - self: @TContractState, owner: ContractAddress, operator: ContractAddress + self: @TContractState, owner: ContractAddress, operator: ContractAddress, ) -> bool; fn approve(ref self: TContractState, to: ContractAddress, token_id: u256); fn set_approval_for_all(ref self: TContractState, operator: ContractAddress, approved: bool); fn transfer_from( - ref self: TContractState, from: ContractAddress, to: ContractAddress, token_id: u256 + ref self: TContractState, from: ContractAddress, to: ContractAddress, token_id: u256, ); fn mint(ref self: TContractState, to: ContractAddress, token_id: u256); } @@ -27,7 +27,7 @@ mod ERC721 { use starknet::{ContractAddress, get_caller_address}; use starknet::storage::{ Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess + StoragePointerWriteAccess, }; use core::num::traits::Zero; @@ -50,7 +50,7 @@ mod ERC721 { enum Event { Approval: Approval, Transfer: Transfer, - ApprovalForAll: ApprovalForAll + ApprovalForAll: ApprovalForAll, } //////////////////////////////// @@ -60,7 +60,7 @@ mod ERC721 { struct Approval { owner: ContractAddress, to: ContractAddress, - token_id: u256 + token_id: u256, } //////////////////////////////// @@ -70,7 +70,7 @@ mod ERC721 { struct Transfer { from: ContractAddress, to: ContractAddress, - token_id: u256 + token_id: u256, } //////////////////////////////// @@ -80,7 +80,7 @@ mod ERC721 { struct ApprovalForAll { owner: ContractAddress, operator: ContractAddress, - approved: bool + approved: bool, } @@ -145,7 +145,7 @@ mod ERC721 { // is_approved_for_all function returns approved operator for a token //////////////////////////////// fn is_approved_for_all( - self: @ContractState, owner: ContractAddress, operator: ContractAddress + self: @ContractState, owner: ContractAddress, operator: ContractAddress, ) -> bool { self.operator_approvals.read((owner, operator)) } @@ -159,7 +159,7 @@ mod ERC721 { assert( get_caller_address() == owner || self.is_approved_for_all(owner, get_caller_address()), - 'Not token owner' + 'Not token owner', ); self.token_approvals.write(token_id, to); self.emit(Approval { owner: self.owner_of(token_id), to: to, token_id: token_id }); @@ -169,7 +169,7 @@ mod ERC721 { // set_approval_for_all function approves an operator to spend all tokens //////////////////////////////// fn set_approval_for_all( - ref self: ContractState, operator: ContractAddress, approved: bool + ref self: ContractState, operator: ContractAddress, approved: bool, ) { let owner = get_caller_address(); assert(owner != operator, 'ERC721: approve to caller'); @@ -181,11 +181,11 @@ mod ERC721 { // transfer_from function is used to transfer a token //////////////////////////////// fn transfer_from( - ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256 + ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256, ) { assert( self._is_approved_or_owner(get_caller_address(), token_id), - 'neither owner nor approved' + 'neither owner nor approved', ); self._transfer(from, to, token_id); } @@ -209,7 +209,7 @@ mod ERC721 { // _is_approved_or_owner checks if an address is an approved spender or owner //////////////////////////////// fn _is_approved_or_owner( - self: @ContractState, spender: ContractAddress, token_id: u256 + self: @ContractState, spender: ContractAddress, token_id: u256, ) -> bool { let owner = self.owners.read(token_id); spender == owner @@ -229,7 +229,7 @@ mod ERC721 { // internal function that performs the transfer logic //////////////////////////////// fn _transfer( - ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256 + ref self: ContractState, from: ContractAddress, to: ContractAddress, token_id: u256, ) { // check that from address is equal to owner of token assert(from == self.owner_of(token_id), 'ERC721: Caller is not owner'); diff --git a/listings/applications/nft_dutch_auction/src/nft_dutch_auction.cairo b/listings/applications/nft_dutch_auction/src/nft_dutch_auction.cairo index dabf5c4c..48085039 100644 --- a/listings/applications/nft_dutch_auction/src/nft_dutch_auction.cairo +++ b/listings/applications/nft_dutch_auction/src/nft_dutch_auction.cairo @@ -9,19 +9,19 @@ pub trait IERC20 { fn get_total_supply(self: @TContractState) -> felt252; fn balance_of(self: @TContractState, account: ContractAddress) -> felt252; fn allowance( - self: @TContractState, owner: ContractAddress, spender: ContractAddress + self: @TContractState, owner: ContractAddress, spender: ContractAddress, ) -> felt252; fn transfer(ref self: TContractState, recipient: ContractAddress, amount: felt252); fn transfer_from( ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, - amount: felt252 + amount: felt252, ); fn approve(ref self: TContractState, spender: ContractAddress, amount: felt252); fn increase_allowance(ref self: TContractState, spender: ContractAddress, added_value: felt252); fn decrease_allowance( - ref self: TContractState, spender: ContractAddress, subtracted_value: felt252 + ref self: TContractState, spender: ContractAddress, subtracted_value: felt252, ); } @@ -34,12 +34,12 @@ trait IERC721 { fn owner_of(self: @TContractState, token_id: u256) -> ContractAddress; fn get_approved(self: @TContractState, token_id: u256) -> ContractAddress; fn is_approved_for_all( - self: @TContractState, owner: ContractAddress, operator: ContractAddress + self: @TContractState, owner: ContractAddress, operator: ContractAddress, ) -> bool; fn approve(ref self: TContractState, to: ContractAddress, token_id: u256); fn set_approval_for_all(ref self: TContractState, operator: ContractAddress, approved: bool); fn transfer_from( - ref self: TContractState, from: ContractAddress, to: ContractAddress, token_id: u256 + ref self: TContractState, from: ContractAddress, to: ContractAddress, token_id: u256, ); fn mint(ref self: TContractState, to: ContractAddress, token_id: u256); } @@ -67,7 +67,7 @@ pub mod NFTDutchAuction { start_at: u64, expires_at: u64, purchase_count: u128, - total_supply: u128 + total_supply: u128, } mod Errors { @@ -85,7 +85,7 @@ pub mod NFTDutchAuction { seller: ContractAddress, duration: u64, discount_rate: u64, - total_supply: u128 + total_supply: u128, ) { assert(starting_price >= discount_rate * duration, Errors::LOW_STARTING_PRICE); @@ -117,7 +117,7 @@ pub mod NFTDutchAuction { let erc20_dispatcher = IERC20Dispatcher { contract_address: self.erc20_token.read() }; let erc721_dispatcher = IERC721Dispatcher { - contract_address: self.erc721_token.read() + contract_address: self.erc721_token.read(), }; let caller = get_caller_address(); @@ -142,7 +142,7 @@ mod tests { use starknet::ContractAddress; use snforge_std::{ declare, DeclareResultTrait, ContractClassTrait, cheat_caller_address, CheatSpan, - cheat_block_timestamp + cheat_block_timestamp, }; use nft_dutch_auction::erc721::{IERC721Dispatcher, IERC721DispatcherTrait}; use super::{INFTDutchAuctionDispatcher, INFTDutchAuctionDispatcherTrait}; @@ -176,7 +176,7 @@ mod tests { erc20_name, erc20_decimals.into(), erc20_initial_supply.into(), - erc20_symbol + erc20_symbol, ]; let (erc20_address, _) = erc20.deploy(@erc20_constructor_calldata).unwrap(); let nft_auction = declare("NFTDutchAuction").unwrap().contract_class(); @@ -187,7 +187,7 @@ mod tests { seller, duration, discount_rate, - total_supply + total_supply, ]; let (nft_auction_address, _) = nft_auction .deploy(@nft_auction_constructor_calldata) @@ -201,7 +201,7 @@ mod tests { let erc721_dispatcher = IERC721Dispatcher { contract_address: erc721_address }; let erc20_dispatcher = IERC20Dispatcher { contract_address: erc20_address }; let nft_auction_dispatcher = INFTDutchAuctionDispatcher { - contract_address: nft_auction_address + contract_address: nft_auction_address, }; let erc20_admin: ContractAddress = 'admin'.try_into().unwrap(); let seller: ContractAddress = 'seller'.try_into().unwrap(); @@ -256,7 +256,7 @@ mod tests { let (_, erc20_address, nft_auction_address) = get_contract_addresses(); let erc20_dispatcher = IERC20Dispatcher { contract_address: erc20_address }; let nft_auction_dispatcher = INFTDutchAuctionDispatcher { - contract_address: nft_auction_address + contract_address: nft_auction_address, }; let erc20_admin: ContractAddress = 'admin'.try_into().unwrap(); let buyer: ContractAddress = 'buyer'.try_into().unwrap(); @@ -300,7 +300,7 @@ mod tests { let (_, erc20_address, nft_auction_address) = get_contract_addresses(); let erc20_dispatcher = IERC20Dispatcher { contract_address: erc20_address }; let nft_auction_dispatcher = INFTDutchAuctionDispatcher { - contract_address: nft_auction_address + contract_address: nft_auction_address, }; let erc20_admin: ContractAddress = 'admin'.try_into().unwrap(); let buyer: ContractAddress = 'buyer'.try_into().unwrap(); @@ -337,7 +337,7 @@ mod tests { fn test_price_decreases_after_some_time() { let (_, _, nft_auction_address) = get_contract_addresses(); let nft_auction_dispatcher = INFTDutchAuctionDispatcher { - contract_address: nft_auction_address + contract_address: nft_auction_address, }; let nft_price_before_time_travel = nft_auction_dispatcher.get_price(); diff --git a/listings/applications/simple_storage_starknetjs/src/storage.cairo b/listings/applications/simple_storage_starknetjs/src/storage.cairo index c7e71819..4a9a5f00 100644 --- a/listings/applications/simple_storage_starknetjs/src/storage.cairo +++ b/listings/applications/simple_storage_starknetjs/src/storage.cairo @@ -11,7 +11,7 @@ mod SimpleStorage { #[storage] struct Storage { - stored_data: u128 + stored_data: u128, } #[abi(embed_v0)] diff --git a/listings/applications/simple_vault/Scarb.toml b/listings/applications/simple_vault/Scarb.toml index d96a0664..a6d3ace3 100644 --- a/listings/applications/simple_vault/Scarb.toml +++ b/listings/applications/simple_vault/Scarb.toml @@ -14,3 +14,4 @@ cairo_test.workspace = true test.workspace = true [[target.starknet-contract]] +build-external-contracts = ["erc20::token::erc20"] diff --git a/listings/applications/simple_vault/src/lib.cairo b/listings/applications/simple_vault/src/lib.cairo index b08098a0..1745c06d 100644 --- a/listings/applications/simple_vault/src/lib.cairo +++ b/listings/applications/simple_vault/src/lib.cairo @@ -1,4 +1 @@ mod simple_vault; - -#[cfg(test)] -mod tests; diff --git a/listings/applications/simple_vault/src/simple_vault.cairo b/listings/applications/simple_vault/src/simple_vault.cairo index c528f281..8ae7d074 100644 --- a/listings/applications/simple_vault/src/simple_vault.cairo +++ b/listings/applications/simple_vault/src/simple_vault.cairo @@ -11,19 +11,19 @@ pub trait IERC20 { fn get_total_supply(self: @TContractState) -> felt252; fn balance_of(self: @TContractState, account: ContractAddress) -> felt252; fn allowance( - self: @TContractState, owner: ContractAddress, spender: ContractAddress + self: @TContractState, owner: ContractAddress, spender: ContractAddress, ) -> felt252; fn transfer(ref self: TContractState, recipient: ContractAddress, amount: felt252); fn transfer_from( ref self: TContractState, sender: ContractAddress, recipient: ContractAddress, - amount: felt252 + amount: felt252, ); fn approve(ref self: TContractState, spender: ContractAddress, amount: felt252); fn increase_allowance(ref self: TContractState, spender: ContractAddress, added_value: felt252); fn decrease_allowance( - ref self: TContractState, spender: ContractAddress, subtracted_value: felt252 + ref self: TContractState, spender: ContractAddress, subtracted_value: felt252, ); } @@ -41,14 +41,14 @@ pub mod SimpleVault { use starknet::{ContractAddress, get_caller_address, get_contract_address}; use starknet::storage::{ Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess + StoragePointerWriteAccess, }; #[storage] struct Storage { token: IERC20Dispatcher, total_supply: u256, - balance_of: Map + balance_of: Map, } #[constructor] @@ -127,17 +127,16 @@ pub mod SimpleVault { } // [!endregion contract] +// TODO migrate to sn-foundry #[cfg(test)] mod tests { - use super::{SimpleVault, ISimpleVaultDispatcher, ISimpleVaultDispatcherTrait,}; + use super::{SimpleVault, ISimpleVaultDispatcher, ISimpleVaultDispatcherTrait}; use erc20::token::{ IERC20DispatcherTrait as IERC20DispatcherTrait_token, - IERC20Dispatcher as IERC20Dispatcher_token + IERC20Dispatcher as IERC20Dispatcher_token, }; use starknet::testing::{set_contract_address, set_account_contract_address}; - use starknet::{ - ContractAddress, SyscallResultTrait, syscalls::deploy_syscall, contract_address_const - }; + use starknet::{ContractAddress, syscalls::deploy_syscall, contract_address_const}; const token_name: felt252 = 'myToken'; const decimals: u8 = 18; @@ -151,23 +150,23 @@ mod tests { let (token_contract_address, _) = deploy_syscall( erc20::token::erc20::TEST_CLASS_HASH.try_into().unwrap(), caller.into(), - array![caller.into(), 'myToken', '8', '1000'.into(), 'MYT'].span(), - false + array![caller.into(), token_name, decimals.into(), initial_supply, symbols].span(), + false, ) - .unwrap_syscall(); + .expect('1'); let (contract_address, _) = deploy_syscall( SimpleVault::TEST_CLASS_HASH.try_into().unwrap(), 0, array![token_contract_address.into()].span(), - false + false, ) - .unwrap_syscall(); + .expect('2'); ( ISimpleVaultDispatcher { contract_address }, contract_address, - IERC20Dispatcher_token { contract_address: token_contract_address } + IERC20Dispatcher_token { contract_address: token_contract_address }, ) } diff --git a/listings/applications/simple_vault/src/tests.cairo b/listings/applications/simple_vault/src/tests.cairo deleted file mode 100644 index 361dba07..00000000 --- a/listings/applications/simple_vault/src/tests.cairo +++ /dev/null @@ -1,2 +0,0 @@ -mod tests { // TODO -} diff --git a/listings/applications/staking/src/contract.cairo b/listings/applications/staking/src/contract.cairo index 5980b2c0..7cebd961 100644 --- a/listings/applications/staking/src/contract.cairo +++ b/listings/applications/staking/src/contract.cairo @@ -28,7 +28,7 @@ pub mod StakingContract { use openzeppelin::token::erc20::interface::{IERC20Dispatcher, IERC20DispatcherTrait}; use starknet::storage::{ Map, StorageMapReadAccess, StorageMapWriteAccess, StoragePointerReadAccess, - StoragePointerWriteAccess + StoragePointerWriteAccess, }; #[storage] @@ -98,7 +98,7 @@ pub mod StakingContract { // can only set duration if the previous duration has already finished assert( self.finish_at.read() < get_block_timestamp().into(), - super::Errors::UNFINISHED_DURATION + super::Errors::UNFINISHED_DURATION, ); self.duration.write(duration); @@ -124,7 +124,7 @@ pub mod StakingContract { assert( self.reward_token.read().balance_of(get_contract_address()) >= rate * self.duration.read(), - super::Errors::NOT_ENOUGH_REWARDS + super::Errors::NOT_ENOUGH_REWARDS, ); self.reward_rate.write(rate); @@ -158,7 +158,7 @@ pub mod StakingContract { assert( self.staking_token.read().balance_of(user) >= amount, - super::Errors::NOT_ENOUGH_BALANCE + super::Errors::NOT_ENOUGH_BALANCE, ); self.update_rewards(user); diff --git a/listings/applications/staking/src/tests/staking_tests.cairo b/listings/applications/staking/src/tests/staking_tests.cairo index d899b876..50d95f5e 100644 --- a/listings/applications/staking/src/tests/staking_tests.cairo +++ b/listings/applications/staking/src/tests/staking_tests.cairo @@ -5,11 +5,10 @@ mod tests { use staking::tests::tokens::{RewardToken, StakingToken}; use staking::contract::{ StakingContract, IStakingContractDispatcher, StakingContract::Event, - StakingContract::Deposit, StakingContract::Withdrawal, StakingContract::RewardsFinished + StakingContract::Deposit, StakingContract::Withdrawal, StakingContract::RewardsFinished, }; use openzeppelin::token::erc20::{interface::IERC20Dispatcher}; use starknet::syscalls::deploy_syscall; - use starknet::SyscallResultTrait; use core::serde::Serde; use starknet::testing::{set_contract_address, set_block_timestamp, pop_log}; use starknet::{contract_address_const, ContractAddress}; @@ -19,18 +18,18 @@ mod tests { struct Deployment { contract: IStakingContractDispatcher, staking_token: IERC20Dispatcher, - reward_token: IERC20Dispatcher + reward_token: IERC20Dispatcher, } fn deploy_util(class_hash: felt252, calldata: Array) -> ContractAddress { let (address, _) = deploy_syscall(class_hash.try_into().unwrap(), 0, calldata.span(), false) - .unwrap_syscall(); + .unwrap(); address } fn deploy_erc20( - class_hash: felt252, name: ByteArray, symbol: ByteArray + class_hash: felt252, name: ByteArray, symbol: ByteArray, ) -> (ContractAddress, IERC20Dispatcher) { let supply: u256 = 1000000; let recipient = contract_address_const::<'recipient'>(); @@ -46,7 +45,7 @@ mod tests { } fn deploy_staking_contract( - staking_token_address: ContractAddress, reward_token_address: ContractAddress + staking_token_address: ContractAddress, reward_token_address: ContractAddress, ) -> (ContractAddress, IStakingContractDispatcher) { let mut calldata: Array = array![]; calldata.append(staking_token_address.into()); @@ -55,7 +54,7 @@ mod tests { let staking_contract_address = deploy_util(StakingContract::TEST_CLASS_HASH, calldata); ( staking_contract_address, - IStakingContractDispatcher { contract_address: staking_contract_address } + IStakingContractDispatcher { contract_address: staking_contract_address }, ) } @@ -68,14 +67,14 @@ mod tests { ); let (_, staking_contract) = deploy_staking_contract( - staking_token_address, reward_token_address + staking_token_address, reward_token_address, ); Deployment { contract: staking_contract, staking_token, reward_token } } fn mint_and_approve_staking_tokens_to( - recipient: ContractAddress, amount: u256, deploy: Deployment, value_to_approve: u256 + recipient: ContractAddress, amount: u256, deploy: Deployment, value_to_approve: u256, ) { // mint tokens let mut state = StakingToken::contract_state_for_testing(); @@ -89,7 +88,7 @@ mod tests { } fn mint_reward_tokens_to( - deployed_contract: ContractAddress, amount: u256, reward_token_address: ContractAddress + deployed_contract: ContractAddress, amount: u256, reward_token_address: ContractAddress, ) { // mint tokens let mut state = RewardToken::contract_state_for_testing(); @@ -116,10 +115,10 @@ mod tests { /// then assert_eq!(state.owner.read(), owner); assert_eq!( - state.staking_token.read().contract_address, deploy.staking_token.contract_address + state.staking_token.read().contract_address, deploy.staking_token.contract_address, ); assert_eq!( - state.reward_token.read().contract_address, deploy.reward_token.contract_address + state.reward_token.read().contract_address, deploy.reward_token.contract_address, ); } @@ -153,11 +152,11 @@ mod tests { // check 1st & 2nd event - when user stakes assert_eq!( pop_log(deploy.contract.contract_address), - Option::Some(Event::RewardsFinished(RewardsFinished { msg: 'Rewards not active yet' })) + Option::Some(Event::RewardsFinished(RewardsFinished { msg: 'Rewards not active yet' })), ); assert_eq!( pop_log(deploy.contract.contract_address), - Option::Some(Event::Deposit(Deposit { user, amount: stake_amount })) + Option::Some(Event::Deposit(Deposit { user, amount: stake_amount })), ); /// when - withdrawal @@ -173,17 +172,17 @@ mod tests { assert_eq!(state.total_supply.read(), stake_amount - withdrawal_amount); assert_eq!( deploy.staking_token.balance_of(user), - amount_tokens_minted - stake_amount + withdrawal_amount + amount_tokens_minted - stake_amount + withdrawal_amount, ); // check 3rd & 4th events - when user withdraws assert_eq!( pop_log(deploy.contract.contract_address), - Option::Some(Event::RewardsFinished(RewardsFinished { msg: 'Rewards not active yet' })) + Option::Some(Event::RewardsFinished(RewardsFinished { msg: 'Rewards not active yet' })), ); assert_eq!( pop_log(deploy.contract.contract_address), - Option::Some(Event::Withdrawal(Withdrawal { user, amount: withdrawal_amount })) + Option::Some(Event::Withdrawal(Withdrawal { user, amount: withdrawal_amount })), ); } @@ -201,7 +200,7 @@ mod tests { mint_reward_tokens_to( deploy.contract.contract_address, reward_tokens_amount, - deploy.reward_token.contract_address + deploy.reward_token.contract_address, ); // owner sets up rewards duration and amount @@ -226,7 +225,7 @@ mod tests { let alice_stake_amount = 40; let alice_amount_tokens_minted = 100; mint_and_approve_staking_tokens_to( - alice, alice_amount_tokens_minted, deploy, alice_stake_amount + alice, alice_amount_tokens_minted, deploy, alice_stake_amount, ); // alice stakes @@ -262,7 +261,7 @@ mod tests { let john_stake_amount = 30; let john_amount_tokens_minted = 100; mint_and_approve_staking_tokens_to( - john, john_amount_tokens_minted, deploy, john_stake_amount + john, john_amount_tokens_minted, deploy, john_stake_amount, ); // john stakes @@ -327,7 +326,7 @@ mod tests { // timestamp after the duration is finished set_block_timestamp( - block_timestamp.try_into().unwrap() + reward_duration.try_into().unwrap() + 10 + block_timestamp.try_into().unwrap() + reward_duration.try_into().unwrap() + 10, ); // alice claims @@ -405,7 +404,7 @@ mod tests { mint_reward_tokens_to( deploy.contract.contract_address, reward_tokens_amount, - deploy.reward_token.contract_address + deploy.reward_token.contract_address, ); // owner sets up rewards duration and amount @@ -429,7 +428,7 @@ mod tests { // alice claims her rewards after the duration is over set_block_timestamp( - block_timestamp.try_into().unwrap() + reward_duration.try_into().unwrap() + block_timestamp.try_into().unwrap() + reward_duration.try_into().unwrap(), ); deploy.contract.claim_rewards(); @@ -449,21 +448,25 @@ mod tests { // check 1st event - when alice stakes assert_eq!( pop_log(deploy.contract.contract_address), - Option::Some(Event::Deposit(Deposit { user: alice, amount: alice_stake_amount })) + Option::Some(Event::Deposit(Deposit { user: alice, amount: alice_stake_amount })), ); // check 2nd event - when alice claims assert_eq!( pop_log(deploy.contract.contract_address), - Option::Some(Event::RewardsFinished(RewardsFinished { msg: 'Rewards all distributed' })) + Option::Some( + Event::RewardsFinished(RewardsFinished { msg: 'Rewards all distributed' }), + ), ); // check 3rd & 4th events - when bob stakes assert_eq!( pop_log(deploy.contract.contract_address), - Option::Some(Event::RewardsFinished(RewardsFinished { msg: 'Rewards all distributed' })) + Option::Some( + Event::RewardsFinished(RewardsFinished { msg: 'Rewards all distributed' }), + ), ); assert_eq!( pop_log(deploy.contract.contract_address), - Option::Some(Event::Deposit(Deposit { user: bob, amount: bob_stake_amount })) + Option::Some(Event::Deposit(Deposit { user: bob, amount: bob_stake_amount })), ); } @@ -481,7 +484,7 @@ mod tests { mint_reward_tokens_to( deploy.contract.contract_address, reward_tokens_amount, - deploy.reward_token.contract_address + deploy.reward_token.contract_address, ); // owner sets up rewards duration and amount diff --git a/listings/applications/staking/src/tests/tokens.cairo b/listings/applications/staking/src/tests/tokens.cairo index 0b0148c6..89e1a4bd 100644 --- a/listings/applications/staking/src/tests/tokens.cairo +++ b/listings/applications/staking/src/tests/tokens.cairo @@ -28,7 +28,7 @@ pub mod RewardToken { name: ByteArray, symbol: ByteArray, initial_supply: u256, - recipient: ContractAddress + recipient: ContractAddress, ) { self.erc20.initializer(name, symbol); self.erc20.mint(recipient, initial_supply); @@ -65,7 +65,7 @@ pub mod StakingToken { name: ByteArray, symbol: ByteArray, initial_supply: u256, - recipient: ContractAddress + recipient: ContractAddress, ) { self.erc20.initializer(name, symbol); self.erc20.mint(recipient, initial_supply); diff --git a/listings/applications/timelock/src/erc721.cairo b/listings/applications/timelock/src/erc721.cairo index fddeda94..36ae6448 100644 --- a/listings/applications/timelock/src/erc721.cairo +++ b/listings/applications/timelock/src/erc721.cairo @@ -36,7 +36,7 @@ pub mod ERC721 { symbol: ByteArray, base_uri: ByteArray, recipient: ContractAddress, - token_id: u256 + token_id: u256, ) { self.erc721.initializer(name, symbol, base_uri); self.erc721.mint(recipient, token_id); diff --git a/listings/applications/timelock/src/tests/timelock.cairo b/listings/applications/timelock/src/tests/timelock.cairo index dd0c98da..bfc1893e 100644 --- a/listings/applications/timelock/src/tests/timelock.cairo +++ b/listings/applications/timelock/src/tests/timelock.cairo @@ -3,7 +3,7 @@ use starknet::account::Call; use core::poseidon::{PoseidonTrait, poseidon_hash_span}; use core::hash::HashStateTrait; use snforge_std::{ - cheat_caller_address, cheat_block_timestamp, CheatSpan, spy_events, EventSpyAssertionsTrait + cheat_caller_address, cheat_block_timestamp, CheatSpan, spy_events, EventSpyAssertionsTrait, }; use openzeppelin::token::erc721::interface::IERC721DispatcherTrait; use openzeppelin::token::erc721::erc721::ERC721Component; @@ -34,7 +34,9 @@ fn test_queue_only_owner() { .timelock_safe .queue(timelock_test.get_call(), timelock_test.get_timestamp()) { Result::Ok(_) => panic_with_felt252('FAIL'), - Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), ownable::Errors::UNAUTHORIZED); } + Result::Err(panic_data) => { + assert_eq!(*panic_data.at(0), ownable::Errors::UNAUTHORIZED); + }, } } @@ -47,7 +49,7 @@ fn test_queue_already_queued() { Result::Ok(_) => panic_with_felt252('FAIL'), Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), TimeLock::Errors::ALREADY_QUEUED); - } + }, } } @@ -58,7 +60,7 @@ fn test_queue_timestamp_not_in_range() { Result::Ok(_) => panic_with_felt252('FAIL'), Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), TimeLock::Errors::TIMESTAMP_NOT_IN_RANGE); - } + }, } match timelock_test .timelock_safe @@ -66,7 +68,7 @@ fn test_queue_timestamp_not_in_range() { Result::Ok(_) => panic_with_felt252('FAIL'), Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), TimeLock::Errors::TIMESTAMP_NOT_IN_RANGE); - } + }, } } @@ -82,10 +84,10 @@ fn test_queue_success() { ( timelock_test.timelock_address, TimeLock::Event::Queue( - TimeLock::Queue { tx_id, call: timelock_test.get_call(), timestamp } - ) - ) - ] + TimeLock::Queue { tx_id, call: timelock_test.get_call(), timestamp }, + ), + ), + ], ); assert_eq!(tx_id, timelock_test.timelock.get_tx_id(timelock_test.get_call(), timestamp)); } @@ -98,7 +100,9 @@ fn test_execute_only_owner() { .timelock_safe .execute(timelock_test.get_call(), timelock_test.get_timestamp()) { Result::Ok(_) => panic_with_felt252('FAIL'), - Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), ownable::Errors::UNAUTHORIZED); } + Result::Err(panic_data) => { + assert_eq!(*panic_data.at(0), ownable::Errors::UNAUTHORIZED); + }, } } @@ -109,7 +113,7 @@ fn test_execute_not_queued() { .timelock_safe .execute(timelock_test.get_call(), timelock_test.get_timestamp()) { Result::Ok(_) => panic_with_felt252('FAIL'), - Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), TimeLock::Errors::NOT_QUEUED); } + Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), TimeLock::Errors::NOT_QUEUED); }, } } @@ -122,7 +126,7 @@ fn test_execute_timestamp_not_passed() { Result::Ok(_) => panic_with_felt252('FAIL'), Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), TimeLock::Errors::TIMESTAMP_NOT_PASSED); - } + }, } } @@ -134,13 +138,13 @@ fn test_execute_timestamp_expired() { cheat_block_timestamp( timelock_test.timelock_address, timestamp + TimeLock::GRACE_PERIOD + 1, - CheatSpan::TargetCalls(1) + CheatSpan::TargetCalls(1), ); match timelock_test.timelock_safe.execute(timelock_test.get_call(), timestamp) { Result::Ok(_) => panic_with_felt252('FAIL'), Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), TimeLock::Errors::TIMESTAMP_EXPIRED); - } + }, } } @@ -160,10 +164,10 @@ fn test_execute_success() { ( timelock_test.timelock_address, TimeLock::Event::Execute( - TimeLock::Execute { tx_id, call: timelock_test.get_call(), timestamp } - ) - ) - ] + TimeLock::Execute { tx_id, call: timelock_test.get_call(), timestamp }, + ), + ), + ], ); } @@ -177,7 +181,7 @@ fn test_execute_failed() { Result::Ok(_) => panic_with_felt252('FAIL'), Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), ERC721Component::Errors::UNAUTHORIZED); - } + }, } } @@ -190,7 +194,9 @@ fn test_cancel_only_owner() { cheat_caller_address(timelock_test.timelock_address, OTHER(), CheatSpan::TargetCalls(1)); match timelock_test.timelock_safe.cancel(tx_id) { Result::Ok(_) => panic_with_felt252('FAIL'), - Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), ownable::Errors::UNAUTHORIZED); } + Result::Err(panic_data) => { + assert_eq!(*panic_data.at(0), ownable::Errors::UNAUTHORIZED); + }, } } @@ -202,7 +208,7 @@ fn test_cancel_not_queued() { .get_tx_id(timelock_test.get_call(), timelock_test.get_timestamp()); match timelock_test.timelock_safe.cancel(tx_id) { Result::Ok(_) => panic_with_felt252('FAIL'), - Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), TimeLock::Errors::NOT_QUEUED); } + Result::Err(panic_data) => { assert_eq!(*panic_data.at(0), TimeLock::Errors::NOT_QUEUED); }, } } @@ -219,8 +225,8 @@ fn test_cancel_success() { @array![ ( timelock_test.timelock_address, - TimeLock::Event::Cancel(TimeLock::Cancel { tx_id }) - ) - ] + TimeLock::Event::Cancel(TimeLock::Cancel { tx_id }), + ), + ], ); } diff --git a/listings/applications/timelock/src/tests/utils.cairo b/listings/applications/timelock/src/tests/utils.cairo index 32973908..f380b445 100644 --- a/listings/applications/timelock/src/tests/utils.cairo +++ b/listings/applications/timelock/src/tests/utils.cairo @@ -59,7 +59,7 @@ pub impl TimeLockTestImpl of TimeLockTestTrait { Call { to: *self.erc721_address, selector: selector!("transfer_from"), - calldata: calldata.span() + calldata: calldata.span(), } } fn get_timestamp(self: @TimeLockTest) -> u64 { diff --git a/listings/applications/timelock/src/timelock.cairo b/listings/applications/timelock/src/timelock.cairo index 38e42ed9..e6540d56 100644 --- a/listings/applications/timelock/src/timelock.cairo +++ b/listings/applications/timelock/src/timelock.cairo @@ -12,7 +12,7 @@ pub trait ITimeLock { pub mod TimeLock { use core::poseidon::{PoseidonTrait, poseidon_hash_span}; use core::hash::HashStateTrait; - use starknet::{get_caller_address, get_block_timestamp, SyscallResultTrait, syscalls}; + use starknet::{get_caller_address, get_block_timestamp, syscalls}; use starknet::account::Call; use components::ownable::ownable_component; use starknet::storage::{Map, StorageMapReadAccess, StorageMapWriteAccess}; @@ -38,7 +38,7 @@ pub mod TimeLock { OwnableEvent: ownable_component::Event, Queue: Queue, Execute: Execute, - Cancel: Cancel + Cancel: Cancel, } #[derive(Drop, starknet::Event)] @@ -46,7 +46,7 @@ pub mod TimeLock { #[key] pub tx_id: felt252, pub call: Call, - pub timestamp: u64 + pub timestamp: u64, } #[derive(Drop, starknet::Event)] @@ -54,13 +54,13 @@ pub mod TimeLock { #[key] pub tx_id: felt252, pub call: Call, - pub timestamp: u64 + pub timestamp: u64, } #[derive(Drop, starknet::Event)] pub struct Cancel { #[key] - pub tx_id: felt252 + pub tx_id: felt252, } pub const MIN_DELAY: u64 = 10; // seconds @@ -103,7 +103,7 @@ pub mod TimeLock { timestamp >= block_timestamp + MIN_DELAY && timestamp <= block_timestamp + MAX_DELAY, - Errors::TIMESTAMP_NOT_IN_RANGE + Errors::TIMESTAMP_NOT_IN_RANGE, ); self.queued.write(tx_id, true); @@ -126,7 +126,7 @@ pub mod TimeLock { self.queued.write(tx_id, false); let result = syscalls::call_contract_syscall(call.to, call.selector, call.calldata) - .unwrap_syscall(); + .unwrap(); self.emit(Execute { tx_id, call: self._copy_call(@call), timestamp }); diff --git a/listings/applications/upgradeable_contract/src/tests.cairo b/listings/applications/upgradeable_contract/src/tests.cairo index a3ff7ba0..fe9f11a6 100644 --- a/listings/applications/upgradeable_contract/src/tests.cairo +++ b/listings/applications/upgradeable_contract/src/tests.cairo @@ -4,18 +4,17 @@ mod tests { use super::super::upgradeable_contract_v0::{ UpgradeableContract_V0, IUpgradeableContractDispatcher as IUpgradeableContractDispatcher_v0, IUpgradeableContractDispatcherTrait as UpgradeableContractDispatcherTrait_v0, - UpgradeableContract_V0::{Event, Upgraded} + UpgradeableContract_V0::{Event, Upgraded}, }; use super::super::upgradeable_contract_v1::{ UpgradeableContract_V1, IUpgradeableContractDispatcher as IUpgradeableContractDispatcher_v1, - IUpgradeableContractDispatcherTrait as UpgradeableContractDispatcherTrait_v1 + IUpgradeableContractDispatcherTrait as UpgradeableContractDispatcherTrait_v1, }; use starknet::{ - ContractAddress, SyscallResultTrait, syscalls::deploy_syscall, get_caller_address, - contract_address_const + ContractAddress, syscalls::deploy_syscall, get_caller_address, contract_address_const, }; use core::num::traits::Zero; @@ -24,26 +23,26 @@ mod tests { // deploy v0 contract fn deploy_v0() -> (IUpgradeableContractDispatcher_v0, ContractAddress, ClassHash) { let (contract_address, _) = deploy_syscall( - UpgradeableContract_V0::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + UpgradeableContract_V0::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); ( IUpgradeableContractDispatcher_v0 { contract_address }, contract_address, - UpgradeableContract_V0::TEST_CLASS_HASH.try_into().unwrap() + UpgradeableContract_V0::TEST_CLASS_HASH.try_into().unwrap(), ) } // deploy v1 contract fn deploy_v1() -> (IUpgradeableContractDispatcher_v1, ContractAddress, ClassHash) { let (contract_address, _) = deploy_syscall( - UpgradeableContract_V1::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + UpgradeableContract_V1::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); ( IUpgradeableContractDispatcher_v1 { contract_address }, contract_address, - UpgradeableContract_V1::TEST_CLASS_HASH.try_into().unwrap() + UpgradeableContract_V1::TEST_CLASS_HASH.try_into().unwrap(), ) } @@ -78,7 +77,7 @@ mod tests { // emit event assert_eq!( starknet::testing::pop_log(contract_address), - Option::Some(Event::Upgraded(Upgraded { implementation: class_hash })) + Option::Some(Event::Upgraded(Upgraded { implementation: class_hash })), ); assert(dispatcher_v0.version() == 1, ' version did not upgrade'); diff --git a/listings/applications/upgradeable_contract/src/upgradeable_contract_v0.cairo b/listings/applications/upgradeable_contract/src/upgradeable_contract_v0.cairo index e8d912ba..571ec785 100644 --- a/listings/applications/upgradeable_contract/src/upgradeable_contract_v0.cairo +++ b/listings/applications/upgradeable_contract/src/upgradeable_contract_v0.cairo @@ -10,7 +10,6 @@ pub trait IUpgradeableContract { #[starknet::contract] pub mod UpgradeableContract_V0 { use starknet::class_hash::ClassHash; - use starknet::SyscallResultTrait; use core::num::traits::Zero; #[storage] @@ -24,7 +23,7 @@ pub mod UpgradeableContract_V0 { #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] pub struct Upgraded { - pub implementation: ClassHash + pub implementation: ClassHash, } #[abi(embed_v0)] @@ -32,7 +31,7 @@ pub mod UpgradeableContract_V0 { // [!region upgrade] fn upgrade(ref self: ContractState, impl_hash: ClassHash) { assert(impl_hash.is_non_zero(), 'Class hash cannot be zero'); - starknet::syscalls::replace_class_syscall(impl_hash).unwrap_syscall(); + starknet::syscalls::replace_class_syscall(impl_hash).unwrap(); self.emit(Event::Upgraded(Upgraded { implementation: impl_hash })) } // [!endregion upgrade] diff --git a/listings/applications/upgradeable_contract/src/upgradeable_contract_v1.cairo b/listings/applications/upgradeable_contract/src/upgradeable_contract_v1.cairo index 78baa8b1..052b4cbf 100644 --- a/listings/applications/upgradeable_contract/src/upgradeable_contract_v1.cairo +++ b/listings/applications/upgradeable_contract/src/upgradeable_contract_v1.cairo @@ -9,7 +9,6 @@ pub trait IUpgradeableContract { #[starknet::contract] pub mod UpgradeableContract_V1 { use starknet::class_hash::ClassHash; - use starknet::SyscallResultTrait; use core::num::traits::Zero; #[storage] @@ -18,19 +17,19 @@ pub mod UpgradeableContract_V1 { #[event] #[derive(Drop, starknet::Event)] enum Event { - Upgraded: Upgraded + Upgraded: Upgraded, } #[derive(Drop, starknet::Event)] struct Upgraded { - implementation: ClassHash + implementation: ClassHash, } #[abi(embed_v0)] impl UpgradeableContract of super::IUpgradeableContract { fn upgrade(ref self: ContractState, impl_hash: ClassHash) { assert(impl_hash.is_non_zero(), 'Class hash cannot be zero'); - starknet::syscalls::replace_class_syscall(impl_hash).unwrap_syscall(); + starknet::syscalls::replace_class_syscall(impl_hash).unwrap(); self.emit(Event::Upgraded(Upgraded { implementation: impl_hash })) } diff --git a/listings/cairo_cheatsheet/Scarb.toml b/listings/cairo_cheatsheet/Scarb.toml index 4daa2a61..5cf958bf 100644 --- a/listings/cairo_cheatsheet/Scarb.toml +++ b/listings/cairo_cheatsheet/Scarb.toml @@ -13,4 +13,3 @@ cairo_test.workspace = true test.workspace = true [[target.starknet-contract]] -allowed-libfuncs-list.name = "experimental" diff --git a/listings/cairo_cheatsheet/src/enum_example.cairo b/listings/cairo_cheatsheet/src/enum_example.cairo index 32ea6800..a6d94c69 100644 --- a/listings/cairo_cheatsheet/src/enum_example.cairo +++ b/listings/cairo_cheatsheet/src/enum_example.cairo @@ -7,6 +7,7 @@ struct Position { #[derive(Drop, Serde, Copy, starknet::Store)] enum UserCommand { + #[default] Login, UpdateProfile, Logout, @@ -14,11 +15,12 @@ enum UserCommand { #[derive(Drop, Serde, Copy, starknet::Store)] enum Action { + #[default] Quit, Move: Position, SendMessage: felt252, ChangeAvatarColor: (u8, u8, u8), - ProfileState: UserCommand + ProfileState: UserCommand, } // [!endregion enums] @@ -45,20 +47,20 @@ mod EnumContract { fn register_action(ref self: ContractState, action: Action) { // quick note: match takes ownership of variable (but enum Action implements Copy trait) match action { - Action::Quit => { println!("Quit"); }, - Action::Move(value) => { println!("Move with x: {} and y: {}", value.x, value.y); }, - Action::SendMessage(msg) => { println!("Write with message: {}", msg); }, + Action::Quit => "Quit", + Action::Move(value) => format!("Move with x: {} and y: {}", value.x, value.y), + Action::SendMessage(msg) => format!("Write with message: {}", msg), Action::ChangeAvatarColor(( - r, g, b - )) => { println!("Change color to r: {}, g: {}, b: {}", r, g, b); }, + r, g, b, + )) => format!("Change color to r: {}, g: {}, b: {}", r, g, b), Action::ProfileState(state) => { let profile_state = match state { UserCommand::Login => 1, UserCommand::UpdateProfile => 2, UserCommand::Logout => 3, }; - println!("profile_state: {}", profile_state); - } + format!("profile_state: {}", profile_state) + }, }; self.most_recent_action.write(action); diff --git a/listings/cairo_cheatsheet/src/if_let_example.cairo b/listings/cairo_cheatsheet/src/if_let_example.cairo index 5fd56033..329157d3 100644 --- a/listings/cairo_cheatsheet/src/if_let_example.cairo +++ b/listings/cairo_cheatsheet/src/if_let_example.cairo @@ -13,15 +13,15 @@ fn if_let() { // "if `let` destructures `number` into `Some(i)`: // evaluate the block (`{}`). if let Option::Some(i) = number { - println!("Matched {}", i); + format!("Matched {}", i); } // If you need to specify a failure, use an else: if let Option::Some(i) = letter { - println!("Matched {}", i); + format!("Matched {}", i); } else { // Destructure failed. Change to the failure case. - println!("Didn't match a number."); + format!("Didn't match a number."); } // Using `if let` with enum @@ -31,19 +31,19 @@ fn if_let() { // Variable a matches Foo::Bar if let Foo::Bar = a { - println!("a is foobar"); + format!("a is foobar"); } // Variable b does not match Foo::Bar // So this will print nothing if let Foo::Bar = b { - println!("b is foobar"); + format!("b is foobar"); } // Variable c matches Foo::Qux which has a value // Similar to Some() in the previous example if let Foo::Qux(value) = c { - println!("c is {}", value); + format!("c is {}", value); } } // [!endregion sheet] diff --git a/listings/cairo_cheatsheet/src/mapping_example.cairo b/listings/cairo_cheatsheet/src/mapping_example.cairo index 176a2240..6befd79c 100644 --- a/listings/cairo_cheatsheet/src/mapping_example.cairo +++ b/listings/cairo_cheatsheet/src/mapping_example.cairo @@ -4,11 +4,11 @@ use starknet::ContractAddress; trait IMappingExample { fn register_user(ref self: TContractState, student_add: ContractAddress, studentName: felt252); fn record_student_score( - ref self: TContractState, student_add: ContractAddress, subject: felt252, score: u16 + ref self: TContractState, student_add: ContractAddress, subject: felt252, score: u16, ); fn view_student_name(self: @TContractState, student_add: ContractAddress) -> felt252; fn view_student_score( - self: @TContractState, student_add: ContractAddress, subject: felt252 + self: @TContractState, student_add: ContractAddress, subject: felt252, ) -> u16; } @@ -26,13 +26,13 @@ mod MappingContract { #[abi(embed_v0)] impl External of super::IMappingExample { fn register_user( - ref self: ContractState, student_add: ContractAddress, studentName: felt252 + ref self: ContractState, student_add: ContractAddress, studentName: felt252, ) { self.students_name.write(student_add, studentName); } fn record_student_score( - ref self: ContractState, student_add: ContractAddress, subject: felt252, score: u16 + ref self: ContractState, student_add: ContractAddress, subject: felt252, score: u16, ) { self.students_result_record.write((student_add, subject), score); } @@ -42,7 +42,7 @@ mod MappingContract { } fn view_student_score( - self: @ContractState, student_add: ContractAddress, subject: felt252 + self: @ContractState, student_add: ContractAddress, subject: felt252, ) -> u16 { // for a 2D mapping its important to take note of the amount of brackets being used. self.students_result_record.read((student_add, subject)) diff --git a/listings/cairo_cheatsheet/src/match_example.cairo b/listings/cairo_cheatsheet/src/match_example.cairo index f32d2df1..3273ea19 100644 --- a/listings/cairo_cheatsheet/src/match_example.cairo +++ b/listings/cairo_cheatsheet/src/match_example.cairo @@ -4,7 +4,7 @@ enum Colour { Blue, Green, Orange, - Black + Black, } #[derive(Drop, Serde)] diff --git a/listings/cairo_cheatsheet/src/struct_example.cairo b/listings/cairo_cheatsheet/src/struct_example.cairo index 7601e0e1..55b7f227 100644 --- a/listings/cairo_cheatsheet/src/struct_example.cairo +++ b/listings/cairo_cheatsheet/src/struct_example.cairo @@ -2,5 +2,5 @@ #[derive(Drop, starknet::Store)] struct Data { address: starknet::ContractAddress, - age: u8 + age: u8, } diff --git a/listings/cairo_cheatsheet/src/while_let_example.cairo b/listings/cairo_cheatsheet/src/while_let_example.cairo index 54b5e7b1..56d6aad5 100644 --- a/listings/cairo_cheatsheet/src/while_let_example.cairo +++ b/listings/cairo_cheatsheet/src/while_let_example.cairo @@ -6,10 +6,8 @@ fn while_let() { // evaluate the block (`{}`), else `break` while let Option::Some(i) = option { if i > 0 { - println!("Greater than 0, break..."); option = Option::None; } else { - println!("`i` is `{:?}`. Try again.", i); option = Option::Some(i + 1); } } diff --git a/listings/getting-started/bytearray/src/bytearray.cairo b/listings/getting-started/bytearray/src/bytearray.cairo index d6d10be9..03911b70 100644 --- a/listings/getting-started/bytearray/src/bytearray.cairo +++ b/listings/getting-started/bytearray/src/bytearray.cairo @@ -11,7 +11,7 @@ pub mod MessageContract { #[storage] struct Storage { - pub message: ByteArray + pub message: ByteArray, } #[constructor] diff --git a/listings/getting-started/calling_other_contracts/src/caller.cairo b/listings/getting-started/calling_other_contracts/src/caller.cairo index 1f599266..7a088711 100644 --- a/listings/getting-started/calling_other_contracts/src/caller.cairo +++ b/listings/getting-started/calling_other_contracts/src/caller.cairo @@ -27,7 +27,7 @@ pub mod Callee { #[starknet::interface] pub trait ICaller { fn set_value_from_address( - ref self: TContractState, addr: starknet::ContractAddress, value: u128 + ref self: TContractState, addr: starknet::ContractAddress, value: u128, ); } @@ -54,21 +54,21 @@ pub mod Caller { #[cfg(test)] mod tests { use super::{Callee, ICalleeDispatcher, Caller, ICallerDispatcher, ICallerDispatcherTrait}; - use starknet::{testing::set_contract_address, syscalls::deploy_syscall, SyscallResultTrait}; + use starknet::{testing::set_contract_address, syscalls::deploy_syscall}; use starknet::storage::StoragePointerReadAccess; fn deploy() -> (ICalleeDispatcher, ICallerDispatcher) { let (address_callee, _) = deploy_syscall( - Callee::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + Callee::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); let (address_caller, _) = deploy_syscall( - Caller::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + Caller::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); ( ICalleeDispatcher { contract_address: address_callee }, - ICallerDispatcher { contract_address: address_caller } + ICallerDispatcher { contract_address: address_caller }, ) } diff --git a/listings/getting-started/constructor/src/constructor.cairo b/listings/getting-started/constructor/src/constructor.cairo index 55540099..c384b00a 100644 --- a/listings/getting-started/constructor/src/constructor.cairo +++ b/listings/getting-started/constructor/src/constructor.cairo @@ -22,7 +22,7 @@ pub mod ExampleConstructor { #[cfg(test)] mod tests { use super::ExampleConstructor; - use starknet::{ContractAddress, SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::{ContractAddress, syscalls::deploy_syscall}; use starknet::{contract_address_const, testing::{set_contract_address}}; use starknet::storage::StorageMapReadAccess; @@ -35,9 +35,9 @@ mod tests { ExampleConstructor::TEST_CLASS_HASH.try_into().unwrap(), 0, array![name, address.into()].span(), - false + false, ) - .unwrap_syscall(); + .unwrap(); let state = @ExampleConstructor::contract_state_for_testing(); set_contract_address(contract_address); diff --git a/listings/getting-started/counter/src/counter.cairo b/listings/getting-started/counter/src/counter.cairo index e44bb058..593d2342 100644 --- a/listings/getting-started/counter/src/counter.cairo +++ b/listings/getting-started/counter/src/counter.cairo @@ -46,16 +46,16 @@ pub mod SimpleCounter { #[cfg(test)] mod test { use super::{SimpleCounter, ISimpleCounterDispatcher, ISimpleCounterDispatcherTrait}; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; fn deploy(init_value: u128) -> ISimpleCounterDispatcher { let (contract_address, _) = deploy_syscall( SimpleCounter::TEST_CLASS_HASH.try_into().unwrap(), 0, array![init_value.into()].span(), - false + false, ) - .unwrap_syscall(); + .unwrap(); ISimpleCounterDispatcher { contract_address } } diff --git a/listings/getting-started/custom_type_serde/src/contract.cairo b/listings/getting-started/custom_type_serde/src/contract.cairo index 8515f554..abd441ea 100644 --- a/listings/getting-started/custom_type_serde/src/contract.cairo +++ b/listings/getting-started/custom_type_serde/src/contract.cairo @@ -10,7 +10,7 @@ pub trait ISerdeCustomType { #[derive(Drop, Serde)] pub struct Person { pub age: u8, - pub name: felt252 + pub name: felt252, } #[starknet::contract] @@ -34,15 +34,15 @@ pub mod SerdeCustomType { #[cfg(test)] mod tests { use super::{ - SerdeCustomType, Person, ISerdeCustomTypeDispatcher, ISerdeCustomTypeDispatcherTrait + SerdeCustomType, Person, ISerdeCustomTypeDispatcher, ISerdeCustomTypeDispatcherTrait, }; - use starknet::{syscalls::deploy_syscall, SyscallResultTrait}; + use starknet::syscalls::deploy_syscall; fn deploy() -> ISerdeCustomTypeDispatcher { let (contract_address, _) = deploy_syscall( - SerdeCustomType::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + SerdeCustomType::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); ISerdeCustomTypeDispatcher { contract_address } } diff --git a/listings/getting-started/errors/src/custom_errors.cairo b/listings/getting-started/errors/src/custom_errors.cairo index 5361b10e..b287514f 100644 --- a/listings/getting-started/errors/src/custom_errors.cairo +++ b/listings/getting-started/errors/src/custom_errors.cairo @@ -35,15 +35,15 @@ pub mod CustomErrorsExample { #[cfg(test)] mod test { use super::{ - CustomErrorsExample, ICustomErrorsExampleDispatcher, ICustomErrorsExampleDispatcherTrait + CustomErrorsExample, ICustomErrorsExampleDispatcher, ICustomErrorsExampleDispatcherTrait, }; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; fn deploy() -> ICustomErrorsExampleDispatcher { let (contract_address, _) = deploy_syscall( - CustomErrorsExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + CustomErrorsExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); ICustomErrorsExampleDispatcher { contract_address } } diff --git a/listings/getting-started/errors/src/simple_errors.cairo b/listings/getting-started/errors/src/simple_errors.cairo index 7598794f..1477e1c8 100644 --- a/listings/getting-started/errors/src/simple_errors.cairo +++ b/listings/getting-started/errors/src/simple_errors.cairo @@ -31,13 +31,13 @@ pub mod ErrorsExample { #[cfg(test)] mod test { use super::{ErrorsExample, IErrorsExampleDispatcher, IErrorsExampleDispatcherTrait}; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; fn deploy() -> IErrorsExampleDispatcher { let (contract_address, _) = deploy_syscall( - ErrorsExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + ErrorsExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); IErrorsExampleDispatcher { contract_address } } diff --git a/listings/getting-started/errors/src/vault_errors.cairo b/listings/getting-started/errors/src/vault_errors.cairo index 595f9a9d..4da8a4e8 100644 --- a/listings/getting-started/errors/src/vault_errors.cairo +++ b/listings/getting-started/errors/src/vault_errors.cairo @@ -49,15 +49,15 @@ pub mod VaultErrorsExample { #[cfg(test)] mod test { use super::{ - VaultErrorsExample, IVaultErrorsExampleDispatcher, IVaultErrorsExampleDispatcherTrait + VaultErrorsExample, IVaultErrorsExampleDispatcher, IVaultErrorsExampleDispatcherTrait, }; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; fn deploy() -> IVaultErrorsExampleDispatcher { let (contract_address, _) = deploy_syscall( - VaultErrorsExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + VaultErrorsExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); IVaultErrorsExampleDispatcher { contract_address } } diff --git a/listings/getting-started/events/src/counter.cairo b/listings/getting-started/events/src/counter.cairo index fa11878d..612c81e5 100644 --- a/listings/getting-started/events/src/counter.cairo +++ b/listings/getting-started/events/src/counter.cairo @@ -21,14 +21,14 @@ pub mod EventCounter { // It must also derive at least the `Drop` and `starknet::Event` traits. pub enum Event { CounterIncreased: CounterIncreased, - UserIncreaseCounter: UserIncreaseCounter + UserIncreaseCounter: UserIncreaseCounter, } // By deriving the `starknet::Event` trait, we indicate to the compiler that // this struct will be used when emitting events. #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] pub struct CounterIncreased { - pub amount: u128 + pub amount: u128, } #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] @@ -51,9 +51,9 @@ pub mod EventCounter { .emit( Event::UserIncreaseCounter( UserIncreaseCounter { - user: get_caller_address(), new_value: self.counter.read() - } - ) + user: get_caller_address(), new_value: self.counter.read(), + }, + ), ); // [!endregion emit] } @@ -65,18 +65,18 @@ pub mod EventCounter { mod tests { use super::{ EventCounter, EventCounter::{Event, CounterIncreased, UserIncreaseCounter}, - IEventCounterDispatcherTrait, IEventCounterDispatcher + IEventCounterDispatcherTrait, IEventCounterDispatcher, }; - use starknet::{contract_address_const, SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::{contract_address_const, syscalls::deploy_syscall}; use starknet::testing::set_contract_address; use starknet::storage::StoragePointerReadAccess; #[test] fn test_increment_events() { let (contract_address, _) = deploy_syscall( - EventCounter::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + EventCounter::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); let mut contract = IEventCounterDispatcher { contract_address }; let state = @EventCounter::contract_state_for_testing(); @@ -94,14 +94,14 @@ mod tests { // [!region test_events] assert_eq!( starknet::testing::pop_log(contract_address), - Option::Some(Event::CounterIncreased(CounterIncreased { amount })) + Option::Some(Event::CounterIncreased(CounterIncreased { amount })), ); // [!endregion test_events] assert_eq!( starknet::testing::pop_log(contract_address), Option::Some( - Event::UserIncreaseCounter(UserIncreaseCounter { user: caller, new_value: amount }) - ) + Event::UserIncreaseCounter(UserIncreaseCounter { user: caller, new_value: amount }), + ), ); } } diff --git a/listings/getting-started/factory/src/simple_factory.cairo b/listings/getting-started/factory/src/simple_factory.cairo index 1d93badc..95fb8766 100644 --- a/listings/getting-started/factory/src/simple_factory.cairo +++ b/listings/getting-started/factory/src/simple_factory.cairo @@ -18,7 +18,7 @@ pub trait ICounterFactory { #[starknet::contract] pub mod CounterFactory { - use starknet::{ContractAddress, ClassHash, SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::{ContractAddress, ClassHash, syscalls::deploy_syscall}; use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; #[storage] @@ -44,9 +44,9 @@ pub mod CounterFactory { // Contract deployment let (deployed_address, _) = deploy_syscall( - self.counter_class_hash.read(), 0, constructor_calldata.span(), false + self.counter_class_hash.read(), 0, constructor_calldata.span(), false, ) - .unwrap_syscall(); + .unwrap(); deployed_address } @@ -70,7 +70,7 @@ pub mod CounterFactory { #[cfg(test)] mod tests { use super::{CounterFactory, ICounterFactoryDispatcher, ICounterFactoryDispatcherTrait}; - use starknet::{SyscallResultTrait, ClassHash, syscalls::deploy_syscall}; + use starknet::{ClassHash, syscalls::deploy_syscall}; // Define a target contract to deploy mod target { @@ -120,19 +120,19 @@ mod tests { /// Deploy a counter factory contract fn deploy_factory( - counter_class_hash: ClassHash, init_value: u128 + counter_class_hash: ClassHash, init_value: u128, ) -> ICounterFactoryDispatcher { let mut constructor_calldata: Array:: = array![ - init_value.into(), counter_class_hash.into() + init_value.into(), counter_class_hash.into(), ]; let (contract_address, _) = deploy_syscall( CounterFactory::TEST_CLASS_HASH.try_into().unwrap(), 0, constructor_calldata.span(), - false + false, ) - .unwrap_syscall(); + .unwrap(); ICounterFactoryDispatcher { contract_address } } diff --git a/listings/getting-started/interfaces_traits/src/explicit.cairo b/listings/getting-started/interfaces_traits/src/explicit.cairo index e9ab6b46..4454cc23 100644 --- a/listings/getting-started/interfaces_traits/src/explicit.cairo +++ b/listings/getting-started/interfaces_traits/src/explicit.cairo @@ -11,7 +11,7 @@ pub mod ExplicitInterfaceContract { #[storage] struct Storage { - value: u32 + value: u32, } #[abi(embed_v0)] @@ -31,9 +31,9 @@ pub mod ExplicitInterfaceContract { mod tests { use super::{ ExplicitInterfaceContract, IExplicitInterfaceContractDispatcher, - IExplicitInterfaceContractDispatcherTrait + IExplicitInterfaceContractDispatcherTrait, }; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; #[test] fn test_interface() { @@ -41,9 +41,9 @@ mod tests { ExplicitInterfaceContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), - false + false, ) - .unwrap_syscall(); + .unwrap(); let mut contract = IExplicitInterfaceContractDispatcher { contract_address }; let value: u32 = 20; diff --git a/listings/getting-started/interfaces_traits/src/implicit.cairo b/listings/getting-started/interfaces_traits/src/implicit.cairo index aa7f5400..0ab2d6d2 100644 --- a/listings/getting-started/interfaces_traits/src/implicit.cairo +++ b/listings/getting-started/interfaces_traits/src/implicit.cairo @@ -5,7 +5,7 @@ pub mod ImplicitInterfaceContract { #[storage] struct Storage { - value: u32 + value: u32, } #[abi(per_item)] @@ -27,7 +27,7 @@ pub mod ImplicitInterfaceContract { #[cfg(test)] mod tests { use super::{ImplicitInterfaceContract, ImplicitInterfaceContract::IImplicitInterfaceContract}; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall, testing::set_contract_address}; + use starknet::{syscalls::deploy_syscall, testing::set_contract_address}; #[test] fn test_interface() { @@ -35,9 +35,9 @@ mod tests { ImplicitInterfaceContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), - false + false, ) - .unwrap_syscall(); + .unwrap(); set_contract_address(contract_address); let mut state = ImplicitInterfaceContract::contract_state_for_testing(); diff --git a/listings/getting-started/interfaces_traits/src/implicit_internal.cairo b/listings/getting-started/interfaces_traits/src/implicit_internal.cairo index 0979d18e..74bdca0f 100644 --- a/listings/getting-started/interfaces_traits/src/implicit_internal.cairo +++ b/listings/getting-started/interfaces_traits/src/implicit_internal.cairo @@ -12,7 +12,7 @@ pub mod ImplicitInternalContract { #[storage] struct Storage { - value: u32 + value: u32, } #[generate_trait] @@ -52,17 +52,20 @@ pub mod ImplicitInternalContract { mod tests { use super::{ ImplicitInternalContract, IImplicitInternalContractDispatcher, - IImplicitInternalContractDispatcherTrait + IImplicitInternalContractDispatcherTrait, }; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; #[test] fn test_interface() { // Set up. let (contract_address, _) = deploy_syscall( - ImplicitInternalContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + ImplicitInternalContract::TEST_CLASS_HASH.try_into().unwrap(), + 0, + array![].span(), + false, ) - .unwrap_syscall(); + .unwrap(); let mut contract = IImplicitInternalContractDispatcher { contract_address }; let initial_value: u32 = 0; diff --git a/listings/getting-started/mappings/src/mappings.cairo b/listings/getting-started/mappings/src/mappings.cairo index 39286151..7a4aa932 100644 --- a/listings/getting-started/mappings/src/mappings.cairo +++ b/listings/getting-started/mappings/src/mappings.cairo @@ -33,14 +33,14 @@ pub mod MapContract { #[cfg(test)] mod test { use super::{MapContract, IMapContractDispatcher, IMapContractDispatcherTrait}; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; #[test] fn test_deploy_and_set_get() { let (contract_address, _) = deploy_syscall( - MapContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + MapContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); let mut contract = IMapContractDispatcher { contract_address }; // Write to map. diff --git a/listings/getting-started/storage/src/contract.cairo b/listings/getting-started/storage/src/contract.cairo index c9cae875..4ae5443c 100644 --- a/listings/getting-started/storage/src/contract.cairo +++ b/listings/getting-started/storage/src/contract.cairo @@ -5,7 +5,7 @@ pub mod Contract { struct Storage { pub a: u128, pub b: u8, - pub c: u256 + pub c: u256, } } // [!endregion contract] @@ -13,15 +13,15 @@ pub mod Contract { #[cfg(test)] mod test { use super::Contract; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; use starknet::storage::StoragePointerReadAccess; #[test] fn test_can_deploy() { let (_contract_address, _) = deploy_syscall( - Contract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + Contract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); } #[test] diff --git a/listings/getting-started/storage/src/minimal_contract.cairo b/listings/getting-started/storage/src/minimal_contract.cairo index a9bf24df..ef8ae142 100644 --- a/listings/getting-started/storage/src/minimal_contract.cairo +++ b/listings/getting-started/storage/src/minimal_contract.cairo @@ -10,14 +10,14 @@ pub mod Contract { #[cfg(test)] mod test { use super::Contract; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; #[test] fn test_can_deploy() { let (_contract_address, _) = deploy_syscall( - Contract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + Contract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); // Not much to test } } diff --git a/listings/getting-started/storing_custom_types/src/contract.cairo b/listings/getting-started/storing_custom_types/src/contract.cairo index 9d29c617..cd2ad282 100644 --- a/listings/getting-started/storing_custom_types/src/contract.cairo +++ b/listings/getting-started/storing_custom_types/src/contract.cairo @@ -10,7 +10,7 @@ pub trait IStoringCustomType { #[derive(Drop, Serde, Copy, starknet::Store)] pub struct Person { pub age: u8, - pub name: felt252 + pub name: felt252, } #[starknet::contract] @@ -20,7 +20,7 @@ pub mod StoringCustomType { #[storage] struct Storage { - pub person: Person + pub person: Person, } #[abi(embed_v0)] @@ -40,7 +40,7 @@ pub mod StoringCustomType { #[cfg(test)] mod tests { - use super::{IStoringCustomType, StoringCustomType, Person,}; + use super::{IStoringCustomType, StoringCustomType, Person}; use starknet::storage::StoragePointerReadAccess; #[test] diff --git a/listings/getting-started/testing_how_to/src/contract.cairo b/listings/getting-started/testing_how_to/src/contract.cairo index 5b9efff1..00a232b4 100644 --- a/listings/getting-started/testing_how_to/src/contract.cairo +++ b/listings/getting-started/testing_how_to/src/contract.cairo @@ -14,7 +14,7 @@ pub mod SimpleContract { #[storage] struct Storage { pub value: u32, - pub owner: ContractAddress + pub owner: ContractAddress, } #[constructor] @@ -48,7 +48,7 @@ mod tests { use super::{SimpleContract, ISimpleContractDispatcher, ISimpleContractDispatcherTrait}; // Import the deploy syscall to be able to deploy the contract. - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; use starknet::{get_contract_address, contract_address_const}; // Use starknet test utils to fake the contract_address @@ -61,9 +61,9 @@ mod tests { SimpleContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![initial_value.into()].span(), - false + false, ) - .unwrap_syscall(); + .unwrap(); // Return the dispatcher. // The dispatcher allows to interact with the contract based on its interface. @@ -164,7 +164,7 @@ mod tests_with_states { // But we can also deploy the contract and interact with it using the dispatcher // as shown in the previous tests, and still use the state for testing. use super::{ISimpleContractDispatcher, ISimpleContractDispatcherTrait}; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall, testing::set_contract_address}; + use starknet::{syscalls::deploy_syscall, testing::set_contract_address}; #[test] fn test_state_with_contract() { @@ -178,9 +178,9 @@ mod tests_with_states { SimpleContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![initial_value.into()].span(), - false + false, ) - .unwrap_syscall(); + .unwrap(); let mut contract = ISimpleContractDispatcher { contract_address }; // create the state diff --git a/listings/getting-started/variables/src/global_variables.cairo b/listings/getting-started/variables/src/global_variables.cairo index c0dcf9d3..01e7af48 100644 --- a/listings/getting-started/variables/src/global_variables.cairo +++ b/listings/getting-started/variables/src/global_variables.cairo @@ -26,14 +26,14 @@ pub mod GlobalExample { #[cfg(test)] mod test { use super::GlobalExample; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; #[test] fn test_can_deploy() { let (_contract_address, _) = deploy_syscall( - GlobalExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + GlobalExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); // Not much to test } } diff --git a/listings/getting-started/variables/src/local_variables.cairo b/listings/getting-started/variables/src/local_variables.cairo index c7f2a2e6..b6d62839 100644 --- a/listings/getting-started/variables/src/local_variables.cairo +++ b/listings/getting-started/variables/src/local_variables.cairo @@ -32,16 +32,16 @@ pub mod LocalVariablesExample { mod test { use super::{ LocalVariablesExample, ILocalVariablesExampleDispatcher, - ILocalVariablesExampleDispatcherTrait + ILocalVariablesExampleDispatcherTrait, }; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; #[test] fn test_can_deploy_and_do_something() { let (contract_address, _) = deploy_syscall( - LocalVariablesExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + LocalVariablesExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); let contract = ILocalVariablesExampleDispatcher { contract_address }; let value = 10; diff --git a/listings/getting-started/variables/src/storage_variables.cairo b/listings/getting-started/variables/src/storage_variables.cairo index 98fff616..3369445e 100644 --- a/listings/getting-started/variables/src/storage_variables.cairo +++ b/listings/getting-started/variables/src/storage_variables.cairo @@ -15,7 +15,7 @@ pub mod StorageVariablesExample { #[storage] struct Storage { // Storage variable holding a number - pub value: u32 + pub value: u32, } #[abi(embed_v0)] @@ -38,18 +38,18 @@ pub mod StorageVariablesExample { mod test { use super::{ StorageVariablesExample, IStorageVariableExampleDispatcher, - IStorageVariableExampleDispatcherTrait + IStorageVariableExampleDispatcherTrait, }; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; use starknet::testing::set_contract_address; use starknet::storage::StoragePointerReadAccess; #[test] fn test_can_deploy_and_mutate_storage() { let (contract_address, _) = deploy_syscall( - StorageVariablesExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + StorageVariablesExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); let contract = IStorageVariableExampleDispatcher { contract_address }; diff --git a/listings/getting-started/visibility/src/visibility.cairo b/listings/getting-started/visibility/src/visibility.cairo index c3b4e2f4..6143566c 100644 --- a/listings/getting-started/visibility/src/visibility.cairo +++ b/listings/getting-started/visibility/src/visibility.cairo @@ -11,7 +11,7 @@ pub mod ExampleContract { #[storage] struct Storage { - pub value: u32 + pub value: u32, } // The `#[abi(embed_v0)]` attribute indicates that all @@ -57,7 +57,7 @@ pub mod ExampleContract { #[cfg(test)] mod test { use super::{ExampleContract, IExampleContractDispatcher, IExampleContractDispatcherTrait}; - use starknet::{SyscallResultTrait, syscalls::deploy_syscall}; + use starknet::syscalls::deploy_syscall; use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; // These imports will allow us to directly access and set the contract state: @@ -71,9 +71,9 @@ mod test { #[test] fn can_call_set_and_get() { let (contract_address, _) = deploy_syscall( - ExampleContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false + ExampleContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, ) - .unwrap_syscall(); + .unwrap(); // You can interact with the external entrypoints of the contract using the dispatcher. let contract = IExampleContractDispatcher { contract_address }; diff --git a/pages/components/collisions.md b/pages/components/collisions.md index 32e0e20c..32757d10 100644 --- a/pages/components/collisions.md +++ b/pages/components/collisions.md @@ -21,7 +21,7 @@ Interface: // [!include ~/listings/applications/components/src/others/switch_collision.cairo:interface] ``` -Here's the storage of the contract (you can expand the code snippet to see the full contract and tests): +Here's the storage of the contract: ```cairo // [!include ~/listings/applications/components/src/others/switch_collision.cairo:storage] diff --git a/pages/getting-started/basics/storage.md b/pages/getting-started/basics/storage.md index 78acbdb4..16210f31 100644 --- a/pages/getting-started/basics/storage.md +++ b/pages/getting-started/basics/storage.md @@ -17,7 +17,7 @@ You can define [storage variables](/getting-started/basics/variables#storage-var :::note Actually these two contracts have the same underlying Sierra program. -From the compiler's perspective, the storage variables don't exist until they are used. +The Sierra code is generated only for storage variables that are actually accessed in the contract's functions. Declaring but never using a storage variable doesn't affect the compiled contract size/gas costs. ::: You can also read about [storing custom types](/getting-started/basics/storing-custom-types). diff --git a/pages/getting-started/basics/syscalls.md b/pages/getting-started/basics/syscalls.md index 9c93fdda..64ce911e 100644 --- a/pages/getting-started/basics/syscalls.md +++ b/pages/getting-started/basics/syscalls.md @@ -163,7 +163,7 @@ let values = array![]; values.append(1); values.append(2); values.append(3); -emit_event_syscall(keys, values).unwrap_syscall(); +emit_event_syscall(keys, values).unwrap(); ``` --> #### library_call diff --git a/pages/index.mdx b/pages/index.mdx index fa8cde31..0814302d 100644 --- a/pages/index.mdx +++ b/pages/index.mdx @@ -39,7 +39,7 @@ You can run each example online by using the [Starknet Remix Plugin](https://rem ## Further reading If you want to learn more about the Cairo programming language, you can read the [Cairo Book](https://book.cairo-lang.org). -If you want to learn more about Starknet, you can read the [Starknet documentation](https://docs.starknet.io/) and the [Starknet Book](https://book.starknet.io). +If you want to learn more about Starknet, you can read the [Starknet documentation](https://docs.starknet.io/) and the [Starknet Book](https://docs.starknet.io/). For more resources, check [Awesome Starknet](https://github.com/keep-starknet-strange/awesome-starknet). diff --git a/routes.ts b/routes.ts index 53ec16c0..0faacdaf 100644 --- a/routes.ts +++ b/routes.ts @@ -198,23 +198,20 @@ const config: Sidebar = [ }, ], }, - { - text: "Account Abstraction", - items: [ - { - text: "AA on Starknet", - link: "/advanced-concepts/account_abstraction", - }, - { - text: "Account Contract", - link: "/advanced-concepts/account_abstraction/account_contract", - }, - { - text: "Account with Spending Limits", - link: "/advanced-concepts/account_abstraction/account_spending_limits", - } - ], - }, + // Hidden as the content is not 100% correct + // { + // text: "Account Abstraction", + // items: [ + // { + // text: "AA on Starknet", + // link: "/advanced-concepts/account_abstraction", + // }, + // { + // text: "Account Contract", + // link: "/advanced-concepts/account_abstraction/account_contract", + // }, + // ], + // }, { text: "Library Calls", link: "/advanced-concepts/library_calls", diff --git a/vocs.config.ts b/vocs.config.ts index b26ef120..da4225c3 100644 --- a/vocs.config.ts +++ b/vocs.config.ts @@ -23,7 +23,7 @@ export default defineConfig({ editLink: { text: "Contribute", pattern: - "https://github.com/NethermindEth/StarknetByExample/edit/vocs/pages/:path", + "https://github.com/NethermindEth/StarknetByExample/edit/dev/pages/:path", }, socials: [ { From 319609a18dc5d2ef94b4f31ec6c53f73d01d3b95 Mon Sep 17 00:00:00 2001 From: Julio <30329843+julio4@users.noreply.github.com> Date: Tue, 17 Dec 2024 19:10:13 +0700 Subject: [PATCH 08/44] Update verify_cairo_programs.yml --- .github/workflows/verify_cairo_programs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify_cairo_programs.yml b/.github/workflows/verify_cairo_programs.yml index 518a91f8..151ceee2 100644 --- a/.github/workflows/verify_cairo_programs.yml +++ b/.github/workflows/verify_cairo_programs.yml @@ -3,7 +3,7 @@ name: Verify Cairo programs compilation on: pull_request: branches: - - main + - dev workflow_dispatch: jobs: From 904b746d5b4020e914dbf57ab368bf8f1bdc68e1 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Wed, 1 Jan 2025 15:48:29 +0100 Subject: [PATCH 09/44] feat: rework index --- pages/index.mdx | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/pages/index.mdx b/pages/index.mdx index 0814302d..34b6bcdb 100644 --- a/pages/index.mdx +++ b/pages/index.mdx @@ -11,47 +11,46 @@ import { ThemeImage } from "../components/ThemeImage"; # Introduction -Starknet By Example is a collection of examples of how to use the Cairo programming language to create smart contracts on Starknet. +Starknet By Example provides practical examples for building smart contracts on Starknet using the Cairo programming language. -Starknet is a permissionless Validity-Rollup that supports general computation. It is currently used as an Ethereum layer-2. Starknet uses the STARK cryptographic proof system to ensure high safety and scalability. +Starknet is a permissionless Validity-Rollup that operates as an Ethereum layer-2 scaling solution. It leverages STARK cryptographic proofs to achieve high security and scalability while maintaining Ethereum's security guarantees. -Starknet smart contracts are written in the Cairo language. Cairo is a Turing-complete programming language designed to write provable programs, abstracting the zk-STARK proof system away from the programmer. +Smart contracts on Starknet are written in Cairo, a Turing-complete programming language specifically designed for creating provable programs. Cairo abstracts away the complexity of zk-STARK proofs, allowing developers to focus on writing smart contract logic. :::warning -⚠️ _The examples have not been audited and are not intended for production use. The authors are not responsible for any damages caused by the use of the code provided in this book._ +⚠️ _These examples are for educational purposes and have not been audited. Do not use this code in production. The authors are not liable for any damages resulting from the use of this code._ -If you find any errors or have suggestions for improvements, please open an issue on the [GitHub repository](https://github.com/NethermindEth/StarknetByExample/issues). All contributions are welcome! +Found an error or have a suggestion? Open an issue on our [GitHub repository](https://github.com/NethermindEth/StarknetByExample/issues). We welcome all contributions! ::: -## For whom is this for? +## Who is this for? -Starknet By Example is for anyone who wants to quickly learn how to write smart contracts on Starknet using Cairo with some technical background in programming and blockchain. +This guide is designed for developers with basic programming and blockchain knowledge who want to learn Starknet smart contract development using Cairo. -The first chapters will give you a basic understanding of the Cairo programming language and how to write, deploy and use smart contracts on Starknet. -The later chapters will cover more advanced topics and show you how to write more complex smart contracts. +The content is structured progressively - early chapters cover Cairo and Starknet fundamentals, while later chapters explore advanced topics and complex smart contract patterns. ## How to use this book? -Each chapter is a standalone example that demonstrates a specific feature or common use case of smart contracts on Starknet. If you are new to Starknet, it is recommended to read the chapters in order. +Each chapter is self-contained and focuses on a specific Starknet feature or smart contract use case. While you can jump to any topic, we recommend following the chapters in order if you're new to Starknet. -You can run each example online by using the [Starknet Remix Plugin](https://remix.ethereum.org/?#activate=Starknet). +Try out the examples instantly using the [Starknet Remix Plugin](https://remix.ethereum.org/?#activate=Starknet). ## Further reading -If you want to learn more about the Cairo programming language, you can read the [Cairo Book](https://book.cairo-lang.org). -If you want to learn more about Starknet, you can read the [Starknet documentation](https://docs.starknet.io/) and the [Starknet Book](https://docs.starknet.io/). - -For more resources, check [Awesome Starknet](https://github.com/keep-starknet-strange/awesome-starknet). +To deepen your knowledge: +- [Starknet Documentation](https://docs.starknet.io/) - The official Starknet documentation +- [Cairo Book](https://book.cairo-lang.org) - Learn more about the Cairo programming language +- [Awesome Starknet](https://github.com/keep-starknet-strange/awesome-starknet) - Curated list of Starknet resources ## Versions -The current version this book uses: +The current version of this book uses: ```md -cairo 2.8.2 +cairo 2.9.2 edition 2024_07 -sierra 1.6.0 // [!include ~/.tool-versions] +sierra 1.6.0 ``` From 0fe426b9c067c2ca2a23c9b7f8569d8e1fff950a Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Wed, 1 Jan 2025 16:38:29 +0100 Subject: [PATCH 10/44] fix: suggest snforge in contributing guide --- CONTRIBUTING.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0543b466..40f4b0ef 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,13 +2,13 @@ When contributing to this repository, please first discuss the change you wish to make via issue or in the telegram channel before making a change. -Join the telegram channel: https://t.me/StarknetByExample +Join the telegram channel: The release branch is `main`. The development branch is `dev` and is considered stable (but not released yet). When you want to contribute, please create a new branch from `dev` and open a pull request to merge your changes back into `dev`. You should never open a pull request to merge your changes directly into `main`. -The `dev` branch is deployed at https://starknet-by-example-dev.voyager.online/ +The `dev` branch is deployed at Please note we have a code of conduct, please follow it in all your interactions with the project. @@ -86,10 +86,10 @@ typos src/ You can add or modify examples in the `listings` directory. Each listing is a scarb project. You can use `scarb init` to create a new scarb project, but be sure to remove the generated git repository with `rm -rf .git` and follow the instructions below for the correct `Scarb.toml` configuration. -You can choose to use standard cairo with `cairo-test` or Starknet Foundry with `snforge_std`. +We prefer to use Starknet Foundry with `snforge_std`, however you can still use `cairo-test` if desired. Please use the appropriate `Scarb.toml` configuration. `scarb test` will automatically resolve to `snforge test` if `snforge_std` is in the dependencies. -Here's the required `Scarb.toml` configuration for **cairo-test**: +Here's the required `Scarb.toml` configuration for **Starknet Foundry**: ```toml [package] @@ -109,7 +109,8 @@ starknet.workspace = true # erc20 = { path = "../../getting-started/erc20" } [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true @@ -117,7 +118,12 @@ test.workspace = true [[target.starknet-contract]] ``` -Here's the required `Scarb.toml` configuration for **Starknet Foundry**: +You also **NEED** to do the following: + +- Remove the generated git repository, `rm -rf .git` (this is important!) +- Double check that the package name is the same as the name of the directory + +Here's the required `Scarb.toml` configuration for **cairo-test**: ```toml [package] @@ -137,8 +143,7 @@ starknet.workspace = true # erc20 = { path = "../../getting-started/erc20" } [dev-dependencies] -assert_macros.workspace = true -snforge_std.workspace = true +cairo_test.workspace = true [scripts] test.workspace = true @@ -146,11 +151,6 @@ test.workspace = true [[target.starknet-contract]] ``` -You also NEED to do the following: - -- Remove the generated git repository, `rm -rf .git` (this is important!) -- Double check that the package name is the same as the name of the directory - ### Verification script The current book has script that verifies the compilation of all Cairo programs in the book. From 86b240dc289975cd1c184c87a82928313fc8f886 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Wed, 1 Jan 2025 16:58:19 +0100 Subject: [PATCH 11/44] fix: update footer date --- footer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/footer.tsx b/footer.tsx index 70d07b30..5985ff6f 100644 --- a/footer.tsx +++ b/footer.tsx @@ -8,7 +8,7 @@ export default function Footer() { />
Released under the MIT License. - © 2024 Nethermind. All Rights Reserved + © 2025 Nethermind. All Rights Reserved
); From 57c35bd10ab421bcf63e3459544c59f2f810b857 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:02:31 +0100 Subject: [PATCH 12/44] feat: migrate storage to snforge --- listings/getting-started/storage/Scarb.toml | 3 +- .../storage/src/contract.cairo | 35 +++++++++---------- .../storage/src/minimal_contract.cairo | 11 +++--- 3 files changed, 22 insertions(+), 27 deletions(-) diff --git a/listings/getting-started/storage/Scarb.toml b/listings/getting-started/storage/Scarb.toml index 4bacb1e5..7d483c5a 100644 --- a/listings/getting-started/storage/Scarb.toml +++ b/listings/getting-started/storage/Scarb.toml @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/storage/src/contract.cairo b/listings/getting-started/storage/src/contract.cairo index 4ae5443c..dc7a436a 100644 --- a/listings/getting-started/storage/src/contract.cairo +++ b/listings/getting-started/storage/src/contract.cairo @@ -1,34 +1,31 @@ // [!region contract] #[starknet::contract] -pub mod Contract { +mod Contract { #[storage] struct Storage { - pub a: u128, - pub b: u8, - pub c: u256, + a: u128, + b: u8, + c: u256, } } // [!endregion contract] #[cfg(test)] mod test { - use super::Contract; - use starknet::syscalls::deploy_syscall; - use starknet::storage::StoragePointerReadAccess; - - #[test] - fn test_can_deploy() { - let (_contract_address, _) = deploy_syscall( - Contract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); - } + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare, load}; #[test] fn test_storage_members() { - let state = @Contract::contract_state_for_testing(); - assert_eq!(state.a.read(), 0_u128); - assert_eq!(state.b.read(), 0_u8); - assert_eq!(state.c.read(), 0_u256); + let contract = declare("Contract").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); + + let mut loaded = load(contract_address, selector!("a"), 1).span(); + assert_eq!(Serde::deserialize(ref loaded).unwrap(), 0); + + let mut loaded = load(contract_address, selector!("b"), 1).span(); + assert_eq!(Serde::deserialize(ref loaded).unwrap(), 0); + + let mut loaded = load(contract_address, selector!("c"), 2).span(); + assert_eq!(Serde::deserialize(ref loaded).unwrap(), 0); } } diff --git a/listings/getting-started/storage/src/minimal_contract.cairo b/listings/getting-started/storage/src/minimal_contract.cairo index ef8ae142..eea58c6a 100644 --- a/listings/getting-started/storage/src/minimal_contract.cairo +++ b/listings/getting-started/storage/src/minimal_contract.cairo @@ -1,6 +1,6 @@ // [!region contract] #[starknet::contract] -pub mod Contract { +mod Contract { #[storage] struct Storage {} } @@ -9,15 +9,12 @@ pub mod Contract { // [!region tests] #[cfg(test)] mod test { - use super::Contract; - use starknet::syscalls::deploy_syscall; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; #[test] fn test_can_deploy() { - let (_contract_address, _) = deploy_syscall( - Contract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); + let contract = declare("Contract").unwrap().contract_class(); + let (_contract_address, _) = contract.deploy(@array![]).unwrap(); // Not much to test } } From b0cbfffe62bc0c9ecb7a89506b928d8bd3b96cc5 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Fri, 3 Jan 2025 11:45:51 +0100 Subject: [PATCH 13/44] feat: rework storage --- pages/getting-started/basics/storage.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/pages/getting-started/basics/storage.md b/pages/getting-started/basics/storage.md index 16210f31..d046ee6a 100644 --- a/pages/getting-started/basics/storage.md +++ b/pages/getting-started/basics/storage.md @@ -1,23 +1,27 @@ # Storage -Here's the most minimal contract you can write in Cairo: +## Basic Contract Structure + +Every Starknet contract must be defined as a module with the `#[starknet::contract]` attribute. Here's the simplest possible Cairo contract: ```cairo // [!include ~/listings/getting-started/storage/src/minimal_contract.cairo:contract] ``` -Storage is a `struct` annotated with `#[storage]`. Every contract must have one and only one storage. -It's a key-value store, where each key will be mapped to a storage address of the contract's storage space. +## Contract Storage Basics + +Storage in Cairo contracts is implemented as a key-value store using a struct marked with the `#[storage]` attribute. Every contract must have exactly one storage definition, which serves as the contract's persistent state on the blockchain and is kept between contract executions. + +### Storage Variables -You can define [storage variables](/getting-started/basics/variables#storage-variables) in your contract, and then use them to store and retrieve data. +You can define [Storage Variables](/getting-started/basics/variables#storage-variables) to store and retrieve data in your contract: ```cairo // [!include ~/listings/getting-started/storage/src/contract.cairo:contract] ``` :::note -Actually these two contracts have the same underlying Sierra program. -The Sierra code is generated only for storage variables that are actually accessed in the contract's functions. Declaring but never using a storage variable doesn't affect the compiled contract size/gas costs. +💡 **Optimization Tip**: Both contracts above generate identical Sierra code. The compiler only generates code for storage variables that are actually used in contract functions. Declaring unused storage variables has no impact on contract size or gas costs. ::: -You can also read about [storing custom types](/getting-started/basics/storing-custom-types). +For more complex data structures, see [Storing Custom Types](/getting-started/basics/storing-custom-types). From 23c161b182c55fa0d0b41b2af19311557791d979 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Fri, 3 Jan 2025 12:03:31 +0100 Subject: [PATCH 14/44] feat: storage space section --- pages/getting-started/basics/storage.md | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/pages/getting-started/basics/storage.md b/pages/getting-started/basics/storage.md index d046ee6a..9388dd43 100644 --- a/pages/getting-started/basics/storage.md +++ b/pages/getting-started/basics/storage.md @@ -25,3 +25,33 @@ You can define [Storage Variables](/getting-started/basics/variables#storage-var ::: For more complex data structures, see [Storing Custom Types](/getting-started/basics/storing-custom-types). + +### Storage Space (advanced) + +The contract's storage space consists of $2^{251}$ *storage slots*, where each slot: + +- Can store a single `felt252` value +- Is initialized to 0 +- Has a unique address that can be accessed using `selector!("variable_name")` for primitive types + +In our previous contract example: + +- Variable `a` (u128): + - Address: `selector!("a")` + - Uses first 128 bits of the slot + - Leaves 124 bits unused +- Variable `b` (u8): + - Address: `selector!("b")` + - Uses first 8 bits of the slot + - Leaves 244 bits unused +- Variable `c` (u256) + - An u256 cannot fit in a single slot + - Base address: `selector!("c")` + - Uses two consecutive slots: + - First slot: lower 128 bits at `selector!("c")` + - Second slot: upper 128 bits at `selector!("c") + 1` + - Leaves 248 bits unused + +:::note +💡 **Storage Optimization**: Notice how many bits are left unused in each slot? This can make storage operations expensive. To optimize storage usage, you can pack multiple variables together. Learn more in [Storage Optimisation](/advanced-concepts/optimisations/store_using_packing). +::: From 9e74dd025fd5fdec4de63d5b91a3938b7f6974e7 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Fri, 3 Jan 2025 12:07:21 +0100 Subject: [PATCH 15/44] fix: syscall typo --- pages/getting-started/basics/syscalls.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/getting-started/basics/syscalls.md b/pages/getting-started/basics/syscalls.md index 64ce911e..bacccda4 100644 --- a/pages/getting-started/basics/syscalls.md +++ b/pages/getting-started/basics/syscalls.md @@ -4,7 +4,7 @@ At the protocol level, the Starknet Operating System (OS) is the program that ma Some of the OS functionalities are exposed to smart contracts through the use of syscalls (system calls). Syscalls can be used to get information about the state of the Starknet network, to interact with/deploy contracts, emit events, send messages, and perform other low-level operations. -Syscalls return a `SyscallResult` which is either `Success` of `Failure`, allowing the contract to handle errors. +Syscalls return a `SyscallResult` which is either `Success` or `Failure`, allowing the contract to handle errors. Here's the available syscalls: From 4ad870ec22aadfc1d59ab871fa9149f7794f5835 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Sun, 12 Jan 2025 09:17:45 +0100 Subject: [PATCH 16/44] feat: migrate constructor to snforge --- Scarb.lock | 6 +++ .../getting-started/constructor/Scarb.toml | 3 +- .../constructor/src/constructor.cairo | 52 +++++++++---------- 3 files changed, 34 insertions(+), 27 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index f401f76d..4f571cb7 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -64,6 +64,9 @@ dependencies = [ [[package]] name = "constructor" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "counter" @@ -300,6 +303,9 @@ dependencies = [ [[package]] name = "storage" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "store_using_packing" diff --git a/listings/getting-started/constructor/Scarb.toml b/listings/getting-started/constructor/Scarb.toml index db71d0e6..239e6080 100644 --- a/listings/getting-started/constructor/Scarb.toml +++ b/listings/getting-started/constructor/Scarb.toml @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/constructor/src/constructor.cairo b/listings/getting-started/constructor/src/constructor.cairo index c384b00a..4234c81c 100644 --- a/listings/getting-started/constructor/src/constructor.cairo +++ b/listings/getting-started/constructor/src/constructor.cairo @@ -1,19 +1,23 @@ // [!region contract] #[starknet::contract] -pub mod ExampleConstructor { - use starknet::ContractAddress; - use starknet::storage::{Map, StorageMapWriteAccess}; +mod ConstructorContract { + // This trait is necessary to be able to write to a specific storage variable + use starknet::storage::StoragePointerWriteAccess; #[storage] struct Storage { - pub names: Map::, + a: u128, + b: u8, + c: u256, } // The constructor is decorated with a `#[constructor]` attribute. // It is not inside an `impl` block. #[constructor] - fn constructor(ref self: ContractState, name: felt252, address: ContractAddress) { - self.names.write(address, name); + fn constructor(ref self: ContractState, a: u128, b: u8, c: u256) { + self.a.write(a); + self.b.write(b); + self.c.write(c); } } // [!endregion contract] @@ -21,29 +25,25 @@ pub mod ExampleConstructor { // [!region tests] #[cfg(test)] mod tests { - use super::ExampleConstructor; - use starknet::{ContractAddress, syscalls::deploy_syscall}; - use starknet::{contract_address_const, testing::{set_contract_address}}; - use starknet::storage::StorageMapReadAccess; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare, load}; #[test] fn should_deploy_with_constructor_init_value() { - let name: felt252 = 'bob'; - let address: ContractAddress = contract_address_const::<'caller'>(); - - let (contract_address, _) = deploy_syscall( - ExampleConstructor::TEST_CLASS_HASH.try_into().unwrap(), - 0, - array![name, address.into()].span(), - false, - ) - .unwrap(); - - let state = @ExampleConstructor::contract_state_for_testing(); - set_contract_address(contract_address); - - let name = state.names.read(address); - assert_eq!(name, 'bob'); + let contract = declare("ConstructorContract").unwrap().contract_class(); + let mut constructor_calldata: Array = array![]; + 1_u128.serialize(ref constructor_calldata); // a + 2_u8.serialize(ref constructor_calldata); // b + 3_u256.serialize(ref constructor_calldata); // c + let (contract_address, _) = contract.deploy(@constructor_calldata).unwrap(); + + let mut loaded = load(contract_address, selector!("a"), 1).span(); + assert_eq!(Serde::deserialize(ref loaded).unwrap(), 1); + + let mut loaded = load(contract_address, selector!("b"), 1).span(); + assert_eq!(Serde::deserialize(ref loaded).unwrap(), 2); + + let mut loaded = load(contract_address, selector!("c"), 2).span(); + assert_eq!(Serde::deserialize(ref loaded).unwrap(), 3); } } // [!endregion tests] From 1dd88c788983426034ecfe3e094918d55307cde5 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Sun, 12 Jan 2025 10:23:35 +0100 Subject: [PATCH 17/44] feat: rework constructor --- pages/getting-started/basics/constructor.md | 30 +++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/pages/getting-started/basics/constructor.md b/pages/getting-started/basics/constructor.md index 13806020..d32b5a9c 100644 --- a/pages/getting-started/basics/constructor.md +++ b/pages/getting-started/basics/constructor.md @@ -1,9 +1,35 @@ # Constructor -Constructors are a special type of function that runs only once when deploying a contract, and can be used to initialize the state of the contract. Your contract must not have more than one constructor, and that constructor function must be annotated with the `#[constructor]` attribute. Also, a good practice consists in naming that function `constructor`. +A constructor is a special function that initializes a contract's state during deployment. It has several key characteristics: -Here's a simple example that demonstrates how to initialize the state of a contract on deployment by defining logic inside a constructor. +- Runs exactly once when the contract is deployed +- Must be annotated with `#[constructor]` +- Up to one constructor per contract +- Function is conventionally named `constructor` + +Here's an example that shows how to initialize storage variables during contract deployment: ```cairo // [!include ~/listings/getting-started/constructor/src/constructor.cairo:contract] ``` + +In this example: + +- The constructor takes three parameters: `a`, `b`, and `c` +- Each parameter corresponds to a storage variable of the same name, but you can specify any argument variable name +- The values are written to storage using the `write()` method. You need to import the `StoragePointerWriteAccess` trait to be able to write to a specific storage pointer + +:::note +**Best Practice** + +Constructors are ideal for: + +- Setting initial contract state +- Storing deployment-time parameters +- Initializing access control (e.g., setting an owner) + +::: + +:::warning +**Constructor values cannot be changed after deployment unless you specifically implement functions to modify them.** +::: From 313f75e4c70cde1a31a2f98f822560e1e9ee5a2b Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Mon, 13 Jan 2025 13:43:55 +0100 Subject: [PATCH 18/44] feat: improve storage layout example --- pages/getting-started/basics/storage.md | 39 ++++++++++++++++--------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/pages/getting-started/basics/storage.md b/pages/getting-started/basics/storage.md index 9388dd43..d93b7d55 100644 --- a/pages/getting-started/basics/storage.md +++ b/pages/getting-started/basics/storage.md @@ -21,7 +21,9 @@ You can define [Storage Variables](/getting-started/basics/variables#storage-var ``` :::note -💡 **Optimization Tip**: Both contracts above generate identical Sierra code. The compiler only generates code for storage variables that are actually used in contract functions. Declaring unused storage variables has no impact on contract size or gas costs. +**Optimization Tip** + +Both contracts above generate identical Sierra code. The compiler only generates code for storage variables that are actually used in contract functions. Declaring unused storage variables has no impact on contract size or gas costs. ::: For more complex data structures, see [Storing Custom Types](/getting-started/basics/storing-custom-types). @@ -32,26 +34,37 @@ The contract's storage space consists of $2^{251}$ *storage slots*, where each s - Can store a single `felt252` value - Is initialized to 0 -- Has a unique address that can be accessed using `selector!("variable_name")` for primitive types + +### Storage Pointers + +Storage variables are stored in storage slots using Starknet's memory model abstraction called **Storage Pointers**. A storage pointer is a tuple `(base_address, offset)` where: + +- `base_address` is the address of the first slot where the variable is stored +- `offset` is the distance from the base address where the variable is stored + +To get the base address of a storage variable, you can use the `selector!` macro to derive it from the variable name: for example, `selector!("variable_name")`. + +### Storage Layout Example In our previous contract example: - Variable `a` (u128): - - Address: `selector!("a")` - - Uses first 128 bits of the slot + - Base address: `selector!("a")` + - Uses lowest 128 bits of the slot at offset 0 - Leaves 124 bits unused - Variable `b` (u8): - - Address: `selector!("b")` - - Uses first 8 bits of the slot + - Base address: `selector!("b")` + - Uses lowest 8 bits of the slot at offset 0 - Leaves 244 bits unused -- Variable `c` (u256) - - An u256 cannot fit in a single slot +- Variable `c` (u256): - Base address: `selector!("c")` - - Uses two consecutive slots: - - First slot: lower 128 bits at `selector!("c")` - - Second slot: upper 128 bits at `selector!("c") + 1` - - Leaves 248 bits unused + - Too large for a single slot, uses two consecutive slots: + - First slot: lower 128 bits at offset 0 + - Second slot: lower 128 bits at offset 1 + - Leaves 248 bits unused, 124 in each slot :::note -💡 **Storage Optimization**: Notice how many bits are left unused in each slot? This can make storage operations expensive. To optimize storage usage, you can pack multiple variables together. Learn more in [Storage Optimisation](/advanced-concepts/optimisations/store_using_packing). +**Storage Optimization** + +Notice how many bits are left unused in each slot? This can make storage operations expensive. To optimize storage usage, you can pack multiple variables together. Learn more in [Storage Optimisation](/advanced-concepts/optimisations/store_using_packing). ::: From 65db4cb7f0fd707a4395108da483bb9589a1fc16 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:12:31 +0100 Subject: [PATCH 19/44] feat: migrate variables to snforge --- listings/getting-started/variables/Scarb.toml | 3 +- .../variables/src/global_variables.cairo | 33 +++---------- .../variables/src/local_variables.cairo | 49 ++++++------------- .../variables/src/storage_variables.cairo | 34 +++++-------- 4 files changed, 36 insertions(+), 83 deletions(-) diff --git a/listings/getting-started/variables/Scarb.toml b/listings/getting-started/variables/Scarb.toml index 59fc6451..9509bac1 100644 --- a/listings/getting-started/variables/Scarb.toml +++ b/listings/getting-started/variables/Scarb.toml @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/variables/src/global_variables.cairo b/listings/getting-started/variables/src/global_variables.cairo index 01e7af48..c2ff2d07 100644 --- a/listings/getting-started/variables/src/global_variables.cairo +++ b/listings/getting-started/variables/src/global_variables.cairo @@ -1,39 +1,20 @@ -#[starknet::interface] -pub trait IGlobalExample { - fn foo(ref self: TContractState); -} - // [!region contract] #[starknet::contract] -pub mod GlobalExample { +pub mod GlobalVariablesContract { // import the required functions from the starknet core library use starknet::get_caller_address; #[storage] struct Storage {} - #[abi(embed_v0)] - impl GlobalExampleImpl of super::IGlobalExample { - fn foo(ref self: ContractState) { - // Call the get_caller_address function to get the sender address - let _caller = get_caller_address(); - // ... - } + pub fn foo(ref self: ContractState) { + // Call the get_caller_address function to get the sender address + let _caller = get_caller_address(); + // ... } } // [!endregion contract] -#[cfg(test)] -mod test { - use super::GlobalExample; - use starknet::syscalls::deploy_syscall; +// Not much to test + - #[test] - fn test_can_deploy() { - let (_contract_address, _) = deploy_syscall( - GlobalExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); - // Not much to test - } -} diff --git a/listings/getting-started/variables/src/local_variables.cairo b/listings/getting-started/variables/src/local_variables.cairo index b6d62839..040ba0a2 100644 --- a/listings/getting-started/variables/src/local_variables.cairo +++ b/listings/getting-started/variables/src/local_variables.cairo @@ -1,51 +1,34 @@ -#[starknet::interface] -pub trait ILocalVariablesExample { - fn do_something(self: @TContractState, value: u32) -> u32; -} - // [!region contract] #[starknet::contract] -pub mod LocalVariablesExample { +mod LocalVariablesContract { #[storage] struct Storage {} - #[abi(embed_v0)] - impl LocalVariablesExample of super::ILocalVariablesExample { - fn do_something(self: @ContractState, value: u32) -> u32 { - // This variable is local to the current block. - // It can't be accessed once it goes out of scope. - let increment = 10; + pub fn do_something(self: @ContractState, value: u32) -> u32 { + // This variable is local to the current block. + // It can't be accessed once it goes out of scope. + let increment = 10; - { - // The scope of a code block allows for local variable declaration - // We can access variables defined in higher scopes. - let sum = value + increment; - sum - } - // We can't access the variable `sum` here, as it's out of scope. + { + // The scope of a code block allows for local variable declaration + // We can access variables defined in higher scopes. + let sum = value + increment; + sum } + // We can't access the variable `sum` here, as it's out of scope. } } // [!endregion contract] #[cfg(test)] mod test { - use super::{ - LocalVariablesExample, ILocalVariablesExampleDispatcher, - ILocalVariablesExampleDispatcherTrait, - }; - use starknet::syscalls::deploy_syscall; + use super::LocalVariablesContract; + use super::LocalVariablesContract::do_something; #[test] - fn test_can_deploy_and_do_something() { - let (contract_address, _) = deploy_syscall( - LocalVariablesExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); - - let contract = ILocalVariablesExampleDispatcher { contract_address }; + fn test_can_do_something() { + let mut state = LocalVariablesContract::contract_state_for_testing(); let value = 10; - let res = contract.do_something(value); - assert_eq!(res, value + 10); + assert_eq!(do_something(@state, value), value + 10); } } diff --git a/listings/getting-started/variables/src/storage_variables.cairo b/listings/getting-started/variables/src/storage_variables.cairo index 3369445e..342a7f00 100644 --- a/listings/getting-started/variables/src/storage_variables.cairo +++ b/listings/getting-started/variables/src/storage_variables.cairo @@ -1,25 +1,26 @@ +// [!region contract] #[starknet::interface] -pub trait IStorageVariableExample { +trait IStorageVariable { fn set(ref self: TContractState, value: u32); fn get(self: @TContractState) -> u32; } -// [!region contract] #[starknet::contract] -pub mod StorageVariablesExample { +mod StorageVariablesContract { // You need to import these storage functions to read and write to storage variables use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + use super::IStorageVariable; // All storage variables are contained in a struct called Storage // annotated with the `#[storage]` attribute #[storage] struct Storage { // Storage variable holding a number - pub value: u32, + value: u32, } #[abi(embed_v0)] - impl StorageVariablesExample of super::IStorageVariableExample { + impl StorageVariables of IStorageVariable { // Write to storage variables by sending a transaction // that calls an external function fn set(ref self: ContractState, value: u32) { @@ -36,31 +37,18 @@ pub mod StorageVariablesExample { #[cfg(test)] mod test { - use super::{ - StorageVariablesExample, IStorageVariableExampleDispatcher, - IStorageVariableExampleDispatcherTrait, - }; - use starknet::syscalls::deploy_syscall; - use starknet::testing::set_contract_address; - use starknet::storage::StoragePointerReadAccess; + use super::{IStorageVariableDispatcher, IStorageVariableDispatcherTrait}; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; #[test] fn test_can_deploy_and_mutate_storage() { - let (contract_address, _) = deploy_syscall( - StorageVariablesExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); - - let contract = IStorageVariableExampleDispatcher { contract_address }; + let contract = declare("StorageVariablesContract").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); + let contract = IStorageVariableDispatcher { contract_address }; let initial_value = 10; contract.set(initial_value); assert_eq!(contract.get(), initial_value); - - // With contract state directly - let state = @StorageVariablesExample::contract_state_for_testing(); - set_contract_address(contract_address); - assert_eq!(state.value.read(), initial_value); } } From b33bbfd05ec9a51300ffb8d02e4d76beeded2b44 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:41:11 +0100 Subject: [PATCH 20/44] feat: rework variables --- Scarb.lock | 3 ++ pages/getting-started/basics/variables.md | 63 +++++++++++++++-------- routes.ts | 8 +-- 3 files changed, 48 insertions(+), 26 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index 4f571cb7..feccab33 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -339,6 +339,9 @@ version = "0.1.0" [[package]] name = "variables" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "visibility" diff --git a/pages/getting-started/basics/variables.md b/pages/getting-started/basics/variables.md index ead4d571..725e44e1 100644 --- a/pages/getting-started/basics/variables.md +++ b/pages/getting-started/basics/variables.md @@ -1,24 +1,32 @@ # Variables -There are 3 types of variables in Cairo contracts: - -- Local - - declared inside a function - - not stored on the blockchain -- Storage - - declared in the [Storage](/getting-started/basics/storage) of a contract - - can be accessed from one execution to another -- Global - - provides information about the blockchain - - accessed anywhere, even within library functions +Cairo contracts support three types of variables, each serving a different purpose: + +1. **Local Variables** + - Temporary variables within functions + - Exist only during function execution + - Not stored on the blockchain + +2. **Storage Variables** + - Defined in the contract's [Storage](/getting-started/basics/storage) + - Persist between contract executions + - Stored on the blockchain + +3. **Global Variables** + - Provide blockchain context and information + - Accessible anywhere in the contract + - Read-only system variables ## Local Variables -Local variables are used and accessed within the scope of a specific function or block of code. They are temporary and exist only for the duration of that particular function or block execution. +Local variables are temporary variables that exist only within their defined scope (a function or code block). Key characteristics: -Local variables are stored in memory and are not stored on the blockchain. This means they cannot be accessed from one execution to another. Local variables are useful for storing temporary data that is relevant only within a specific context. They also make the code more readable by giving names to intermediate values. +- Stored in memory, not on the blockchain +- Used for intermediate calculations and temporary data +- Available only during function execution +- Help improve code readability by naming values -Here's a simple example of a contract with only local variables: +Here's an example demonstrating local variable scope: ```cairo // [!include ~/listings/getting-started/variables/src/local_variables.cairo:contract] @@ -26,25 +34,36 @@ Here's a simple example of a contract with only local variables: ## Storage Variables -Storage variables are persistent data stored on the blockchain. They can be accessed from one execution to another, allowing the contract to remember and update information over time. See [Storage](/getting-started/basics/storage). - -To write or update a storage variable, you need to interact with the contract through an external entrypoint by sending a transaction. +Storage variables provide persistent state for your contract on the blockchain. They have these properties: -On the other hand, you can read state variables for free, without any transaction, simply by interacting with a node. +- Persist between contract executions +- Can be read for free (no transaction needed) +- Require a transaction to write to them +- Must be defined in the contract's Storage struct -Here's a simple example of a contract with one storage variable: +Here's an example showing storage variable usage: ```cairo // [!include ~/listings/getting-started/variables/src/storage_variables.cairo:contract] ``` +:::note +**Storage Access** + +- Reading: Free operation, no transaction needed +- Writing: Requires a transaction and costs gas + +::: + ## Global Variables -Global variables are predefined variables that provide information about the blockchain and the current execution environment. They can be accessed at any time and from anywhere! +Global variables provide access to blockchain context and system information. In Starknet: -In Starknet, you can access global variables by using specific functions from the Starknet core library. +- Accessed through core library functions +- Available anywhere in the contract +- Provide critical blockchain context (e.g., caller address, block info) -For example, the `get_caller_address` function returns the address of the caller of the current transaction, and the `get_contract_address` function returns the address of the current contract. +Example using global variables: ```cairo // [!include ~/listings/getting-started/variables/src/global_variables.cairo:contract] diff --git a/routes.ts b/routes.ts index 0faacdaf..6f7702ce 100644 --- a/routes.ts +++ b/routes.ts @@ -18,14 +18,14 @@ const config: Sidebar = [ text: "Storage", link: "/getting-started/basics/storage", }, - { - text: "Constructor", - link: "/getting-started/basics/constructor", - }, { text: "Variables", link: "/getting-started/basics/variables", }, + { + text: "Constructor", + link: "/getting-started/basics/constructor", + }, { text: "Visibility and Mutability", link: "/getting-started/basics/visibility-mutability", From 9455abf3d2908372034bafe44aab96e84cafcff1 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 14 Jan 2025 15:59:14 +0100 Subject: [PATCH 21/44] fix: simplify local variable --- .../getting-started/variables/src/local_variables.cairo | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/listings/getting-started/variables/src/local_variables.cairo b/listings/getting-started/variables/src/local_variables.cairo index 040ba0a2..43bcf8c0 100644 --- a/listings/getting-started/variables/src/local_variables.cairo +++ b/listings/getting-started/variables/src/local_variables.cairo @@ -4,7 +4,7 @@ mod LocalVariablesContract { #[storage] struct Storage {} - pub fn do_something(self: @ContractState, value: u32) -> u32 { + pub fn do_something(value: u32) -> u32 { // This variable is local to the current block. // It can't be accessed once it goes out of scope. let increment = 10; @@ -22,13 +22,11 @@ mod LocalVariablesContract { #[cfg(test)] mod test { - use super::LocalVariablesContract; use super::LocalVariablesContract::do_something; #[test] fn test_can_do_something() { - let mut state = LocalVariablesContract::contract_state_for_testing(); let value = 10; - assert_eq!(do_something(@state, value), value + 10); + assert_eq!(do_something(value), value + 10); } } From 6c419f518c098a78f832afd83de90d0b6b9cf186 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Thu, 16 Jan 2025 10:34:46 +0100 Subject: [PATCH 22/44] feat: migrate visibility to snforge --- Scarb.lock | 3 + .../getting-started/visibility/Scarb.toml | 3 +- .../visibility/src/visibility.cairo | 117 +++++++++--------- 3 files changed, 62 insertions(+), 61 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index feccab33..de4d40ad 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -346,6 +346,9 @@ dependencies = [ [[package]] name = "visibility" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "write_to_any_slot" diff --git a/listings/getting-started/visibility/Scarb.toml b/listings/getting-started/visibility/Scarb.toml index ec43ebaa..d313c951 100644 --- a/listings/getting-started/visibility/Scarb.toml +++ b/listings/getting-started/visibility/Scarb.toml @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/visibility/src/visibility.cairo b/listings/getting-started/visibility/src/visibility.cairo index 6143566c..a872346f 100644 --- a/listings/getting-started/visibility/src/visibility.cairo +++ b/listings/getting-started/visibility/src/visibility.cairo @@ -1,103 +1,100 @@ +// [!region contract] +// This trait defines the public interface of our contract +// All functions declared here will be accessible externally #[starknet::interface] -pub trait IExampleContract { +trait ContractInterface { fn set(ref self: TContractState, value: u32); fn get(self: @TContractState) -> u32; } -// [!region contract] #[starknet::contract] -pub mod ExampleContract { +mod Contract { use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; + use super::ContractInterface; #[storage] - struct Storage { + pub struct Storage { pub value: u32, } - // The `#[abi(embed_v0)]` attribute indicates that all - // the functions in this implementation can be called externally. - // Omitting this attribute would make all the functions internal. + // External Functions Implementation + // The `#[abi(embed_v0)]` attribute makes these functions callable from outside the contract + // This is where we implement our public interface defined in ContractInterface #[abi(embed_v0)] - impl ExampleContract of super::IExampleContract { - // The `set` function can be called externally - // because it is written inside an implementation marked as `#[abi(embed_v0)]`. - // It can modify the contract's state as it is passed as a reference. + pub impl ContractImpl of ContractInterface { + // External function that can modify state + // - Takes `ref self` to allow state modifications + // - Calls internal `increment` function to demonstrate internal function usage fn set(ref self: ContractState, value: u32) { - self.value.write(value); + self.value.write(increment(value)); } - // The `get` function can be called externally - // because it is written inside an implementation marked as `#[abi(embed_v0)]`. - // However, it can't modify the contract's state, as it is passed as a snapshot - // -> It's only a "view" function. + // External view function (cannot modify state) + // - Takes `@self` (snapshot) to prevent state modifications + // - Demonstrates calling an internal function (_read_value) fn get(self: @ContractState) -> u32 { - // We can call an internal function from any functions within the contract - PrivateFunctionsTrait::_read_value(self) + self._read_value() } } - // The lack of the `#[abi(embed_v0)]` attribute indicates that all the functions in - // this implementation can only be called internally. - // We name the trait `PrivateFunctionsTrait` to indicate that it is an - // internal trait allowing us to call internal functions. + // Internal Functions Implementation + // These functions can only be called from within the contract + // The #[generate_trait] attribute creates a trait for these internal functions #[generate_trait] - pub impl PrivateFunctions of PrivateFunctionsTrait { - // The `_read_value` function is outside the implementation that is - // marked as `#[abi(embed_v0)]`, so it's an _internal_ function - // and can only be called from within the contract. - // However, it can't modify the contract's state, as it is passed - // as a snapshot: it is only a "view" function. + pub impl Internal of InternalTrait { + // Internal view function + // - Takes `@self` as it only needs to read state + // - Can only be called by other functions within the contract fn _read_value(self: @ContractState) -> u32 { self.value.read() } } + + // Pure Internal Function + // - Doesn't access contract state + // - Defined directly in the contract body + // - Considered good practice to keep pure functions outside impl blocks + // It's also possible to use ContractState here, but it's not recommended + // as it'll require to pass the state as a parameter + pub fn increment(value: u32) -> u32 { + value + 1 + } } // [!endregion contract] #[cfg(test)] mod test { - use super::{ExampleContract, IExampleContractDispatcher, IExampleContractDispatcherTrait}; - use starknet::syscalls::deploy_syscall; use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - - // These imports will allow us to directly access and set the contract state: - // - for `PrivateFunctionsTrait` internal functions access - // implementation need to be public to be able to access it - use super::ExampleContract::PrivateFunctionsTrait; - // to set the contract address for the state - // and also be able to use the dispatcher on the same contract - use starknet::testing::set_contract_address; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; + use super::{ContractInterfaceDispatcher, ContractInterfaceDispatcherTrait}; + use super::Contract; + use super::Contract::{InternalTrait, increment}; #[test] - fn can_call_set_and_get() { - let (contract_address, _) = deploy_syscall( - ExampleContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); + fn test_external_functions() { + // Deploy the contract + let contract = declare("Contract").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); - // You can interact with the external entrypoints of the contract using the dispatcher. - let contract = IExampleContractDispatcher { contract_address }; - // But for internal functions, you need to use the contract state. - let mut state = ExampleContract::contract_state_for_testing(); - set_contract_address(contract_address); + // Create contract interface for external calls + let contract = ContractInterfaceDispatcher { contract_address }; - // The contract dispatcher and state refer to the same contract. - assert_eq!(contract.get(), state.value.read()); - - // We can set from the dispatcher + // Test external function that modifies state contract.set(42); - assert_eq!(contract.get(), state.value.read()); - assert_eq!(42, state.value.read()); - assert_eq!(42, contract.get()); + assert_eq!(43, contract.get()); // Value is incremented + } + + #[test] + fn test_internal_functions() { + // Create contract state for internal function access + let mut state = Contract::contract_state_for_testing(); - // Or directly from the state for more complex operations + // Test direct state modification state.value.write(24); - assert_eq!(contract.get(), state.value.read()); assert_eq!(24, state.value.read()); - assert_eq!(24, contract.get()); - // We can also access internal functions from the state + // Test internal function access assert_eq!(state._read_value(), state.value.read()); - assert_eq!(state._read_value(), contract.get()); + assert_eq!(25, increment(24)); } } From bb3e7e0569acb87308d0d1fa2c309ca8fcab471a Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Thu, 16 Jan 2025 13:12:26 +0100 Subject: [PATCH 23/44] feat: rework visibility --- .../basics/visibility-mutability.md | 79 +++++++++++++++---- routes.ts | 8 +- 2 files changed, 68 insertions(+), 19 deletions(-) diff --git a/pages/getting-started/basics/visibility-mutability.md b/pages/getting-started/basics/visibility-mutability.md index 3d4a57f9..aad460e2 100644 --- a/pages/getting-started/basics/visibility-mutability.md +++ b/pages/getting-started/basics/visibility-mutability.md @@ -1,29 +1,78 @@ -# Visibility and Mutability +# Interfaces, Visibility and Mutability -## Visibility +## Function Visibility -There are two types of functions in Starknet contracts: +In Starknet contracts, functions can have two types of visibility: -- Functions that are accessible externally and can be called by anyone. -- Functions that are only accessible internally and can only be called by other functions in the contract. - -These functions are also typically divided into two different implementation blocks. The first `impl` block for externally accessible functions is explicitly annotated with an `#[abi(embed_v0)]` attribute. This indicates that all the functions inside this block can be called either as a transaction or as a view function. The second `impl` block for internally accessible functions is not annotated with any attribute, which means that all the functions inside this block are private by default. +- **External Functions**: Can be called by anyone, including other contracts and users +- **Internal Functions**: Can only be called by other functions within the same contract ## State Mutability -Regardless of whether a function is internal or external, it can either modify the contract's state or not. When we declare functions that interact with storage variables inside a smart contract, -we need to explicitly state that we are accessing the `ContractState` by adding it as the first parameter of the function. This can be done in two different ways: +Every function in a contract can either modify or just read the contract's state. This behavior is determined by how we pass the `ContractState` parameter: + +- **State-Modifying Functions**: Use `ref self: ContractState` + - Can read and write to storage + - Require a transaction to execute + - Cost gas to run + +- **View Functions**: Use `self: @ContractState` + - Can only read from storage + - Can be called directly through an RPC node + - Free to call (no transaction needed) + +:::note +Internal functions follow the same state mutability rules as external functions. The only difference is who can call them. +::: + +## Implementation + +### External Functions + +For external functions (both state-modifying and view), you need: + +1. **Interface Definition** + - Defined with `#[starknet::interface]` attribute + - Lists all functions that can be called externally + - Functions can be called as transactions or view calls + - Part of the contract's public API -- If we want our function to be able to mutate the state of the contract, we pass it by reference like this: `ref self: ContractState` -- If we want our function to be read-only and not mutate the state of the contract, we pass it by snapshot like this: `self: @ContractState` +2. **Interface Implementation** + - Uses `#[abi(embed_v0)]` attribute + - Becomes part of the contract's ABI (Application Binary Interface) + - ABI defines how to interact with the contract from outside + - Must implement all functions defined in the interface -Read-only functions, also called view functions, can be directly called without making a transaction. You can interact with them directly through an RPC node to read the contract's state, and they're free to call! -External functions, that modify the contract's state, on the other hand, can only be called by making a transaction. +### Internal Functions -Internal functions can't be called externally, but the same principle applies regarding state mutability. +For internal functions, there are two options: -Let's take a look at a simple example contract to see these in action: +1. **Implementation Block** + - Can use `#[generate_trait]` attribute + - Recommended for functions that need `ContractState` access + - Sometimes prefixed with `_` to indicate internal use + +2. **Direct Contract Body** + - Functions defined directly in the contract + - Recommended for pure functions + - Useful for helper functions and calculations + +## Example + +Here's a complete example demonstrating these concepts: ```cairo // [!include ~/listings/getting-started/visibility/src/visibility.cairo:contract] ``` + +:::note +**Multiple Implementations** + +Cairo contracts can implement multiple interfaces and have multiple internal implementation blocks. This is not only possible but recommended because it: + +- Keeps each implementation block focused on a single responsibility +- Makes the code more maintainable and easier to test +- Simplifies the implementation of standard interfaces +- Allows for better organization of related functionality + +::: diff --git a/routes.ts b/routes.ts index 6f7702ce..70b18183 100644 --- a/routes.ts +++ b/routes.ts @@ -18,6 +18,10 @@ const config: Sidebar = [ text: "Storage", link: "/getting-started/basics/storage", }, + { + text: "Interfaces, Visibility and Mutability", + link: "/getting-started/basics/visibility-mutability", + }, { text: "Variables", link: "/getting-started/basics/variables", @@ -26,10 +30,6 @@ const config: Sidebar = [ text: "Constructor", link: "/getting-started/basics/constructor", }, - { - text: "Visibility and Mutability", - link: "/getting-started/basics/visibility-mutability", - }, { text: "Counter Example", link: "/getting-started/basics/counter", From 4632562a7a2a6da4fe8cb50add2b19f0aded7ca5 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:52:13 +0100 Subject: [PATCH 24/44] feat: migrate counter to snforge --- Scarb.lock | 3 +++ listings/getting-started/counter/Scarb.toml | 3 ++- .../getting-started/counter/src/counter.cairo | 17 +++++++---------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index de4d40ad..6b3fd50b 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -71,6 +71,9 @@ dependencies = [ [[package]] name = "counter" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "crowdfunding" diff --git a/listings/getting-started/counter/Scarb.toml b/listings/getting-started/counter/Scarb.toml index 3979e167..fa07006f 100644 --- a/listings/getting-started/counter/Scarb.toml +++ b/listings/getting-started/counter/Scarb.toml @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/counter/src/counter.cairo b/listings/getting-started/counter/src/counter.cairo index 593d2342..bf205d3c 100644 --- a/listings/getting-started/counter/src/counter.cairo +++ b/listings/getting-started/counter/src/counter.cairo @@ -13,7 +13,7 @@ pub mod SimpleCounter { #[storage] struct Storage { // Counter variable - pub counter: u128, + counter: u128, } #[constructor] @@ -45,17 +45,14 @@ pub mod SimpleCounter { #[cfg(test)] mod test { - use super::{SimpleCounter, ISimpleCounterDispatcher, ISimpleCounterDispatcherTrait}; - use starknet::syscalls::deploy_syscall; + use super::{ISimpleCounterDispatcher, ISimpleCounterDispatcherTrait}; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; fn deploy(init_value: u128) -> ISimpleCounterDispatcher { - let (contract_address, _) = deploy_syscall( - SimpleCounter::TEST_CLASS_HASH.try_into().unwrap(), - 0, - array![init_value.into()].span(), - false, - ) - .unwrap(); + let contract = declare("SimpleCounter").unwrap().contract_class(); + let mut constructor_calldata = array![]; + init_value.serialize(ref constructor_calldata); + let (contract_address, _) = contract.deploy(@constructor_calldata).unwrap(); ISimpleCounterDispatcher { contract_address } } From 4d474364d1df837d516abb869e619a9f71363616 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:33:49 +0100 Subject: [PATCH 25/44] fix: remove pub visibility for counter contract --- listings/getting-started/counter/src/counter.cairo | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/listings/getting-started/counter/src/counter.cairo b/listings/getting-started/counter/src/counter.cairo index bf205d3c..ed538eb1 100644 --- a/listings/getting-started/counter/src/counter.cairo +++ b/listings/getting-started/counter/src/counter.cairo @@ -1,5 +1,5 @@ #[starknet::interface] -pub trait ISimpleCounter { +trait ISimpleCounter { fn get_current_count(self: @TContractState) -> u128; fn increment(ref self: TContractState); fn decrement(ref self: TContractState); @@ -7,7 +7,7 @@ pub trait ISimpleCounter { // [!region contract] #[starknet::contract] -pub mod SimpleCounter { +mod SimpleCounter { use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; #[storage] From b8120c9af4c1cd02dd7e828edf59225e94ef07a8 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:34:12 +0100 Subject: [PATCH 26/44] feat: migrate mappings to snforge --- Scarb.lock | 3 ++ listings/getting-started/mappings/Scarb.toml | 3 +- .../mappings/src/mappings.cairo | 33 +++++++++++-------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index 6b3fd50b..57afc518 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -127,6 +127,9 @@ version = "0.1.0" [[package]] name = "mappings" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "merkle_tree" diff --git a/listings/getting-started/mappings/Scarb.toml b/listings/getting-started/mappings/Scarb.toml index b5a30f8a..51b8de05 100644 --- a/listings/getting-started/mappings/Scarb.toml +++ b/listings/getting-started/mappings/Scarb.toml @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/mappings/src/mappings.cairo b/listings/getting-started/mappings/src/mappings.cairo index 7a4aa932..cf94d12f 100644 --- a/listings/getting-started/mappings/src/mappings.cairo +++ b/listings/getting-started/mappings/src/mappings.cairo @@ -1,24 +1,25 @@ use starknet::ContractAddress; #[starknet::interface] -pub trait IMapContract { +trait IMapContract { fn set(ref self: TContractState, key: ContractAddress, value: felt252); fn get(self: @TContractState, key: ContractAddress) -> felt252; } // [!region contract] #[starknet::contract] -pub mod MapContract { +mod MapContract { + use super::IMapContract; use starknet::ContractAddress; use starknet::storage::{Map, StorageMapReadAccess, StorageMapWriteAccess}; #[storage] struct Storage { - map: Map::, + map: Map, } #[abi(embed_v0)] - impl MapContractImpl of super::IMapContract { + impl MapContractImpl of IMapContract { fn set(ref self: ContractState, key: ContractAddress, value: felt252) { self.map.write(key, value); } @@ -32,23 +33,27 @@ pub mod MapContract { #[cfg(test)] mod test { - use super::{MapContract, IMapContractDispatcher, IMapContractDispatcherTrait}; - use starknet::syscalls::deploy_syscall; + use super::{IMapContractDispatcher, IMapContractDispatcherTrait}; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; + use starknet::contract_address_const; + + fn deploy() -> IMapContractDispatcher { + let contract = declare("MapContract").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); + IMapContractDispatcher { contract_address } + } #[test] fn test_deploy_and_set_get() { - let (contract_address, _) = deploy_syscall( - MapContract::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); - let mut contract = IMapContractDispatcher { contract_address }; + let contract = deploy(); // Write to map. + let key = contract_address_const::<'key'>(); let value: felt252 = 1; - contract.set(key: contract_address, value: value); + contract.set(key, value); // Read from map. - let read_value = contract.get(contract_address); - assert(read_value == 1, 'wrong value read'); + let read_value = contract.get(key); + assert_eq!(read_value, value); } } From 4d9e92884fb01ce67f2d4949b4d4ccc26e3fed03 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:34:46 +0100 Subject: [PATCH 27/44] feat: rework mappings --- pages/getting-started/basics/mappings.md | 34 +++++++++++++++++++----- routes.ts | 8 +++--- 2 files changed, 32 insertions(+), 10 deletions(-) diff --git a/pages/getting-started/basics/mappings.md b/pages/getting-started/basics/mappings.md index c9754e97..e3d48f35 100644 --- a/pages/getting-started/basics/mappings.md +++ b/pages/getting-started/basics/mappings.md @@ -1,15 +1,37 @@ # Mappings -Maps are a key-value data structure used to store data within a smart contract. In Cairo they are implemented using the `Map` type. It's important to note that the `Map` type can only be used inside the `Storage` struct of a contract and that it can't be used elsewhere. +Maps are a fundamental key-value data structure in Cairo smart contracts that allow you to store and retrieve values using unique keys. The `Map` type in `starknet::storage` is specifically designed for contract storage for this purpose. -Here we demonstrate how to use the `Map` type within a Cairo contract, to map between a key of type `ContractAddress` and value of type `felt252`. The key-value types are specified within angular brackets <>. We write to the map by calling the `write()` method, passing in both the key and value. Similarly, we can read the value associated with a given key by calling the `read()` method and passing in the relevant key. +Here's a simple example that demonstrates how to use a `Map`: -Some additional notes: +```cairo +// [!include ~/listings/getting-started/mappings/src/mappings.cairo:contract] +``` + +Let's break down the key components: + +- **Declaration**: Maps are declared using `Map` syntax +- **Storage**: Maps must be declared inside the contract's `Storage` struct + - You need to import the `StorageMapReadAccess` and `StorageMapWriteAccess` traits from `starknet::storage` +- **Operations**: + - `write(key, value)`: Stores a value for a given key + - `read(key)`: Retrieves the value associated with a key +- Maps automatically initialize all values to zero +- Keys and values must be of valid storage types, see [Storing Custom Types](/getting-started/basics/storing-custom-types) -- More complex key-value mappings are possible, for example we could use `Map::<(ContractAddress, ContractAddress), felt252>` to create an allowance on an ERC20 token contract. +### Composite Keys -- In mappings, the address of the value at key $k_1,...,k_n$ is $\text{h}(...\text{h}(\text{h}(\text{sn\_keccak}(name),k_1),k_2),...,k_n)$ where $\text{h}$ is the Pedersen hash and the final value is taken $(\bmod {2^{251}} - 256~)$. You can learn more about the contract storage layout in the [Starknet Documentation](https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/contract-storage/#storage_variables). +For more complex scenarios, you can use composite keys by combining multiple values: ```cairo -// [!include ~/listings/getting-started/mappings/src/mappings.cairo:contract] +// Example: ERC20 allowance mapping +Map<(ContractAddress, ContractAddress), felt252> // (owner, spender) -> amount ``` + +### Storage Layout (advanced) + +Under the hood, Cairo maps use a deterministic storage layout: + +- Each key-value pair is stored at a unique address calculated using Pedersen hashes +- The address formula is: $\text{h}(...\text{h}(\text{h}(\text{sn\_keccak}(name),k_1),k_2),...,k_n)$ mod $2^{251} - 256$ +- Learn more in the [Starknet Documentation](https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/contract-storage/#storage_variables) diff --git a/routes.ts b/routes.ts index 70b18183..80e6a99d 100644 --- a/routes.ts +++ b/routes.ts @@ -34,10 +34,6 @@ const config: Sidebar = [ text: "Counter Example", link: "/getting-started/basics/counter", }, - { - text: "Mappings", - link: "/getting-started/basics/mappings", - }, { text: "Errors", link: "/getting-started/basics/errors", @@ -58,6 +54,10 @@ const config: Sidebar = [ text: "Storing Custom Types", link: "/getting-started/basics/storing-custom-types", }, + { + text: "Mappings", + link: "/getting-started/basics/mappings", + }, { text: "Custom types in entrypoints", link: "/getting-started/basics/custom-types-in-entrypoints", From e1908dab035bdfeedee4d7ef759adc578b768081 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:10:21 +0100 Subject: [PATCH 28/44] remove ByteArray/String chapter --- listings/getting-started/bytearray/.gitignore | 1 - listings/getting-started/bytearray/Scarb.lock | 6 -- listings/getting-started/bytearray/Scarb.toml | 15 ----- .../bytearray/src/bytearray.cairo | 55 ------------------- .../getting-started/bytearray/src/lib.cairo | 1 - .../basics/bytearrays-strings.md | 45 --------------- routes.ts | 4 -- 7 files changed, 127 deletions(-) delete mode 100644 listings/getting-started/bytearray/.gitignore delete mode 100644 listings/getting-started/bytearray/Scarb.lock delete mode 100644 listings/getting-started/bytearray/Scarb.toml delete mode 100644 listings/getting-started/bytearray/src/bytearray.cairo delete mode 100644 listings/getting-started/bytearray/src/lib.cairo delete mode 100644 pages/getting-started/basics/bytearrays-strings.md diff --git a/listings/getting-started/bytearray/.gitignore b/listings/getting-started/bytearray/.gitignore deleted file mode 100644 index 1de56593..00000000 --- a/listings/getting-started/bytearray/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target \ No newline at end of file diff --git a/listings/getting-started/bytearray/Scarb.lock b/listings/getting-started/bytearray/Scarb.lock deleted file mode 100644 index 60e3a935..00000000 --- a/listings/getting-started/bytearray/Scarb.lock +++ /dev/null @@ -1,6 +0,0 @@ -# Code generated by scarb DO NOT EDIT. -version = 1 - -[[package]] -name = "constructor" -version.workspace = true diff --git a/listings/getting-started/bytearray/Scarb.toml b/listings/getting-started/bytearray/Scarb.toml deleted file mode 100644 index 0ed5aa06..00000000 --- a/listings/getting-started/bytearray/Scarb.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "bytearray" -version.workspace = true -edition.workspace = true - -[dependencies] -starknet.workspace = true - -[dev-dependencies] -cairo_test.workspace = true - -[scripts] -test.workspace = true - -[[target.starknet-contract]] diff --git a/listings/getting-started/bytearray/src/bytearray.cairo b/listings/getting-started/bytearray/src/bytearray.cairo deleted file mode 100644 index 03911b70..00000000 --- a/listings/getting-started/bytearray/src/bytearray.cairo +++ /dev/null @@ -1,55 +0,0 @@ -#[starknet::interface] -pub trait IMessage { - fn append(ref self: TContractState, str: ByteArray); - fn prepend(ref self: TContractState, str: ByteArray); -} - -// [!region contract] -#[starknet::contract] -pub mod MessageContract { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - - #[storage] - struct Storage { - pub message: ByteArray, - } - - #[constructor] - fn constructor(ref self: ContractState) { - self.message.write("World!"); - } - - #[abi(embed_v0)] - impl MessageContract of super::IMessage { - fn append(ref self: ContractState, str: ByteArray) { - self.message.write(self.message.read() + str); - } - - fn prepend(ref self: ContractState, str: ByteArray) { - self.message.write(str + self.message.read()); - } - } -} -// [!endregion contract] - -#[cfg(test)] -mod tests { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use bytearray::bytearray::{MessageContract, IMessage}; - - #[test] - #[available_gas(2000000000)] - fn message_contract_tests() { - let mut state = MessageContract::contract_state_for_testing(); - state.message.write("World!"); - - let message = state.message.read(); - assert(message == "World!", 'wrong message'); - - state.append(" Good day, sir!"); - assert(state.message.read() == "World! Good day, sir!", 'wrong message (append)'); - - state.prepend("Hello, "); - assert(state.message.read() == "Hello, World! Good day, sir!", 'wrong message (prepend)'); - } -} diff --git a/listings/getting-started/bytearray/src/lib.cairo b/listings/getting-started/bytearray/src/lib.cairo deleted file mode 100644 index f5e70c2b..00000000 --- a/listings/getting-started/bytearray/src/lib.cairo +++ /dev/null @@ -1 +0,0 @@ -mod bytearray; diff --git a/pages/getting-started/basics/bytearrays-strings.md b/pages/getting-started/basics/bytearrays-strings.md deleted file mode 100644 index 9ea7db86..00000000 --- a/pages/getting-started/basics/bytearrays-strings.md +++ /dev/null @@ -1,45 +0,0 @@ -# Strings and ByteArrays - -In Cairo, there's no native type for strings. Instead, you can use a single `felt252` to store a short string or a `ByteArray` for strings of arbitrary length. - -## Short strings - -Each character is encoded on 8 bits following the ASCII standard, so it's possible to store up to 31 characters in a single `felt252`. - -Short strings are declared with single quotes, like this: `'Hello, World!'`. -See the [Felt](/cairo_cheatsheet/felt) section for more information about short strings with the `felt252` type. - -:::note -Notice that any short string only use up to 31 bytes, so it's possible to represent any short string with `bytes31`. -::: - -## ByteArray (Long strings) - -The `ByteArray` struct is used to store strings of arbitrary length. It contains a field `data` of type `Array` to store a sequence of short strings. - -ByteArrays are declared with double quotes, like this: `"Hello, World!"`. - -They can be stored in the contract's storage and passed as arguments to entrypoints. - -```cairo -// [!include ~/listings/getting-started/bytearray/src/bytearray.cairo:contract] -``` - -### Operations - -ByteArrays also provide a set of operations that facilitate the manipulation of strings. -Here are the available operations on an instance of `ByteArray`: - -- `append(mut other: @ByteArray)` - Append another ByteArray to the current one. -- `append_word(word: felt252, len: usize)` - Append a short string to the ByteArray. You **need to ensure** that `len` is at most 31 and that `word` can be converted to a `bytes31` with maximum `len` bytes/characters. -- `append_byte(byte: felt252)` - Append a single byte/character to the end of the ByteArray. -- `len() -> usize` - Get the length of the ByteArray. -- `at(index: usize) -> Option` - Access the character at the given index. -- `rev() -> ByteArray` - Return a new ByteArray with the characters of the original one in reverse order. -- `append_word_rev(word: felt252, len: usize)` - Append a short string to the ByteArray in reverse order. You **need to ensure** again that `len` is at most 31 and that `word` can be converted to a `bytes31` with maximum `len` bytes/characters. - -Additionally, there are some operations that can be called as static functions: - -- `concat(left: @ByteArray, right: @ByteArray)` - Concatenate two ByteArrays. - -Concatenation of `ByteArray` (with `append(mut other: @ByteArray)`) can also be done with the `+` and `+=` operators directly, and access to a specific index can be done with the `[]` operator (with the maximum index being `len() - 1`). diff --git a/routes.ts b/routes.ts index 80e6a99d..2f0b226b 100644 --- a/routes.ts +++ b/routes.ts @@ -46,10 +46,6 @@ const config: Sidebar = [ text: "Syscalls", link: "/getting-started/basics/syscalls", }, - { - text: "Strings and ByteArrays", - link: "/getting-started/basics/bytearrays-strings", - }, { text: "Storing Custom Types", link: "/getting-started/basics/storing-custom-types", From e05dc64b0802d864cb2f85023715633a2673d097 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:10:46 +0100 Subject: [PATCH 29/44] feat: migrate errors to snforge --- Scarb.lock | 3 + listings/getting-started/errors/Scarb.toml | 3 +- .../errors/src/custom_errors.cairo | 32 +++++----- .../errors/src/simple_errors.cairo | 59 ++++++++++++------- .../errors/src/vault_errors.cairo | 28 ++++----- 5 files changed, 70 insertions(+), 55 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index 57afc518..536cdf05 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -99,6 +99,9 @@ version = "0.1.0" [[package]] name = "errors" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "events" diff --git a/listings/getting-started/errors/Scarb.toml b/listings/getting-started/errors/Scarb.toml index cc12bd89..c84833f8 100644 --- a/listings/getting-started/errors/Scarb.toml +++ b/listings/getting-started/errors/Scarb.toml @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/errors/src/custom_errors.cairo b/listings/getting-started/errors/src/custom_errors.cairo index b287514f..e75f5533 100644 --- a/listings/getting-started/errors/src/custom_errors.cairo +++ b/listings/getting-started/errors/src/custom_errors.cairo @@ -1,24 +1,24 @@ #[starknet::interface] -pub trait ICustomErrorsExample { +trait ICustomErrors { fn test_assert(self: @TContractState, i: u256); fn test_panic(self: @TContractState, i: u256); } // [!region contract] -pub mod Errors { +mod Errors { pub const NOT_POSITIVE: felt252 = 'must be greater than 0'; pub const NOT_NULL: felt252 = 'must not be null'; } #[starknet::contract] -pub mod CustomErrorsExample { - use super::Errors; +mod CustomErrorsContract { + use super::{Errors, ICustomErrors}; #[storage] struct Storage {} #[abi(embed_v0)] - impl CustomErrorsExample of super::ICustomErrorsExample { + impl CustomErrorsContract of ICustomErrors { fn test_assert(self: @ContractState, i: u256) { assert(i > 0, Errors::NOT_POSITIVE); } @@ -34,28 +34,24 @@ pub mod CustomErrorsExample { #[cfg(test)] mod test { - use super::{ - CustomErrorsExample, ICustomErrorsExampleDispatcher, ICustomErrorsExampleDispatcherTrait, - }; - use starknet::syscalls::deploy_syscall; - - fn deploy() -> ICustomErrorsExampleDispatcher { - let (contract_address, _) = deploy_syscall( - CustomErrorsExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); - ICustomErrorsExampleDispatcher { contract_address } + use super::{ICustomErrorsDispatcher, ICustomErrorsDispatcherTrait}; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; + + fn deploy() -> ICustomErrorsDispatcher { + let contract = declare("CustomErrorsContract").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); + ICustomErrorsDispatcher { contract_address } } #[test] - #[should_panic(expected: ('must not be null', 'ENTRYPOINT_FAILED'))] + #[should_panic(expected: 'must not be null')] fn should_panic() { let contract = deploy(); contract.test_panic(0); } #[test] - #[should_panic(expected: ('must be greater than 0', 'ENTRYPOINT_FAILED'))] + #[should_panic(expected: 'must be greater than 0')] fn should_assert() { let contract = deploy(); contract.test_assert(0); diff --git a/listings/getting-started/errors/src/simple_errors.cairo b/listings/getting-started/errors/src/simple_errors.cairo index 1477e1c8..bae0f5b4 100644 --- a/listings/getting-started/errors/src/simple_errors.cairo +++ b/listings/getting-started/errors/src/simple_errors.cairo @@ -1,28 +1,35 @@ #[starknet::interface] -pub trait IErrorsExample { +trait IErrors { fn test_assert(self: @TContractState, i: u256); fn test_panic(self: @TContractState, i: u256); } // [!region contract] #[starknet::contract] -pub mod ErrorsExample { +mod ErrorsContract { + use super::IErrors; + #[storage] struct Storage {} #[abi(embed_v0)] - impl ErrorsExample of super::IErrorsExample { + impl ErrorsContract of IErrors { + // Assert used to validate a condition + // and abort execution if the condition is not met fn test_assert(self: @ContractState, i: u256) { - // Assert used to validate a condition - // and abort execution if the condition is not met assert(i > 0, 'i must be greater than 0'); + let x = 10; + assert!(i > x, "i must be greater than {}", x); } + // Panic used to abort execution directly fn test_panic(self: @ContractState, i: u256) { if (i == 0) { - // Panic used to abort execution directly core::panic_with_felt252('i must not be 0'); } + if (i < 10) { + panic!("i: {} must be greater than 10", i); + } } } } @@ -30,28 +37,40 @@ pub mod ErrorsExample { #[cfg(test)] mod test { - use super::{ErrorsExample, IErrorsExampleDispatcher, IErrorsExampleDispatcherTrait}; - use starknet::syscalls::deploy_syscall; - - fn deploy() -> IErrorsExampleDispatcher { - let (contract_address, _) = deploy_syscall( - ErrorsExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); - IErrorsExampleDispatcher { contract_address } + use super::{IErrorsDispatcher, IErrorsDispatcherTrait}; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; + + fn deploy() -> IErrorsDispatcher { + let contract = declare("ErrorsContract").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); + IErrorsDispatcher { contract_address } } #[test] - #[should_panic(expected: ('i must not be 0', 'ENTRYPOINT_FAILED'))] - fn should_panic() { + #[should_panic(expected: 'i must be greater than 0')] + fn should_assert_with_felt() { + let contract = deploy(); + contract.test_assert(0); + } + + #[test] + #[should_panic(expected: "i must be greater than 10")] + fn should_assert_with_byte_array() { + let contract = deploy(); + contract.test_assert(5); + } + + #[test] + #[should_panic(expected: 'i must not be 0')] + fn should_panic_with_felt() { let contract = deploy(); contract.test_panic(0); } #[test] - #[should_panic(expected: ('i must be greater than 0', 'ENTRYPOINT_FAILED'))] - fn should_assert() { + #[should_panic(expected: "i: 5 must be greater than 10")] + fn should_panic_with_byte_array() { let contract = deploy(); - contract.test_assert(0); + contract.test_panic(5); } } diff --git a/listings/getting-started/errors/src/vault_errors.cairo b/listings/getting-started/errors/src/vault_errors.cairo index 4da8a4e8..c9db40e3 100644 --- a/listings/getting-started/errors/src/vault_errors.cairo +++ b/listings/getting-started/errors/src/vault_errors.cairo @@ -1,19 +1,19 @@ #[starknet::interface] -pub trait IVaultErrorsExample { +trait IVaultErrors { fn deposit(ref self: TContractState, amount: u256); fn withdraw(ref self: TContractState, amount: u256); } // [!region contract] -pub mod VaultErrors { +mod VaultErrors { pub const INSUFFICIENT_BALANCE: felt252 = 'insufficient_balance'; // you can define more errors here } #[starknet::contract] -pub mod VaultErrorsExample { +mod VaultErrorsContract { use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - use super::VaultErrors; + use super::{VaultErrors, IVaultErrors}; #[storage] struct Storage { @@ -21,7 +21,7 @@ pub mod VaultErrorsExample { } #[abi(embed_v0)] - impl VaultErrorsExample of super::IVaultErrorsExample { + impl VaultErrorsContract of IVaultErrors { fn deposit(ref self: ContractState, amount: u256) { let mut balance = self.balance.read(); balance = balance + amount; @@ -48,17 +48,13 @@ pub mod VaultErrorsExample { #[cfg(test)] mod test { - use super::{ - VaultErrorsExample, IVaultErrorsExampleDispatcher, IVaultErrorsExampleDispatcherTrait, - }; - use starknet::syscalls::deploy_syscall; + use super::{IVaultErrorsDispatcher, IVaultErrorsDispatcherTrait}; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; - fn deploy() -> IVaultErrorsExampleDispatcher { - let (contract_address, _) = deploy_syscall( - VaultErrorsExample::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); - IVaultErrorsExampleDispatcher { contract_address } + fn deploy() -> IVaultErrorsDispatcher { + let contract = declare("VaultErrorsContract").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); + IVaultErrorsDispatcher { contract_address } } #[test] @@ -69,7 +65,7 @@ mod test { } #[test] - #[should_panic(expected: ('insufficient_balance', 'ENTRYPOINT_FAILED'))] + #[should_panic(expected: 'insufficient_balance')] fn should_panic_on_insufficient_balance() { let mut contract = deploy(); contract.deposit(10); From 41cdc06de0f3e912518007643aff32a27da61a4e Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:11:11 +0100 Subject: [PATCH 30/44] feat: rework errors --- pages/getting-started/basics/errors.md | 57 ++++++++++++++++++-------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/pages/getting-started/basics/errors.md b/pages/getting-started/basics/errors.md index 600985e9..0c0190c5 100644 --- a/pages/getting-started/basics/errors.md +++ b/pages/getting-started/basics/errors.md @@ -1,38 +1,63 @@ -# Errors +# Error Handling in Cairo -Errors can be used to handle validation and other conditions that may occur during the execution of a smart contract. -If an error is thrown during the execution of a smart contract call, the execution is stopped and any changes made during the transaction are reverted. +Cairo provides robust error handling mechanisms for smart contracts. When an error occurs during contract execution, the transaction is immediately reverted and all state changes are undone. -To throw an error, use the `assert` or `panic` functions: +## Basic Error Functions -- `assert` is used to validate conditions. - If the check fails, an error is thrown along with a specified value, often a message. - It's similar to the `require` statement in Solidity. +Cairo offers two main functions for error handling: -- `panic` immediately halts the execution with the given error value. - It should be used for complex condition checks and for internal errors. It's similar to the `revert` statement in Solidity. - You can use `panic_with_felt252` to directly pass a `felt252` as the error value. +### 1. `assert` -The `assert_eq!`, `assert_ne!`, `assert_lt!`, `assert_le!`, `assert_gt!` and `assert_ge!` macros can be used as an `assert` shorthand to compare two values, but **only** in tests. In contracts, you should only use the `assert` function. +- Used for condition validation (similar to Solidity's `require`) +- Stops execution if the condition is false +- Supports two formats: -Here's a simple example that demonstrates the use of these functions: + ```cairo + assert(condition, 'error message'); // Basic assertion + assert!(condition, "formatted error: {}", x); // Formatted string error + ``` + +### 2. `panic` + +- Used for immediate execution halt (similar to Solidity's `revert`) +- Best for complex conditions or internal errors +- Supports multiple formats: + + ```cairo + panic_with_felt252('error message'); // Basic panic + panic!("formatted error: value={}", value); // Formatted string error + ``` + +:::warning +While Cairo provides assertion macros like `assert_eq!` and `assert_ne!`, these are **only for testing**. In contract code, always use the standard `assert` function. +::: + +## Simple Example + +Here's a basic example demonstrating both error handling approaches: ```cairo // [!include ~/listings/getting-started/errors/src/simple_errors.cairo:contract] ``` -## Custom errors +## Custom Error Codes -You can make error handling easier by defining your error codes in a specific module. +For better organization and consistency, you can define error messages in a dedicated module: ```cairo // [!include ~/listings/getting-started/errors/src/custom_errors.cairo:contract] ``` -## Vault example +## Real-World Example: Vault Contract -Here's another example that demonstrates the use of errors in a more complex contract: +Here's a practical example showing error handling in a vault contract that manages deposits and withdrawals: ```cairo // [!include ~/listings/getting-started/errors/src/vault_errors.cairo:contract] ``` + +In this example: + +1. Custom errors are defined in a separate module +2. The `withdraw` function demonstrates both `assert` and `panic` approaches +3. Balance checks protect against underflow conditions From 93845ffb69c9f89c8cd11f2d2b1da94e52e62316 Mon Sep 17 00:00:00 2001 From: Julio <30329843+julio4@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:20:51 +0100 Subject: [PATCH 31/44] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index bf09c9e4..ee29065f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Starknet by Example +Dev preview at: https://starknet-by-example-dev.voyager.online/ + ## Description Starknet by Example is a collection of examples of how to use the [Cairo](https://github.com/starkware-libs/cairo) programming language to create smart contracts on Starknet. From 93ee3fb3356e3a84a2aa47b3c02beb032c6b3e18 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Wed, 22 Jan 2025 13:32:43 +0100 Subject: [PATCH 32/44] feat: migrate events to snforge --- Scarb.lock | 7 +- listings/getting-started/events/Scarb.toml | 3 +- .../getting-started/events/src/counter.cairo | 110 ++++++++++-------- 3 files changed, 64 insertions(+), 56 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index 536cdf05..00726fac 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -18,10 +18,6 @@ dependencies = [ "snforge_std", ] -[[package]] -name = "bytearray" -version = "0.1.0" - [[package]] name = "cairo_cheatsheet" version = "0.1.0" @@ -106,6 +102,9 @@ dependencies = [ [[package]] name = "events" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "factory" diff --git a/listings/getting-started/events/Scarb.toml b/listings/getting-started/events/Scarb.toml index 35c9f343..3cd2e428 100644 --- a/listings/getting-started/events/Scarb.toml +++ b/listings/getting-started/events/Scarb.toml @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/events/src/counter.cairo b/listings/getting-started/events/src/counter.cairo index 612c81e5..e391961b 100644 --- a/listings/getting-started/events/src/counter.cairo +++ b/listings/getting-started/events/src/counter.cairo @@ -1,18 +1,37 @@ +// [!region contract] #[starknet::interface] -pub trait IEventCounter { +trait IEventCounter { fn increment(ref self: TContractState, amount: u128); } -// [!region contract] +mod Events { + // Events must derive the `starknet::Event` trait + #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] + pub struct CounterIncreased { + pub amount: u128, + } + + #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] + pub struct UserIncreaseCounter { + // The `#[key]` attribute indicates that this event will be indexed. + // You can also use `#[flat]` for nested structs. + #[key] + pub user: starknet::ContractAddress, + pub new_value: u128, + } +} + #[starknet::contract] -pub mod EventCounter { - use starknet::{get_caller_address, ContractAddress}; +mod EventCounter { + use super::IEventCounter; + use super::Events::*; + use starknet::get_caller_address; use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; #[storage] struct Storage { // Counter value - pub counter: u128, + counter: u128, } #[event] @@ -24,24 +43,8 @@ pub mod EventCounter { UserIncreaseCounter: UserIncreaseCounter, } - // By deriving the `starknet::Event` trait, we indicate to the compiler that - // this struct will be used when emitting events. - #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] - pub struct CounterIncreased { - pub amount: u128, - } - - #[derive(Copy, Drop, Debug, PartialEq, starknet::Event)] - pub struct UserIncreaseCounter { - // The `#[key]` attribute indicates that this event will be indexed. - // You can also use `#[flat]` for nested structs. - #[key] - pub user: ContractAddress, - pub new_value: u128, - } - #[abi(embed_v0)] - impl EventCounter of super::IEventCounter { + impl EventCounter of IEventCounter { fn increment(ref self: ContractState, amount: u128) { self.counter.write(self.counter.read() + amount); // Emit event @@ -64,44 +67,49 @@ pub mod EventCounter { #[cfg(test)] mod tests { use super::{ - EventCounter, EventCounter::{Event, CounterIncreased, UserIncreaseCounter}, - IEventCounterDispatcherTrait, IEventCounterDispatcher, + EventCounter::{Event, CounterIncreased, UserIncreaseCounter}, IEventCounterDispatcherTrait, + IEventCounterDispatcher, }; - use starknet::{contract_address_const, syscalls::deploy_syscall}; - use starknet::testing::set_contract_address; - use starknet::storage::StoragePointerReadAccess; + use starknet::contract_address_const; + + use snforge_std::{ + EventSpyAssertionsTrait, spy_events, start_cheat_caller_address, stop_cheat_caller_address, + ContractClassTrait, DeclareResultTrait, declare, + }; + + fn deploy() -> IEventCounterDispatcher { + let contract = declare("EventCounter").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); + IEventCounterDispatcher { contract_address } + } #[test] fn test_increment_events() { - let (contract_address, _) = deploy_syscall( - EventCounter::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); - let mut contract = IEventCounterDispatcher { contract_address }; - let state = @EventCounter::contract_state_for_testing(); - + let mut contract = deploy(); let amount = 10; let caller = contract_address_const::<'caller'>(); - // fake caller - set_contract_address(caller); + // [!region test_events] + let mut spy = spy_events(); + start_cheat_caller_address(contract.contract_address, caller); contract.increment(amount); - // set back to the contract for reading state - set_contract_address(contract_address); - assert_eq!(state.counter.read(), amount); + stop_cheat_caller_address(contract.contract_address); - // Notice the order: the first event emitted is the first to be popped. - // [!region test_events] - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some(Event::CounterIncreased(CounterIncreased { amount })), - ); + spy + .assert_emitted( + @array![ + ( + contract.contract_address, + Event::CounterIncreased(CounterIncreased { amount }), + ), + ( + contract.contract_address, + Event::UserIncreaseCounter( + UserIncreaseCounter { user: caller, new_value: amount }, + ), + ), + ], + ); // [!endregion test_events] - assert_eq!( - starknet::testing::pop_log(contract_address), - Option::Some( - Event::UserIncreaseCounter(UserIncreaseCounter { user: caller, new_value: amount }), - ), - ); } } From a4fa6b4492627ff372bc711b078ebb6b5b18d97d Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Thu, 23 Jan 2025 13:52:22 +0100 Subject: [PATCH 33/44] feat: rework events --- pages/getting-started/basics/events.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/pages/getting-started/basics/events.md b/pages/getting-started/basics/events.md index 4dabcd7a..06b12399 100644 --- a/pages/getting-started/basics/events.md +++ b/pages/getting-started/basics/events.md @@ -1,10 +1,26 @@ # Events -Events are a way to emit data from a contract. All events must be defined in the `Event` enum, which must be annotated with the `#[event]` attribute. -An event is defined as a struct that derives the `starknet::Event` trait. The fields of that struct correspond to the data that will be emitted. An event can be indexed for easy and fast access when querying the data at a later time by adding a `#[key]` attribute to a field member. +Events in Cairo smart contracts allow you to emit and record data on the Starknet blockchain. They are essential for tracking important state changes and providing transparency to users and other contracts. Events are also useful when building interfaces, to be notified about important state changes. -Here's a simple example of a contract that emits an event each time a counter is incremented by the `increment` function: +To use events in your contract: + +1. Create event structs that derive the `starknet::Event` trait +2. Define an `Event` enum in the contract, annotated with `#[event]`, where each variant is linked to an event struct +3. Emit events with the `emit` function + +You can make events searchable by adding the `#[key]` attribute to specific fields, which indexes them for efficient querying later. + +Events variant names and structs are recommended to be named consistently, even if it create some redundancy when emitting events. + +Here's a practical example of a contract that emits events when incrementing a counter: ```cairo // [!include ~/listings/getting-started/events/src/counter.cairo:contract] ``` + +:::note + +For better code organization, especially in larger contracts, you can define event structs outside of the contract module, as shown in the example here. +While this allows you to group related events in separate modules or files, remember that you must still include all event variants in the contract's `Event` enum. + +::: From c35893201783bac17ad938c92fde411cd2d3bcfb Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Thu, 23 Jan 2025 14:02:45 +0100 Subject: [PATCH 34/44] feat: migrate storing_custom_types to snforge --- Scarb.lock | 3 ++ .../storing_custom_types/Scarb.toml | 3 +- .../storing_custom_types/src/contract.cairo | 47 +++++++++---------- routes.ts | 12 ++--- 4 files changed, 33 insertions(+), 32 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index 00726fac..af2ff3d3 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -322,6 +322,9 @@ version = "0.1.0" [[package]] name = "storing_custom_types" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "struct_as_mapping_key" diff --git a/listings/getting-started/storing_custom_types/Scarb.toml b/listings/getting-started/storing_custom_types/Scarb.toml index 44f881b8..17eda441 100644 --- a/listings/getting-started/storing_custom_types/Scarb.toml +++ b/listings/getting-started/storing_custom_types/Scarb.toml @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/storing_custom_types/src/contract.cairo b/listings/getting-started/storing_custom_types/src/contract.cairo index cd2ad282..d5f6986a 100644 --- a/listings/getting-started/storing_custom_types/src/contract.cairo +++ b/listings/getting-started/storing_custom_types/src/contract.cairo @@ -1,30 +1,31 @@ +// [!region contract] #[starknet::interface] -pub trait IStoringCustomType { +trait IStoringCustomType { fn set_person(ref self: TContractState, person: Person); fn set_name(ref self: TContractState, name: felt252); } -// [!region contract] // Deriving the starknet::Store trait // allows us to store the `Person` struct in the contract's storage. #[derive(Drop, Serde, Copy, starknet::Store)] -pub struct Person { - pub age: u8, - pub name: felt252, +struct Person { + age: u8, + name: felt252, } #[starknet::contract] -pub mod StoringCustomType { +mod StoringCustomType { use starknet::storage::StoragePointerWriteAccess; use super::Person; + use super::IStoringCustomType; #[storage] struct Storage { - pub person: Person, + person: Person, } #[abi(embed_v0)] - impl StoringCustomType of super::IStoringCustomType { + impl StoringCustomType of IStoringCustomType { fn set_person(ref self: ContractState, person: Person) { self.person.write(person); } @@ -40,30 +41,26 @@ pub mod StoringCustomType { #[cfg(test)] mod tests { - use super::{IStoringCustomType, StoringCustomType, Person}; - use starknet::storage::StoragePointerReadAccess; + use super::{IStoringCustomTypeDispatcherTrait, IStoringCustomTypeDispatcher, Person}; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; + + fn deploy() -> IStoringCustomTypeDispatcher { + let contract = declare("StoringCustomType").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); + IStoringCustomTypeDispatcher { contract_address } + } + #[test] fn can_call_set_person() { - let mut state = StoringCustomType::contract_state_for_testing(); - + let mut contract = deploy(); let person = Person { age: 10, name: 'Joe' }; - - state.set_person(person); - - let read_person = state.person.read(); - - assert_eq!(person.age, read_person.age); - assert_eq!(person.name, read_person.name); + contract.set_person(person); } #[test] fn can_call_set_name() { - let mut state = StoringCustomType::contract_state_for_testing(); - - state.set_name('John'); - - let read_person = state.person.read(); - assert_eq!(read_person.name, 'John'); + let mut contract = deploy(); + contract.set_name('John'); } } diff --git a/routes.ts b/routes.ts index 2f0b226b..99e74560 100644 --- a/routes.ts +++ b/routes.ts @@ -42,21 +42,21 @@ const config: Sidebar = [ text: "Events", link: "/getting-started/basics/events", }, - { - text: "Syscalls", - link: "/getting-started/basics/syscalls", - }, { text: "Storing Custom Types", link: "/getting-started/basics/storing-custom-types", }, + { + text: "Custom Types in Entrypoints", + link: "/getting-started/basics/custom-types-in-entrypoints", + }, { text: "Mappings", link: "/getting-started/basics/mappings", }, { - text: "Custom types in entrypoints", - link: "/getting-started/basics/custom-types-in-entrypoints", + text: "Syscalls", + link: "/getting-started/basics/syscalls", }, { text: "Documentation", From c2c3c29aa6c00b60bcfb4088c13759f199fb0d69 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Thu, 23 Jan 2025 14:23:13 +0100 Subject: [PATCH 35/44] feat: rework storing_custom_types --- .../basics/storing-custom-types.md | 14 --------- .../basics/storing_custom_types.md | 29 +++++++++++++++++++ 2 files changed, 29 insertions(+), 14 deletions(-) delete mode 100644 pages/getting-started/basics/storing-custom-types.md create mode 100644 pages/getting-started/basics/storing_custom_types.md diff --git a/pages/getting-started/basics/storing-custom-types.md b/pages/getting-started/basics/storing-custom-types.md deleted file mode 100644 index c14093a1..00000000 --- a/pages/getting-started/basics/storing-custom-types.md +++ /dev/null @@ -1,14 +0,0 @@ -# Storing Custom Types - -While native types can be stored in a contract's storage without any additional work, custom types require a bit more work. This is because at compile time, the compiler does not know how to store custom types in storage. To solve this, we need to implement the `Store` trait for our custom type. It is enough to just derive this trait, unless our custom type contains arrays or dictionaries. - -```cairo -// [!include ~/listings/getting-started/storing_custom_types/src/contract.cairo:contract] -``` - -Note that it is also possible to individually access the members of the stored struct. -This is possible because deriving the `Store` trait also generates the corresponding `StoragePointer` for each member. - -```cairo -// [!include ~/listings/getting-started/storing_custom_types/src/contract.cairo:set_name] -``` diff --git a/pages/getting-started/basics/storing_custom_types.md b/pages/getting-started/basics/storing_custom_types.md new file mode 100644 index 00000000..842502d2 --- /dev/null +++ b/pages/getting-started/basics/storing_custom_types.md @@ -0,0 +1,29 @@ +# Storing Custom Types + +In Starknet contracts, storing custom types in contract storage requires implementing the `Store` trait. While native types (like `felt252`, `u128`, etc.) can be stored directly, custom types need this additional step to generate the necessary implementation on how to handle their storage. + +To make a custom type storable: + +1. Derive the `starknet::Store` trait for your struct +2. Add any other necessary traits like `Drop`, `Serde`, and `Copy` +3. Define your storage variables using the custom type + +Here's an example showing how to store a custom `Person` struct: + +```cairo +// [!include ~/listings/getting-started/storing_custom_types/src/contract.cairo:contract] +``` + +:::note + +For more complex types, you might need to implement the `Store` trait manually instead of deriving it. + +::: + +## Accessing Struct Members + +When you derive the `Store` trait, Cairo automatically generates the necessary storage pointers for each struct member. This allows you to access and modify individual fields of your stored struct directly: + +```cairo +// [!include ~/listings/getting-started/storing_custom_types/src/contract.cairo:set_name] +``` From d13e155d1fdcf98decbb9d4a06254474a4b8f804 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Fri, 24 Jan 2025 17:42:13 +0100 Subject: [PATCH 36/44] feat: migrate custom_type_entrypoints to snforge --- Scarb.lock | 5 ++- .../.gitignore | 0 .../Scarb.lock | 0 .../Scarb.toml | 5 ++- .../src/contract.cairo | 40 ++++++++----------- .../src/lib.cairo | 0 .../basics/custom-types-in-entrypoints.md | 2 +- 7 files changed, 24 insertions(+), 28 deletions(-) rename listings/getting-started/{custom_type_serde => custom_type_entrypoints}/.gitignore (100%) rename listings/getting-started/{custom_type_serde => custom_type_entrypoints}/Scarb.lock (100%) rename listings/getting-started/{custom_type_serde => custom_type_entrypoints}/Scarb.toml (66%) rename listings/getting-started/{custom_type_serde => custom_type_entrypoints}/src/contract.cairo (60%) rename listings/getting-started/{custom_type_serde => custom_type_entrypoints}/src/lib.cairo (100%) diff --git a/Scarb.lock b/Scarb.lock index af2ff3d3..34dddc6e 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -81,8 +81,11 @@ dependencies = [ ] [[package]] -name = "custom_type_serde" +name = "custom_type_entrypoints" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "ecdsa_verification" diff --git a/listings/getting-started/custom_type_serde/.gitignore b/listings/getting-started/custom_type_entrypoints/.gitignore similarity index 100% rename from listings/getting-started/custom_type_serde/.gitignore rename to listings/getting-started/custom_type_entrypoints/.gitignore diff --git a/listings/getting-started/custom_type_serde/Scarb.lock b/listings/getting-started/custom_type_entrypoints/Scarb.lock similarity index 100% rename from listings/getting-started/custom_type_serde/Scarb.lock rename to listings/getting-started/custom_type_entrypoints/Scarb.lock diff --git a/listings/getting-started/custom_type_serde/Scarb.toml b/listings/getting-started/custom_type_entrypoints/Scarb.toml similarity index 66% rename from listings/getting-started/custom_type_serde/Scarb.toml rename to listings/getting-started/custom_type_entrypoints/Scarb.toml index 1a3dfe62..e7d79c8d 100644 --- a/listings/getting-started/custom_type_serde/Scarb.toml +++ b/listings/getting-started/custom_type_entrypoints/Scarb.toml @@ -1,5 +1,5 @@ [package] -name = "custom_type_serde" +name = "custom_type_entrypoints" version.workspace = true edition.workspace = true @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/custom_type_serde/src/contract.cairo b/listings/getting-started/custom_type_entrypoints/src/contract.cairo similarity index 60% rename from listings/getting-started/custom_type_serde/src/contract.cairo rename to listings/getting-started/custom_type_entrypoints/src/contract.cairo index abd441ea..a6d4c42a 100644 --- a/listings/getting-started/custom_type_serde/src/contract.cairo +++ b/listings/getting-started/custom_type_entrypoints/src/contract.cairo @@ -1,27 +1,28 @@ +// [!region contract] #[starknet::interface] -pub trait ISerdeCustomType { +trait ISerdeCustomType { fn person_input(ref self: TContractState, person: Person); fn person_output(self: @TContractState) -> Person; } -// [!region contract] // Deriving the `Serde` trait allows us to use // the `Person` type as an entrypoint parameter and as a return value #[derive(Drop, Serde)] -pub struct Person { - pub age: u8, - pub name: felt252, +struct Person { + age: u8, + name: felt252, } #[starknet::contract] -pub mod SerdeCustomType { +mod SerdeCustomType { use super::Person; + use super::ISerdeCustomType; #[storage] struct Storage {} #[abi(embed_v0)] - impl SerdeCustomType of super::ISerdeCustomType { + impl SerdeCustomType of ISerdeCustomType { fn person_input(ref self: ContractState, person: Person) {} fn person_output(self: @ContractState) -> Person { @@ -33,40 +34,31 @@ pub mod SerdeCustomType { #[cfg(test)] mod tests { - use super::{ - SerdeCustomType, Person, ISerdeCustomTypeDispatcher, ISerdeCustomTypeDispatcherTrait, - }; - use starknet::syscalls::deploy_syscall; + use super::{ISerdeCustomTypeDispatcher, ISerdeCustomTypeDispatcherTrait, Person}; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; fn deploy() -> ISerdeCustomTypeDispatcher { - let (contract_address, _) = deploy_syscall( - SerdeCustomType::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); + let contract = declare("SerdeCustomType").unwrap().contract_class(); + let (contract_address, _) = contract.deploy(@array![]).unwrap(); ISerdeCustomTypeDispatcher { contract_address } } - #[test] - fn should_deploy() { - deploy(); - } - #[test] fn should_get_person_output() { let contract = deploy(); let expected_person = Person { age: 10, name: 'Joe' }; + let received_person = contract.person_output(); let age_received = received_person.age; let name_received = received_person.name; - assert(age_received == expected_person.age, 'Wrong age value'); - assert(name_received == expected_person.name, 'Wrong name value'); + assert_eq!(age_received, expected_person.age); + assert_eq!(name_received, expected_person.name); } #[test] - #[available_gas(2000000000)] fn should_call_person_input() { - let contract = deploy(); + let mut contract = deploy(); let expected_person = Person { age: 10, name: 'Joe' }; contract.person_input(expected_person); } diff --git a/listings/getting-started/custom_type_serde/src/lib.cairo b/listings/getting-started/custom_type_entrypoints/src/lib.cairo similarity index 100% rename from listings/getting-started/custom_type_serde/src/lib.cairo rename to listings/getting-started/custom_type_entrypoints/src/lib.cairo diff --git a/pages/getting-started/basics/custom-types-in-entrypoints.md b/pages/getting-started/basics/custom-types-in-entrypoints.md index c54b0691..8ec76b8d 100644 --- a/pages/getting-started/basics/custom-types-in-entrypoints.md +++ b/pages/getting-started/basics/custom-types-in-entrypoints.md @@ -4,7 +4,7 @@ Using custom types in entrypoints requires our type to implement the `Serde` tra Thankfully, we can just derive the `Serde` trait for our custom type. ```cairo -// [!include ~/listings/getting-started/custom_type_serde/src/contract.cairo:contract] +// [!include ~/listings/getting-started/custom_type_entrypoints/src/contract.cairo:contract] ``` :::note From b9d04503373f5b33b1e4fc66d35abafa64d14da5 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Fri, 24 Jan 2025 18:06:44 +0100 Subject: [PATCH 37/44] feat: rework custom_type_entrypoints --- .../basics/custom-types-in-entrypoints.md | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/pages/getting-started/basics/custom-types-in-entrypoints.md b/pages/getting-started/basics/custom-types-in-entrypoints.md index 8ec76b8d..4dc59e2a 100644 --- a/pages/getting-started/basics/custom-types-in-entrypoints.md +++ b/pages/getting-started/basics/custom-types-in-entrypoints.md @@ -1,12 +1,21 @@ -# Custom types in entrypoints +# Custom Types in Entrypoints -Using custom types in entrypoints requires our type to implement the `Serde` trait. This is because when calling an entrypoint, the input is sent as an array of `felt252` to the entrypoint, and we need to be able to deserialize it into our custom type. Similarly, when returning a custom type from an entrypoint, we need to be able to serialize it into an array of `felt252`. -Thankfully, we can just derive the `Serde` trait for our custom type. +When using custom types in Starknet contract entrypoints, you need to handle serialization and deserialization of data. This is because: + +1. Input parameters are sent to entrypoints as arrays of `felt252` +2. Return values must be converted back to arrays of `felt252` +3. Custom types need to be converted between these formats automatically + +## Using the Serde Trait + +The `Serde` trait provides the necessary serialization and deserialization capabilities for your custom types. For most simple types, you can derive this trait automatically: ```cairo // [!include ~/listings/getting-started/custom_type_entrypoints/src/contract.cairo:contract] ``` :::note -The purpose of this example is to demonstrate the ability to use custom types as inputs and outputs in contract calls. For simplicity, we are not using getters and setters to manage the contract's state. +For some complex types, you might need to implement the `Serde` trait manually. This gives you control over how your type is serialized and deserialized. + +The `Serde` trait is distinct from the `Store` trait - `Serde` is for passing data in and out of entrypoints, while `Store` is for persisting data in contract storage. ::: From 24d3d089056e3c2c9f507b56587e180b2c4d279f Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Sat, 25 Jan 2025 10:32:45 +0100 Subject: [PATCH 38/44] feat: update syscalls (close #283) --- pages/getting-started/basics/syscalls.md | 273 ----------------------- pages/getting-started/syscalls.md | 250 +++++++++++++++++++++ routes.ts | 8 +- 3 files changed, 254 insertions(+), 277 deletions(-) delete mode 100644 pages/getting-started/basics/syscalls.md create mode 100644 pages/getting-started/syscalls.md diff --git a/pages/getting-started/basics/syscalls.md b/pages/getting-started/basics/syscalls.md deleted file mode 100644 index bacccda4..00000000 --- a/pages/getting-started/basics/syscalls.md +++ /dev/null @@ -1,273 +0,0 @@ -# Syscalls - -At the protocol level, the Starknet Operating System (OS) is the program that manages the whole Starknet network. - -Some of the OS functionalities are exposed to smart contracts through the use of syscalls (system calls). Syscalls can be used to get information about the state of the Starknet network, to interact with/deploy contracts, emit events, send messages, and perform other low-level operations. - -Syscalls return a `SyscallResult` which is either `Success` or `Failure`, allowing the contract to handle errors. - -Here's the available syscalls: - -- [get_block_hash](#get_block_hash) -- [get_execution_info](#get_execution_info) -- [call_contract](#call_contract) -- [deploy](#deploy) -- [emit_event](#emit_event) -- [library_call](#library_call) -- [send_message_to_L1](#send_message_to_L1) -- [replace_class](#replace_class) -- [storage_read](#storage_read) -- [storage_write](#storage_write) - - -#### get_block_hash - -```cairo -fn get_block_hash_syscall(block_number: u64) -> SyscallResult -``` - -Get the hash of the block number `block_number`. - -Only within the range `[first_v0_12_0_block, current_block - 10]`. - -#### get_execution_info - -```cairo -fn get_execution_info_syscall() -> SyscallResult> -``` - -Get information about the current execution context. -The returned `ExecutionInfo` is defined as : - -```cairo -#[derive(Copy, Drop, Debug)] -pub struct ExecutionInfo { - pub block_info: Box, - pub tx_info: Box, - pub caller_address: ContractAddress, - pub contract_address: ContractAddress, - pub entry_point_selector: felt252, -} - -#[derive(Copy, Drop, Debug, Serde)] -pub struct BlockInfo { - pub block_number: u64, - pub block_timestamp: u64, - pub sequencer_address: ContractAddress, -} - -#[derive(Copy, Drop, Debug, Serde)] -pub struct TxInfo { - // The version of the transaction. Always fixed (1) - pub version: felt252, - // The account contract from which this transaction originates. - pub account_contract_address: ContractAddress, - // The max_fee field of the transaction. - pub max_fee: u128, - // The signature of the transaction. - pub signature: Span, - // The hash of the transaction. - pub transaction_hash: felt252, - // The identifier of the chain. - // This field can be used to prevent replay of testnet transactions on mainnet. - pub chain_id: felt252, - // The transaction's nonce. - pub nonce: felt252, - // A span of ResourceBounds structs. - pub resource_bounds: Span, - // The tip. - pub tip: u128, - // If specified, the paymaster should pay for the execution of the tx. - // The data includes the address of the paymaster sponsoring the transaction, followed by - // extra data to send to the paymaster. - pub paymaster_data: Span, - // The data availability mode for the nonce. - pub nonce_data_availability_mode: u32, - // The data availability mode for the account balance from which fee will be taken. - pub fee_data_availability_mode: u32, - // If nonempty, will contain the required data for deploying and initializing an account - // contract: its class hash, address salt and constructor calldata. - pub account_deployment_data: Span, -} -``` - -`starknet::info` provides helper functions to access the `ExecutionInfo` fields in a more convenient way: - -- `get_execution_info() -> Box` -- `get_caller_address() -> ContractAddress` -- `get_contract_address() -> ContractAddress` -- `get_block_info() -> Box` -- `get_tx_info() -> Box` -- `get_block_timestamp() -> u64` -- `get_block_number() -> u64` - -#### call_contract - -```cairo -fn call_contract_syscall( - address: ContractAddress, entry_point_selector: felt252, calldata: Span -) -> SyscallResult> -``` - -Call a contract at `address` with the given `entry_point_selector` and `calldata`. -Failure can't be caught for this syscall, and if the call fails, the whole transaction will revert. - -This is not the recommended way to call a contract. Instead, use the dispatcher generated from the contract interface as shown in the [Calling other contracts](/getting-started/interacting/calling_other_contracts) chapter. - - - -#### deploy - -```cairo -fn deploy_syscall( - class_hash: ClassHash, - contract_address_salt: felt252, - calldata: Span, - deploy_from_zero: bool, -) -> SyscallResult<(ContractAddress, Span::)> -``` - -Deploy a new contract of the predeclared class `class_hash` with `calldata`. -The success result is a tuple containing the deployed contract address and the return value of the constructor. - -`contract_address_salt` and `deploy_from_zero` are used to compute the contract address. - -Example of the usage of the `deploy` syscall from the [Factory pattern](/getting-started/interacting/factory): - -```cairo -// [!include ~/listings/getting-started/factory/src/simple_factory.cairo:deploy] -``` - -#### emit_event - -```cairo -fn emit_event_syscall( - keys: Span, data: Span -) -> SyscallResult<()> -``` - -Emit an event with the given `keys` and `data`. - -Example of the usage of the `emit_event` syscall from the [Events](/getting-started/basics/events) chapter: - -```cairo -// [!include ~/listings/getting-started/events/src/counter.cairo:emit] -``` - - - - -#### library_call - -```cairo -fn library_call_syscall( - class_hash: ClassHash, function_selector: felt252, calldata: Span -) -> SyscallResult> -``` - -Call the function `function_selector` of the class `class_hash` with `calldata`. -This is analogous to a delegate call in Ethereum, but only a single class is called. - - - -#### send_message_to_L1 - -```cairo -fn send_message_to_l1_syscall( - to_address: felt252, payload: Span -) -> SyscallResult<()> -``` - -Send a message to the L1 contract at `to_address` with the given `payload`. - - - -#### replace_class - -```cairo -fn replace_class_syscall( - class_hash: ClassHash -) -> SyscallResult<()> -``` - -Replace the class of the calling contract with the class `class_hash`. - -This is used for contract upgrades. Here's an example from the [Upgradeable Contract](/applications/upgradeable_contract): - -```cairo -// [!include ~/listings/applications/upgradeable_contract/src/upgradeable_contract_v0.cairo:upgrade] -``` - -The new class code will only be used for future calls to the contract. -The current transaction containing the `replace_class` syscall will continue to use the old class code. Note that you can explicitly use the new class code in the same transaction by calling `call_contract` after the `replace_class` syscall. - -#### storage_read - -```cairo -fn storage_read_syscall( - address_domain: u32, address: StorageAddress, -) -> SyscallResult -``` - -This low-level syscall is used to get the value in the storage of a specific key at `address` in the `address_domain`. - -`address_domain` is used to distinguish between data availability modes. -Currently, only mode `ONCHAIN` (`0`) is supported. - -#### storage_write - -```cairo -fn storage_write_syscall( - address_domain: u32, address: StorageAddress, value: felt252 -) -> SyscallResult<()> -``` - -Similar to `storage_read`, this low-level syscall is used to write the value `value` in the storage of a specific key at `address` in the `address_domain`. - -## Documentation - -Syscalls are defined in [`starknet::syscall`](https://github.com/starkware-libs/cairo/blob/ec14a5e2c484190ff40811c973a72a53739cedb7/corelib/src/starknet/syscalls.cairo). - -You can also read the [official documentation page](https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/system-calls-cairo1/) for more details. - - diff --git a/pages/getting-started/syscalls.md b/pages/getting-started/syscalls.md new file mode 100644 index 00000000..39f6793f --- /dev/null +++ b/pages/getting-started/syscalls.md @@ -0,0 +1,250 @@ +# System Calls (Syscalls) + +System calls (syscalls) are the interface between Starknet smart contracts and the Starknet Operating System (OS). They provide essential functionalities for: + +- Reading blockchain state and context +- Contract interactions (deployment, calls) +- Event emission +- Cross-layer communication +- Storage operations + +All syscalls return a `SyscallResult` type, which can be either `Success` or `Failure`, enabling proper error handling in your contracts. + +## Available Syscalls + +### Blockchain State + +- [get_execution_info](#get_execution_info) - Get current execution context +- [get_block_hash](#get_block_hash) - Retrieve a block's hash +- [get_class_hash_at](#get_class_hash_at) - Get the class hash of a contract at a specific address + +### Contract Operations + +- [call_contract](#call_contract) - Call another contract +- [deploy](#deploy) - Deploy a new contract +- [library_call](#library_call) - Make a delegate call +- [replace_class](#replace_class) - Upgrade contract code + +### Events and Messaging + +- [emit_event](#emit_event) - Emit contract events +- [send_message_to_l1](#send_message_to_l1) - Send messages to Ethereum (L1) + +### Storage Operations + +- [storage_read](#storage_read) - Read from contract storage +- [storage_write](#storage_write) - Write to contract storage + +### Cryptographic Operations + +- [keccak](#keccak) - Compute Keccak hash +- [sha256_process_block](#sha256_process_block) - Compute SHA256 hash + +## Detailed Reference + +### get_block_hash + +```cairo +fn get_block_hash_syscall(block_number: u64) -> SyscallResult +``` + +Retrieves the hash of a specific block by its number. Only works for blocks within the range `[first_v0_12_0_block, current_block - 10]`. + +### get_execution_info + +:::info + +Instead of using this syscall directly, the `starknet::info` module provides convenient helper functions: + +- `get_execution_info()` - Full execution context +- `get_caller_address()` - Current caller +- `get_contract_address()` - Current contract +- `get_block_info()` - Block information +- `get_tx_info()` - Transaction details +- `get_block_timestamp()` - Current block time +- `get_block_number()` - Current block number + +::: + +```cairo +fn get_execution_info_v2_syscall() -> SyscallResult> +fn get_execution_info_syscall() -> SyscallResult> +``` + +Returns information about the current execution context. + +### get_class_hash_at + +:::warning +This syscall will only be supported from Starknet v0.13.4 onwards. +::: + +```cairo +fn get_class_hash_at_syscall(contract_address: ContractAddress) -> SyscallResult +``` + +Returns the class hash of a contract at a specific address. + +### call_contract + +:::info +For safer contract calls, use the dispatcher pattern shown in [Calling other contracts](/getting-started/interacting/calling_other_contracts) +::: + +```cairo +fn call_contract_syscall( + address: ContractAddress, + entry_point_selector: felt252, + calldata: Span +) -> SyscallResult> +``` + +Calls a contract at the specified address. Failures cannot be caught and will revert the entire transaction. + +### deploy + +```cairo +fn deploy_syscall( + class_hash: ClassHash, + contract_address_salt: felt252, + calldata: Span, + deploy_from_zero: bool, +) -> SyscallResult<(ContractAddress, Span::)> +``` + +Deploys a new contract instance. Returns the deployed address and constructor result. + +The [Simple Factory](/getting-started/interacting/factory) uses the `deploy` syscall under the hood: + +```cairo +// [!include ~/listings/getting-started/factory/src/simple_factory.cairo:deploy] +``` + +### emit_event + +```cairo +fn emit_event_syscall( + keys: Span, + data: Span +) -> SyscallResult<()> +``` + +Emits an event with indexed keys and data values. + +See the [Events](/getting-started/basics/events) section for more information: + +```cairo +// [!include ~/listings/getting-started/events/src/counter.cairo:emit] +``` + +### library_call + +```cairo +fn library_call_syscall( + class_hash: ClassHash, + function_selector: felt252, + calldata: Span +) -> SyscallResult> +``` + +Makes a delegate call to execute code from another contract class within the current contract's context. Similar to Ethereum's delegatecall but limited to a single class. + +### send_message_to_l1 + +```cairo +fn send_message_to_l1_syscall( + to_address: felt252, + payload: Span +) -> SyscallResult<()> +``` + +Sends a message to an Ethereum (L1) contract. + +### replace_class + +```cairo +fn replace_class_syscall( + class_hash: ClassHash +) -> SyscallResult<()> +``` + +Upgrades the contract's code by replacing its class hash. + +This syscall is used in [Upgradeable Contract](/applications/upgradeable_contract): + +```cairo +// [!include ~/listings/applications/upgradeable_contract/src/upgradeable_contract_v0.cairo:upgrade] +``` + +:::note +The new code only affects future calls. The current transaction continues with the old code unless explicitly called through `call_contract`. +::: + +### storage_read + +:::warning +Using this syscall directly is not recommended. Follow the [Storage](/getting-started/basics/storage) section for more information. +::: + +```cairo +fn storage_read_syscall( + address_domain: u32, + address: StorageAddress, +) -> SyscallResult +``` + +Low-level storage read operation. + +### storage_write + +:::warning +Using this syscall directly is not recommended. Follow the [Storage](/getting-started/basics/storage) section for more information. +::: + +```cairo +fn storage_write_syscall( + address_domain: u32, + address: StorageAddress, + value: felt252 +) -> SyscallResult<()> +``` + +Low-level storage write operation. + +### keccak + +```cairo +fn keccak_syscall(input: Span) -> SyscallResult +``` + +Computes the Keccak hash of the input data as a little-endian 256-bit number, where `input` is a Span of 64-bits little-endian words. + +:::note +**Padding** + +- The input must be a multiple of 1088 bits (== 17 u64 words) +- The input must be pre-padded following the Keccak padding rule (pad10\*1): + 1. Add a '1' bit + 2. Add zero or more '0' bits + 3. Add a final '1' bit + The total length after padding must be a multiple of 1088 bits + ::: + +### sha256_process_block + +```cairo +fn sha256_process_block_syscall( + state: core::sha256::Sha256StateHandle, input: Box<[u32; 16]>, +) -> SyscallResult {} +``` + +Computes the next SHA-256 state of the input block with the given state. + +:::note +The system call does not add any padding and the input needs to be a multiple of 512 bits (== 16 u32 words). +::: + +## Additional Resources + +- [Official Syscalls Documentation](https://docs.starknet.io/documentation/architecture_and_concepts/Smart_Contracts/system-calls-cairo1/) +- [Source Code](https://github.com/starkware-libs/cairo/blob/v2.9.2/corelib/src/starknet/syscalls.cairo) diff --git a/routes.ts b/routes.ts index 99e74560..11f33295 100644 --- a/routes.ts +++ b/routes.ts @@ -54,10 +54,6 @@ const config: Sidebar = [ text: "Mappings", link: "/getting-started/basics/mappings", }, - { - text: "Syscalls", - link: "/getting-started/basics/syscalls", - }, { text: "Documentation", link: "/getting-started/basics/documentation", @@ -89,6 +85,10 @@ const config: Sidebar = [ text: "Testing contracts", link: "/getting-started/testing/contract-testing", }, + { + text: "Syscalls Reference", + link: "/getting-started/syscalls", + }, ], }, { From 4cbc935e9c323eab6472126dc9b4fead75b2f6bd Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Sun, 26 Jan 2025 16:33:03 +0100 Subject: [PATCH 39/44] feat: remove interacting/interface chapter --- .../interfaces_traits/.gitignore | 1 - .../interfaces_traits/Scarb.lock | 6 -- .../interfaces_traits/Scarb.toml | 15 ---- .../interfaces_traits/src/explicit.cairo | 56 ------------- .../interfaces_traits/src/implicit.cairo | 50 ------------ .../src/implicit_internal.cairo | 79 ------------------- .../interfaces_traits/src/lib.cairo | 3 - .../interacting/interfaces-traits.md | 39 --------- routes.ts | 4 - 9 files changed, 253 deletions(-) delete mode 100644 listings/getting-started/interfaces_traits/.gitignore delete mode 100644 listings/getting-started/interfaces_traits/Scarb.lock delete mode 100644 listings/getting-started/interfaces_traits/Scarb.toml delete mode 100644 listings/getting-started/interfaces_traits/src/explicit.cairo delete mode 100644 listings/getting-started/interfaces_traits/src/implicit.cairo delete mode 100644 listings/getting-started/interfaces_traits/src/implicit_internal.cairo delete mode 100644 listings/getting-started/interfaces_traits/src/lib.cairo delete mode 100644 pages/getting-started/interacting/interfaces-traits.md diff --git a/listings/getting-started/interfaces_traits/.gitignore b/listings/getting-started/interfaces_traits/.gitignore deleted file mode 100644 index eb5a316c..00000000 --- a/listings/getting-started/interfaces_traits/.gitignore +++ /dev/null @@ -1 +0,0 @@ -target diff --git a/listings/getting-started/interfaces_traits/Scarb.lock b/listings/getting-started/interfaces_traits/Scarb.lock deleted file mode 100644 index c5dde57a..00000000 --- a/listings/getting-started/interfaces_traits/Scarb.lock +++ /dev/null @@ -1,6 +0,0 @@ -# Code generated by scarb DO NOT EDIT. -version = 1 - -[[package]] -name = "interfaces_traits" -version.workspace = true diff --git a/listings/getting-started/interfaces_traits/Scarb.toml b/listings/getting-started/interfaces_traits/Scarb.toml deleted file mode 100644 index 0cc1a25d..00000000 --- a/listings/getting-started/interfaces_traits/Scarb.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "interfaces_traits" -version.workspace = true -edition.workspace = true - -[dependencies] -starknet.workspace = true - -[dev-dependencies] -cairo_test.workspace = true - -[scripts] -test.workspace = true - -[[target.starknet-contract]] diff --git a/listings/getting-started/interfaces_traits/src/explicit.cairo b/listings/getting-started/interfaces_traits/src/explicit.cairo deleted file mode 100644 index 4454cc23..00000000 --- a/listings/getting-started/interfaces_traits/src/explicit.cairo +++ /dev/null @@ -1,56 +0,0 @@ -// [!region contract] -#[starknet::interface] -pub trait IExplicitInterfaceContract { - fn get_value(self: @TContractState) -> u32; - fn set_value(ref self: TContractState, value: u32); -} - -#[starknet::contract] -pub mod ExplicitInterfaceContract { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - - #[storage] - struct Storage { - value: u32, - } - - #[abi(embed_v0)] - impl ExplicitInterfaceContract of super::IExplicitInterfaceContract { - fn get_value(self: @ContractState) -> u32 { - self.value.read() - } - - fn set_value(ref self: ContractState, value: u32) { - self.value.write(value); - } - } -} -// [!endregion contract] - -#[cfg(test)] -mod tests { - use super::{ - ExplicitInterfaceContract, IExplicitInterfaceContractDispatcher, - IExplicitInterfaceContractDispatcherTrait, - }; - use starknet::syscalls::deploy_syscall; - - #[test] - fn test_interface() { - let (contract_address, _) = deploy_syscall( - ExplicitInterfaceContract::TEST_CLASS_HASH.try_into().unwrap(), - 0, - array![].span(), - false, - ) - .unwrap(); - let mut contract = IExplicitInterfaceContractDispatcher { contract_address }; - - let value: u32 = 20; - contract.set_value(value); - - let read_value = contract.get_value(); - - assert_eq!(read_value, value); - } -} diff --git a/listings/getting-started/interfaces_traits/src/implicit.cairo b/listings/getting-started/interfaces_traits/src/implicit.cairo deleted file mode 100644 index 0ab2d6d2..00000000 --- a/listings/getting-started/interfaces_traits/src/implicit.cairo +++ /dev/null @@ -1,50 +0,0 @@ -// [!region contract] -#[starknet::contract] -pub mod ImplicitInterfaceContract { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - - #[storage] - struct Storage { - value: u32, - } - - #[abi(per_item)] - #[generate_trait] - pub impl ImplicitInterfaceContract of IImplicitInterfaceContract { - #[external(v0)] - fn get_value(self: @ContractState) -> u32 { - self.value.read() - } - - #[external(v0)] - fn set_value(ref self: ContractState, value: u32) { - self.value.write(value); - } - } -} -// [!endregion contract] - -#[cfg(test)] -mod tests { - use super::{ImplicitInterfaceContract, ImplicitInterfaceContract::IImplicitInterfaceContract}; - use starknet::{syscalls::deploy_syscall, testing::set_contract_address}; - - #[test] - fn test_interface() { - let (contract_address, _) = deploy_syscall( - ImplicitInterfaceContract::TEST_CLASS_HASH.try_into().unwrap(), - 0, - array![].span(), - false, - ) - .unwrap(); - set_contract_address(contract_address); - let mut state = ImplicitInterfaceContract::contract_state_for_testing(); - - let value = 42; - state.set_value(value); - let read_value = state.get_value(); - - assert_eq!(read_value, value); - } -} diff --git a/listings/getting-started/interfaces_traits/src/implicit_internal.cairo b/listings/getting-started/interfaces_traits/src/implicit_internal.cairo deleted file mode 100644 index 74bdca0f..00000000 --- a/listings/getting-started/interfaces_traits/src/implicit_internal.cairo +++ /dev/null @@ -1,79 +0,0 @@ -// [!region contract] -#[starknet::interface] -pub trait IImplicitInternalContract { - fn add(ref self: TContractState, nb: u32); - fn get_value(self: @TContractState) -> u32; - fn get_const(self: @TContractState) -> u32; -} - -#[starknet::contract] -pub mod ImplicitInternalContract { - use starknet::storage::{StoragePointerReadAccess, StoragePointerWriteAccess}; - - #[storage] - struct Storage { - value: u32, - } - - #[generate_trait] - impl InternalFunctions of InternalFunctionsTrait { - fn set_value(ref self: ContractState, value: u32) { - self.value.write(value); - } - - fn get_const() -> u32 { - 42 - } - } - - #[constructor] - fn constructor(ref self: ContractState) { - self.set_value(0); - } - - #[abi(embed_v0)] - impl ImplicitInternalContract of super::IImplicitInternalContract { - fn add(ref self: ContractState, nb: u32) { - self.set_value(self.value.read() + nb); - } - - fn get_value(self: @ContractState) -> u32 { - self.value.read() - } - - fn get_const(self: @ContractState) -> u32 { - self.get_const() - } - } -} -// [!endregion contract] - -#[cfg(test)] -mod tests { - use super::{ - ImplicitInternalContract, IImplicitInternalContractDispatcher, - IImplicitInternalContractDispatcherTrait, - }; - use starknet::syscalls::deploy_syscall; - - #[test] - fn test_interface() { - // Set up. - let (contract_address, _) = deploy_syscall( - ImplicitInternalContract::TEST_CLASS_HASH.try_into().unwrap(), - 0, - array![].span(), - false, - ) - .unwrap(); - let mut contract = IImplicitInternalContractDispatcher { contract_address }; - - let initial_value: u32 = 0; - assert_eq!(contract.get_value(), initial_value); - - let add_value: u32 = 10; - contract.add(add_value); - - assert_eq!(contract.get_value(), initial_value + add_value); - } -} diff --git a/listings/getting-started/interfaces_traits/src/lib.cairo b/listings/getting-started/interfaces_traits/src/lib.cairo deleted file mode 100644 index 500b0482..00000000 --- a/listings/getting-started/interfaces_traits/src/lib.cairo +++ /dev/null @@ -1,3 +0,0 @@ -mod explicit; -mod implicit_internal; -mod implicit; diff --git a/pages/getting-started/interacting/interfaces-traits.md b/pages/getting-started/interacting/interfaces-traits.md deleted file mode 100644 index 751c931a..00000000 --- a/pages/getting-started/interacting/interfaces-traits.md +++ /dev/null @@ -1,39 +0,0 @@ -# Contract interfaces and Traits generation - -Contract interfaces define the structure and behavior of a contract, serving as the contract's public ABI. They list all the function signatures that a contract exposes. For a detailed explanation of interfaces, you can refer to the [Cairo Book](https://book.cairo-lang.org/ch13-02-anatomy-of-a-simple-contract.html#the-interface-the-contracts-blueprint). - -In Cairo, to specify the interface you need to define a trait annotated with `#[starknet::interface]` and then implement that trait in the contract. - -When a function needs to access the contract state, it must have a `self` parameter of type `ContractState`. This implies that the corresponding function signature in the interface trait must also take a `TContractState` type as a parameter. It's important to note that every function in the contract interface must have this `self` parameter of type `TContractState`. - -You can use the `#[generate_trait]` attribute to implicitly generate the trait for a specific implementation block. This attribute automatically generates a trait with the same functions as the ones in the implemented block, replacing the `self` parameter with a generic `TContractState` parameter. However, you will need to annotate the block with the `#[abi(per_item)]` attribute, and each function with the appropriate attribute depending on whether it's an external function, a constructor or an L1 handler. - -In summary, there's two ways to handle interfaces: - -- Explicitly, by defining a trait annotated with `#[starknet::interface]` -- Implicitly, by using `#[generate_trait]` combined with the `#[abi(per_item)]` attributes, and annotating each function inside the implementation block with the appropriate attribute. - -## Explicit interface - -```cairo -// [!include ~/listings/getting-started/interfaces_traits/src/explicit.cairo:contract] -``` - -## Implicit interface - -```cairo -// [!include ~/listings/getting-started/interfaces_traits/src/implicit.cairo:contract] -``` - -:::note -You can import an implicitly generated contract interface with `use contract::{GeneratedContractInterface}`. However, the `Dispatcher` will not be generated automatically. -::: - -## Internal functions - -You can also use `#[generate_trait]` for your internal functions. -Since this trait is generated in the context of the contract, you can define pure functions as well (functions without the `self` parameter). - -```cairo -// [!include ~/listings/getting-started/interfaces_traits/src/implicit_internal.cairo:contract] -``` diff --git a/routes.ts b/routes.ts index 11f33295..04eff920 100644 --- a/routes.ts +++ b/routes.ts @@ -67,10 +67,6 @@ const config: Sidebar = [ text: "How to deploy", link: "/getting-started/interacting/how_to_deploy", }, - { - text: "Contract interfaces and Traits generation", - link: "/getting-started/interacting/interfaces-traits", - }, { text: "Calling other contracts", link: "/getting-started/interacting/calling_other_contracts", From dd00697850974d7db2170d26f5ee82558575ba06 Mon Sep 17 00:00:00 2001 From: CountryCousin Date: Sun, 26 Jan 2025 14:02:15 +0100 Subject: [PATCH 40/44] Update simple_vault.cairo update of functions using ref and snapshots --- listings/applications/simple_vault/src/simple_vault.cairo | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/listings/applications/simple_vault/src/simple_vault.cairo b/listings/applications/simple_vault/src/simple_vault.cairo index 8ae7d074..fc708ec8 100644 --- a/listings/applications/simple_vault/src/simple_vault.cairo +++ b/listings/applications/simple_vault/src/simple_vault.cairo @@ -31,8 +31,8 @@ pub trait IERC20 { pub trait ISimpleVault { fn deposit(ref self: TContractState, amount: u256); fn withdraw(ref self: TContractState, shares: u256); - fn user_balance_of(ref self: TContractState, account: ContractAddress) -> u256; - fn contract_total_supply(ref self: TContractState) -> u256; + fn user_balance_of(self: @TContractState, account: ContractAddress) -> u256; + fn contract_total_supply(self: @TContractState) -> u256; } #[starknet::contract] @@ -71,11 +71,11 @@ pub mod SimpleVault { #[abi(embed_v0)] impl SimpleVault of super::ISimpleVault { - fn user_balance_of(ref self: ContractState, account: ContractAddress) -> u256 { + fn user_balance_of(self: @ContractState, account: ContractAddress) -> u256 { self.balance_of.read(account) } - fn contract_total_supply(ref self: ContractState) -> u256 { + fn contract_total_supply(self: @ContractState) -> u256 { self.total_supply.read() } From 48a3667312f8ff5105ee0dc4d4d02e98e93b8951 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Mon, 27 Jan 2025 17:12:03 +0100 Subject: [PATCH 41/44] feat: migrate calling_other_contract to snforge --- Scarb.lock | 7 +- .../calling_other_contracts/Scarb.toml | 3 +- .../calling_other_contracts/src/caller.cairo | 68 +++++++++---------- 3 files changed, 39 insertions(+), 39 deletions(-) diff --git a/Scarb.lock b/Scarb.lock index 34dddc6e..1f544d5c 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -25,6 +25,9 @@ version = "0.1.0" [[package]] name = "calling_other_contracts" version = "0.1.0" +dependencies = [ + "snforge_std", +] [[package]] name = "coin_flip" @@ -121,10 +124,6 @@ version = "0.1.0" name = "hash_trait" version = "0.1.0" -[[package]] -name = "interfaces_traits" -version = "0.1.0" - [[package]] name = "library_calls" version = "0.1.0" diff --git a/listings/getting-started/calling_other_contracts/Scarb.toml b/listings/getting-started/calling_other_contracts/Scarb.toml index 2595a9bd..717546c9 100644 --- a/listings/getting-started/calling_other_contracts/Scarb.toml +++ b/listings/getting-started/calling_other_contracts/Scarb.toml @@ -7,7 +7,8 @@ edition.workspace = true starknet.workspace = true [dev-dependencies] -cairo_test.workspace = true +assert_macros.workspace = true +snforge_std.workspace = true [scripts] test.workspace = true diff --git a/listings/getting-started/calling_other_contracts/src/caller.cairo b/listings/getting-started/calling_other_contracts/src/caller.cairo index 7a088711..133c6340 100644 --- a/listings/getting-started/calling_other_contracts/src/caller.cairo +++ b/listings/getting-started/calling_other_contracts/src/caller.cairo @@ -1,31 +1,37 @@ // [!region callee_contract] // This will automatically generate ICalleeDispatcher and ICalleeDispatcherTrait #[starknet::interface] -pub trait ICallee { - fn set_value(ref self: TContractState, value: u128) -> u128; +trait ICallee { + fn set_value(ref self: TContractState, value: u128); + fn get_value(self: @TContractState) -> u128; } #[starknet::contract] -pub mod Callee { - use starknet::storage::StoragePointerWriteAccess; +mod Callee { + use starknet::storage::{StoragePointerWriteAccess, StoragePointerReadAccess}; + use super::ICallee; #[storage] struct Storage { - pub value: u128, + value: u128, } #[abi(embed_v0)] - impl ICalleeImpl of super::ICallee { - fn set_value(ref self: ContractState, value: u128) -> u128 { + impl ICalleeImpl of ICallee { + fn set_value(ref self: ContractState, value: u128) { self.value.write(value); - value + } + fn get_value(self: @ContractState) -> u128 { + self.value.read() } } } // [!endregion callee_contract] +// Interface for the contract that will make the calls #[starknet::interface] -pub trait ICaller { +trait ICaller { + // Call another contract to set its value fn set_value_from_address( ref self: TContractState, addr: starknet::ContractAddress, value: u128, ); @@ -33,18 +39,19 @@ pub trait ICaller { // [!region caller_contract] #[starknet::contract] -pub mod Caller { - // We need to import the dispatcher of the callee contract - // If you don't have a proper import, you can redefine the interface by yourself +mod Caller { + // Import the generated dispatcher types for the Callee contract use super::{ICalleeDispatcher, ICalleeDispatcherTrait}; + use super::ICaller; use starknet::ContractAddress; #[storage] struct Storage {} #[abi(embed_v0)] - impl ICallerImpl of super::ICaller { + impl ICallerImpl of ICaller { fn set_value_from_address(ref self: ContractState, addr: ContractAddress, value: u128) { + // Create a dispatcher instance and call the target contract ICalleeDispatcher { contract_address: addr }.set_value(value); } } @@ -53,37 +60,30 @@ pub mod Caller { #[cfg(test)] mod tests { - use super::{Callee, ICalleeDispatcher, Caller, ICallerDispatcher, ICallerDispatcherTrait}; - use starknet::{testing::set_contract_address, syscalls::deploy_syscall}; - use starknet::storage::StoragePointerReadAccess; + use super::{ + ICalleeDispatcher, ICalleeDispatcherTrait, ICallerDispatcher, ICallerDispatcherTrait, + }; + use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; fn deploy() -> (ICalleeDispatcher, ICallerDispatcher) { - let (address_callee, _) = deploy_syscall( - Callee::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); - let (address_caller, _) = deploy_syscall( - Caller::TEST_CLASS_HASH.try_into().unwrap(), 0, array![].span(), false, - ) - .unwrap(); + let contract = declare("Callee").unwrap().contract_class(); + let (callee_contract_address, _) = contract.deploy(@array![]).unwrap(); + + let contract = declare("Caller").unwrap().contract_class(); + let (caller_contract_address, _) = contract.deploy(@array![]).unwrap(); ( - ICalleeDispatcher { contract_address: address_callee }, - ICallerDispatcher { contract_address: address_caller }, + ICalleeDispatcher { contract_address: callee_contract_address }, + ICallerDispatcher { contract_address: caller_contract_address }, ) } #[test] fn test_caller() { - let init_value: u128 = 42; - let (callee, caller) = deploy(); - caller.set_value_from_address(callee.contract_address, init_value); - - let state = @Callee::contract_state_for_testing(); - set_contract_address(callee.contract_address); + let value: u128 = 42; - let value_read: u128 = state.value.read(); + caller.set_value_from_address(callee.contract_address, value); - assert_eq!(value_read, init_value); + assert_eq!(callee.get_value(), value); } } From ac41ee50f40c682b4c59a08dce9482db77121326 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Mon, 27 Jan 2025 17:12:22 +0100 Subject: [PATCH 42/44] feat: rework calling_other_contract --- .../interacting/calling_other_contracts.md | 35 ++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/pages/getting-started/interacting/calling_other_contracts.md b/pages/getting-started/interacting/calling_other_contracts.md index 55288e6b..7be9dc90 100644 --- a/pages/getting-started/interacting/calling_other_contracts.md +++ b/pages/getting-started/interacting/calling_other_contracts.md @@ -1,22 +1,41 @@ -# Calling other contracts +# Calling Other Contracts -There are two different ways to call other contracts in Cairo. +In Starknet, contracts can interact with each other through contract calls. The recommended way to make these calls is using the dispatcher pattern, which provides type safety and better error handling. -The easiest way to call other contracts is by using the dispatcher of the contract you want to call. -You can read more about Dispatchers in the [Cairo Book](https://book.cairo-lang.org/ch15-02-interacting-with-another-contract.html#calling-contracts-using-the-contract-dispatcher). +## Understanding Dispatchers -The other way is to use the `starknet::call_contract_syscall` syscall yourself. However, this method is not recommended and will not be covered in this chapter. +A dispatcher is an automatically generated struct that handles the serialization and deserialization of contract calls. To use dispatchers: -In order to call other contracts using dispatchers, you will need to define the called contract's interface as a trait annotated with the `#[starknet::interface]` attribute, and then import the `IContractDispatcher` and `IContractDispatcherTrait` items in your contract. +1. Define the target contract's interface as a trait with `#[starknet::interface]` (`IContract`) +2. Import the generated dispatcher types (`IContractDispatcher` and `IContractDispatcherTrait`) +3. Create a dispatcher instance with the target contract's address -Here's the `Callee` contract interface and implementation: +Let's look at a practical example where one contract (`Caller`) interacts with another (`Callee`). The `Callee` contract stores a value that can be set and retrieved: ```cairo // [!include ~/listings/getting-started/calling_other_contracts/src/caller.cairo:callee_contract] ``` -The following `Caller` contract uses the `Callee` dispatcher to call the `Callee` contract: +The `Caller` contract demonstrates how to use the dispatcher to interact with `Callee`: ```cairo // [!include ~/listings/getting-started/calling_other_contracts/src/caller.cairo:caller_contract] ``` + +### Key Points: + +- The `#[starknet::interface]` attribute automatically generates the dispatcher types +- Dispatchers handle all the low-level details of contract interaction +- Contract calls are type-safe and checked at compile time +- Each contract maintains its own storage and state + +For more details about dispatchers, check out the [Cairo Book](https://book.cairo-lang.org/ch102-02-interacting-with-another-contract.html). + +:::note +While you can use the low-level `call_contract_syscall` directly, it's not recommended as it: + +- Requires manual serialization/deserialization +- Lacks compile-time type checking +- Is more easy to make mistakes + +::: From b78c30cc1f7db35f39598274cc998b093a5063c5 Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 28 Jan 2025 23:07:35 +0100 Subject: [PATCH 43/44] fix: cairo cheatsheet in sub listing --- Scarb.lock | 4 ---- listings/cairo_cheatsheet/{ => listing}/.gitignore | 0 listings/cairo_cheatsheet/{ => listing}/Scarb.lock | 0 listings/cairo_cheatsheet/{ => listing}/Scarb.toml | 0 .../cairo_cheatsheet/{ => listing}/src/array_example.cairo | 0 .../cairo_cheatsheet/{ => listing}/src/dict_example.cairo | 0 .../cairo_cheatsheet/{ => listing}/src/enum_example.cairo | 0 .../cairo_cheatsheet/{ => listing}/src/felt_example.cairo | 0 .../cairo_cheatsheet/{ => listing}/src/if_let_example.cairo | 0 listings/cairo_cheatsheet/{ => listing}/src/lib.cairo | 0 .../cairo_cheatsheet/{ => listing}/src/loop_example.cairo | 0 .../cairo_cheatsheet/{ => listing}/src/mapping_example.cairo | 0 .../cairo_cheatsheet/{ => listing}/src/match_example.cairo | 0 .../cairo_cheatsheet/{ => listing}/src/struct_example.cairo | 0 .../cairo_cheatsheet/{ => listing}/src/tuple_example.cairo | 0 .../{ => listing}/src/type_casting_example.cairo | 0 .../cairo_cheatsheet/{ => listing}/src/while_example.cairo | 0 .../{ => listing}/src/while_let_example.cairo | 0 pages/cairo_cheatsheet/arrays.md | 2 +- pages/cairo_cheatsheet/dict.md | 2 +- pages/cairo_cheatsheet/enums.md | 4 ++-- pages/cairo_cheatsheet/felt.md | 4 ++-- pages/cairo_cheatsheet/if_let.md | 2 +- pages/cairo_cheatsheet/loop.md | 2 +- pages/cairo_cheatsheet/mapping.md | 2 +- pages/cairo_cheatsheet/match.md | 2 +- pages/cairo_cheatsheet/struct.md | 2 +- pages/cairo_cheatsheet/tuples.md | 2 +- pages/cairo_cheatsheet/type_casting.md | 2 +- pages/cairo_cheatsheet/while.md | 2 +- pages/cairo_cheatsheet/while_let.md | 2 +- pages/getting-started/testing/contract-testing.md | 2 +- 32 files changed, 16 insertions(+), 20 deletions(-) rename listings/cairo_cheatsheet/{ => listing}/.gitignore (100%) rename listings/cairo_cheatsheet/{ => listing}/Scarb.lock (100%) rename listings/cairo_cheatsheet/{ => listing}/Scarb.toml (100%) rename listings/cairo_cheatsheet/{ => listing}/src/array_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/dict_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/enum_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/felt_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/if_let_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/lib.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/loop_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/mapping_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/match_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/struct_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/tuple_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/type_casting_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/while_example.cairo (100%) rename listings/cairo_cheatsheet/{ => listing}/src/while_let_example.cairo (100%) diff --git a/Scarb.lock b/Scarb.lock index 1f544d5c..d6ab17ce 100644 --- a/Scarb.lock +++ b/Scarb.lock @@ -18,10 +18,6 @@ dependencies = [ "snforge_std", ] -[[package]] -name = "cairo_cheatsheet" -version = "0.1.0" - [[package]] name = "calling_other_contracts" version = "0.1.0" diff --git a/listings/cairo_cheatsheet/.gitignore b/listings/cairo_cheatsheet/listing/.gitignore similarity index 100% rename from listings/cairo_cheatsheet/.gitignore rename to listings/cairo_cheatsheet/listing/.gitignore diff --git a/listings/cairo_cheatsheet/Scarb.lock b/listings/cairo_cheatsheet/listing/Scarb.lock similarity index 100% rename from listings/cairo_cheatsheet/Scarb.lock rename to listings/cairo_cheatsheet/listing/Scarb.lock diff --git a/listings/cairo_cheatsheet/Scarb.toml b/listings/cairo_cheatsheet/listing/Scarb.toml similarity index 100% rename from listings/cairo_cheatsheet/Scarb.toml rename to listings/cairo_cheatsheet/listing/Scarb.toml diff --git a/listings/cairo_cheatsheet/src/array_example.cairo b/listings/cairo_cheatsheet/listing/src/array_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/array_example.cairo rename to listings/cairo_cheatsheet/listing/src/array_example.cairo diff --git a/listings/cairo_cheatsheet/src/dict_example.cairo b/listings/cairo_cheatsheet/listing/src/dict_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/dict_example.cairo rename to listings/cairo_cheatsheet/listing/src/dict_example.cairo diff --git a/listings/cairo_cheatsheet/src/enum_example.cairo b/listings/cairo_cheatsheet/listing/src/enum_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/enum_example.cairo rename to listings/cairo_cheatsheet/listing/src/enum_example.cairo diff --git a/listings/cairo_cheatsheet/src/felt_example.cairo b/listings/cairo_cheatsheet/listing/src/felt_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/felt_example.cairo rename to listings/cairo_cheatsheet/listing/src/felt_example.cairo diff --git a/listings/cairo_cheatsheet/src/if_let_example.cairo b/listings/cairo_cheatsheet/listing/src/if_let_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/if_let_example.cairo rename to listings/cairo_cheatsheet/listing/src/if_let_example.cairo diff --git a/listings/cairo_cheatsheet/src/lib.cairo b/listings/cairo_cheatsheet/listing/src/lib.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/lib.cairo rename to listings/cairo_cheatsheet/listing/src/lib.cairo diff --git a/listings/cairo_cheatsheet/src/loop_example.cairo b/listings/cairo_cheatsheet/listing/src/loop_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/loop_example.cairo rename to listings/cairo_cheatsheet/listing/src/loop_example.cairo diff --git a/listings/cairo_cheatsheet/src/mapping_example.cairo b/listings/cairo_cheatsheet/listing/src/mapping_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/mapping_example.cairo rename to listings/cairo_cheatsheet/listing/src/mapping_example.cairo diff --git a/listings/cairo_cheatsheet/src/match_example.cairo b/listings/cairo_cheatsheet/listing/src/match_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/match_example.cairo rename to listings/cairo_cheatsheet/listing/src/match_example.cairo diff --git a/listings/cairo_cheatsheet/src/struct_example.cairo b/listings/cairo_cheatsheet/listing/src/struct_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/struct_example.cairo rename to listings/cairo_cheatsheet/listing/src/struct_example.cairo diff --git a/listings/cairo_cheatsheet/src/tuple_example.cairo b/listings/cairo_cheatsheet/listing/src/tuple_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/tuple_example.cairo rename to listings/cairo_cheatsheet/listing/src/tuple_example.cairo diff --git a/listings/cairo_cheatsheet/src/type_casting_example.cairo b/listings/cairo_cheatsheet/listing/src/type_casting_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/type_casting_example.cairo rename to listings/cairo_cheatsheet/listing/src/type_casting_example.cairo diff --git a/listings/cairo_cheatsheet/src/while_example.cairo b/listings/cairo_cheatsheet/listing/src/while_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/while_example.cairo rename to listings/cairo_cheatsheet/listing/src/while_example.cairo diff --git a/listings/cairo_cheatsheet/src/while_let_example.cairo b/listings/cairo_cheatsheet/listing/src/while_let_example.cairo similarity index 100% rename from listings/cairo_cheatsheet/src/while_let_example.cairo rename to listings/cairo_cheatsheet/listing/src/while_let_example.cairo diff --git a/pages/cairo_cheatsheet/arrays.md b/pages/cairo_cheatsheet/arrays.md index 23b3d794..4a54ab89 100644 --- a/pages/cairo_cheatsheet/arrays.md +++ b/pages/cairo_cheatsheet/arrays.md @@ -20,5 +20,5 @@ trait ArrayTrait { For example: ```cairo -// [!include ~/listings/cairo_cheatsheet/src/array_example.cairo] +// [!include ~/listings/cairo_cheatsheet/listing/src/array_example.cairo] ``` diff --git a/pages/cairo_cheatsheet/dict.md b/pages/cairo_cheatsheet/dict.md index d7bd1248..fc5bd0b2 100644 --- a/pages/cairo_cheatsheet/dict.md +++ b/pages/cairo_cheatsheet/dict.md @@ -8,5 +8,5 @@ A dictionary is a data structure used to store key-value pairs, enabling efficie For example: ```cairo -// [!include ~/listings/cairo_cheatsheet/src/dict_example.cairo:sheet] +// [!include ~/listings/cairo_cheatsheet/listing/src/dict_example.cairo:sheet] ``` diff --git a/pages/cairo_cheatsheet/enums.md b/pages/cairo_cheatsheet/enums.md index 23b85766..81d192dc 100644 --- a/pages/cairo_cheatsheet/enums.md +++ b/pages/cairo_cheatsheet/enums.md @@ -5,7 +5,7 @@ Just like other programming languages, enums (enumerations) are used in cairo to In cairo, `enum variants` can hold different data types (the unit type, structs, other enums, tuples, default core library types, arrays, dictionaries, ...), as shown in the code snippet below. Furthermore, as a quick reminder, enums are expressions, meaning they can return values. ```cairo -// [!include ~/listings/cairo_cheatsheet/src/enum_example.cairo:enums] +// [!include ~/listings/cairo_cheatsheet/listing/src/enum_example.cairo:enums] ``` Enums can be declared both inside and outside a contract. If declared outside, they need to be imported inside using the `use` keyword, just like other imports. @@ -24,5 +24,5 @@ Enums can be declared both inside and outside a contract. If declared outside, t Here is an example of a contract illustrating the above statements : ```cairo -// [!include ~/listings/cairo_cheatsheet/src/enum_example.cairo:enum_contract] +// [!include ~/listings/cairo_cheatsheet/listing/src/enum_example.cairo:enum_contract] ``` diff --git a/pages/cairo_cheatsheet/felt.md b/pages/cairo_cheatsheet/felt.md index a47da1cc..e4ce25d1 100644 --- a/pages/cairo_cheatsheet/felt.md +++ b/pages/cairo_cheatsheet/felt.md @@ -1,10 +1,10 @@ # Felt `felt252` is a fundamental data type in Cairo from which all other data types are derived. -`felt252` can also be used to store [short string representations](/getting-started/basics/bytearrays-strings#short-strings) with a maximum length of 31 characters. +`felt252` can also be used to store 'short string representations' with a maximum length of 31 characters. For example: ```cairo -// [!include ~/listings/cairo_cheatsheet/src/felt_example.cairo:sheet] +// [!include ~/listings/cairo_cheatsheet/listing/src/felt_example.cairo:sheet] ``` diff --git a/pages/cairo_cheatsheet/if_let.md b/pages/cairo_cheatsheet/if_let.md index d4904664..7496a5a6 100644 --- a/pages/cairo_cheatsheet/if_let.md +++ b/pages/cairo_cheatsheet/if_let.md @@ -3,7 +3,7 @@ A `if let` statement is a combination of an `if` statement and a `let` statement. It allows you to execute the block only if the pattern matches. It's a cleaner way to handle a `match` statement with only one pattern that you want to handle. ```cairo -// [!include ~/listings/cairo_cheatsheet/src/if_let_example.cairo:sheet] +// [!include ~/listings/cairo_cheatsheet/listing/src/if_let_example.cairo:sheet] ``` ### See also diff --git a/pages/cairo_cheatsheet/loop.md b/pages/cairo_cheatsheet/loop.md index a15fe539..70fbd1a3 100644 --- a/pages/cairo_cheatsheet/loop.md +++ b/pages/cairo_cheatsheet/loop.md @@ -5,7 +5,7 @@ A `loop` specifies a block of code that will run repetitively until a halting co For example: ```cairo -// [!include ~/listings/cairo_cheatsheet/src/loop_example.cairo:sheet] +// [!include ~/listings/cairo_cheatsheet/listing/src/loop_example.cairo:sheet] ``` ### See also diff --git a/pages/cairo_cheatsheet/mapping.md b/pages/cairo_cheatsheet/mapping.md index e32a4d05..9c61e48d 100644 --- a/pages/cairo_cheatsheet/mapping.md +++ b/pages/cairo_cheatsheet/mapping.md @@ -3,5 +3,5 @@ The `Map` type can be used to represent a collection of key-value. ```cairo -// [!include ~/listings/cairo_cheatsheet/src/mapping_example.cairo] +// [!include ~/listings/cairo_cheatsheet/listing/src/mapping_example.cairo] ``` diff --git a/pages/cairo_cheatsheet/match.md b/pages/cairo_cheatsheet/match.md index 1a5048cf..0f2b7d29 100644 --- a/pages/cairo_cheatsheet/match.md +++ b/pages/cairo_cheatsheet/match.md @@ -5,5 +5,5 @@ The `match` expression in Cairo allows us to control the flow of our code by com For example: ```cairo -// [!include ~/listings/cairo_cheatsheet/src/match_example.cairo] +// [!include ~/listings/cairo_cheatsheet/listing/src/match_example.cairo] ``` diff --git a/pages/cairo_cheatsheet/struct.md b/pages/cairo_cheatsheet/struct.md index f4938402..16fd879b 100644 --- a/pages/cairo_cheatsheet/struct.md +++ b/pages/cairo_cheatsheet/struct.md @@ -5,5 +5,5 @@ A struct is a data type similar to a tuple. Like tuples, they can be used to hol For example: ```cairo -// [!include ~/listings/cairo_cheatsheet/src/struct_example.cairo] +// [!include ~/listings/cairo_cheatsheet/listing/src/struct_example.cairo] ``` diff --git a/pages/cairo_cheatsheet/tuples.md b/pages/cairo_cheatsheet/tuples.md index d438f646..77251500 100644 --- a/pages/cairo_cheatsheet/tuples.md +++ b/pages/cairo_cheatsheet/tuples.md @@ -5,5 +5,5 @@ Tuples is a data type to group a fixed number of items of potentially different For example: ```cairo -// [!include ~/listings/cairo_cheatsheet/src/tuple_example.cairo:sheet] +// [!include ~/listings/cairo_cheatsheet/listing/src/tuple_example.cairo:sheet] ``` diff --git a/pages/cairo_cheatsheet/type_casting.md b/pages/cairo_cheatsheet/type_casting.md index ad49878c..cd24d670 100644 --- a/pages/cairo_cheatsheet/type_casting.md +++ b/pages/cairo_cheatsheet/type_casting.md @@ -6,5 +6,5 @@ The `into` method is used for conversion from a smaller data type to a larger da For example: ```cairo -// [!include ~/listings/cairo_cheatsheet/src/type_casting_example.cairo:sheet] +// [!include ~/listings/cairo_cheatsheet/listing/src/type_casting_example.cairo:sheet] ``` diff --git a/pages/cairo_cheatsheet/while.md b/pages/cairo_cheatsheet/while.md index 9c923fc0..8708df02 100644 --- a/pages/cairo_cheatsheet/while.md +++ b/pages/cairo_cheatsheet/while.md @@ -3,7 +3,7 @@ A `while` loop allows you to specify a condition that must be true for the loop to continue. ```cairo -// [!include ~/listings/cairo_cheatsheet/src/while_example.cairo:sheet] +// [!include ~/listings/cairo_cheatsheet/listing/src/while_example.cairo:sheet] ``` ### See also diff --git a/pages/cairo_cheatsheet/while_let.md b/pages/cairo_cheatsheet/while_let.md index f6013a94..8b77510a 100644 --- a/pages/cairo_cheatsheet/while_let.md +++ b/pages/cairo_cheatsheet/while_let.md @@ -3,7 +3,7 @@ A `while let` loop is a combination of a `while` loop and a `let` statement. It allows you to execute the loop body only if the pattern matches. ```cairo -// [!include ~/listings/cairo_cheatsheet/src/while_let_example.cairo:sheet] +// [!include ~/listings/cairo_cheatsheet/listing/src/while_let_example.cairo:sheet] ``` ### See also diff --git a/pages/getting-started/testing/contract-testing.md b/pages/getting-started/testing/contract-testing.md index 2deff011..bb650962 100644 --- a/pages/getting-started/testing/contract-testing.md +++ b/pages/getting-started/testing/contract-testing.md @@ -72,7 +72,7 @@ To make testing more convenient, the `testing` module of the corelib provides so - `pop_log>(address: ContractAddress) -> Option` - `pop_l2_to_l1_message(address: ContractAddress) -> Option<(felt252, Span)>` -You may also need the `info` module from the corelib, which allows you to access information about the current execution context (see [syscalls](/getting-started/basics/syscalls)): +You may also need the `info` module from the corelib, which allows you to access information about the current execution context (see [syscalls](/getting-started/syscalls)): - `get_caller_address() -> ContractAddress` - `get_contract_address() -> ContractAddress` From 43282229bcba56b62c4011ca97c5edb4473e1fcc Mon Sep 17 00:00:00 2001 From: julio4 <30329843+julio4@users.noreply.github.com> Date: Tue, 28 Jan 2025 23:07:45 +0100 Subject: [PATCH 44/44] feat: update CI/CD --- .github/workflows/verify_cairo_programs.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/verify_cairo_programs.yml b/.github/workflows/verify_cairo_programs.yml index 151ceee2..879699a3 100644 --- a/.github/workflows/verify_cairo_programs.yml +++ b/.github/workflows/verify_cairo_programs.yml @@ -4,9 +4,16 @@ on: pull_request: branches: - dev + - main workflow_dispatch: jobs: + typos: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: crate-ci/typos@master + compile_and_verify: runs-on: ubuntu-latest @@ -19,7 +26,7 @@ jobs: - name: Configure upstream repository run: | git remote add upstream https://github.com/NethermindEth/StarknetByExample - git fetch upstream main + git fetch upstream - name: Install scarb uses: software-mansion/setup-scarb@v1 @@ -27,13 +34,7 @@ jobs: - name: Install snforge uses: foundry-rs/setup-snfoundry@v3 - - name: Run build script + - name: Verify changes run: | chmod +x scripts/cairo_programs_verifier.sh ./scripts/cairo_programs_verifier.sh - - typos: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: crate-ci/typos@master