Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@mischnic/json-sourcemap": "^0.1.1",
"@monaco-editor/react": "^4.6.0",
"@saucelabs/theme-github-codeblock": "^0.2.3",
"@shikijs/themes": "^2.2.0",
"ajv": "^8.12.0",
"clsx": "^1.2.1",
"docusaurus-json-schema-plugin": "^1.12.1",
Expand All @@ -38,6 +39,7 @@
"react": "^18.0.0",
"react-dom": "^18.0.0",
"react-markdown": "^9.0.1",
"shiki": "^2.2.0",
"ts-morph": "^22.0.0",
"yaml-template": "^1.0.0"
},
Expand Down
309 changes: 309 additions & 0 deletions packages/web/spec/program/example.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
---
sidebar_position: 3
---

import { ProgramExampleContextProvider, useProgramExampleContext, SourceContents, Opcodes, Viewer } from "@theme/ProgramExample";

# Example program

<ProgramExampleContextProvider
sources={[{
id: 0,
path: "PaidIncrementer.eg",
language: "examplelang",
contents: `name PaidIncrementer;

// define storage layout to include variable
// at slot 0
storage {
[0] storedValue: uint256;
}

// runtime logic
code {
// require fee for incrementing
if (msg.callvalue < 3 finney) {
return;
}

let localValue = storedValue + 1;
storedValue = localValue;
}
`}]}
instructions={[
{
operation: {
mnemonic: "PUSH6",
arguments: ["0x02ba7def3000"],
},
context: ({ findSourceRange }) => ({
code: findSourceRange("3 finney"),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}],
remark: "hexadecimal for 3 finney"
})
},
{
operation: {
mnemonic: "CALLVALUE"
},
context: ({ findSourceRange }) => ({
code: findSourceRange("msg.callvalue"),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}],
})
},
{
operation: {
mnemonic: "LT"
},
context: ({ findSourceRange }) => ({
code: findSourceRange("msg.callvalue < 3 finney"),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}],
})
},
{
operation: {
mnemonic: "PUSH1",
arguments: ["0x13"]
},
context: ({ findSourceRange }) => ({
code: findSourceRange("if (msg.callvalue < 3 finney) {\n return;\n }"),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}],
})
},
{
operation: {
mnemonic: "JUMPI"
},

context: ({ findSourceRange }) => ({
code: findSourceRange("if (msg.callvalue < 3 finney) {\n return;\n }"),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}],
remark: "jump to end unless sufficient fee"
})
},
{
operation: {
mnemonic: "PUSH0"
},
context: ({ findSourceRange }) => ({
code: findSourceRange("storedValue", { after: "localValue =" }),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}],
remark: "push stack slot of state variable"
})
},
{
operation: {
mnemonic: "SLOAD"
},
context: ({ findSourceRange }) => ({
code: findSourceRange("storedValue", { after: "let localValue" }),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}],
})
},
{
operation: {
mnemonic: "PUSH1",
arguments: ["0x01"]
},
context: ({ findSourceRange }) => ({
code: findSourceRange("1"),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}],
})
},
{
operation: {
mnemonic: "ADD"
},
context: ({ findSourceRange }) => ({
code: findSourceRange("let localValue = storedValue + 1;"),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}, {
identifier: "localValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "stack",
slot: 0
},
declaration: findSourceRange("let localValue")
}],
})
},
{
operation: {
mnemonic: "PUSH0"
},
context: ({ findSourceRange }) => ({
code: findSourceRange("storedValue ="),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}, {
identifier: "localValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "stack",
slot: 1
},
declaration: findSourceRange("let localValue")
}],
})
},
{
operation: {
mnemonic: "SSTORE"
},
context: ({ findSourceRange }) => ({
code: findSourceRange("storedValue = localValue;"),
variables: [{
identifier: "storedValue",
type: {
kind: "uint",
bits: 256
},
pointer: {
location: "storage",
slot: 0
},
declaration: findSourceRange("[0] storedValue: uint256")
}],
})
},
{
operation: {
mnemonic: "JUMPDEST"
},
context: ({ findSourceRange }) => ({
code: findSourceRange("return;"),
remark: "skip to here if not enough paid"
})
}
]}
>


This page helps illustrate the program schema's
[key concepts](/spec/program/concepts) by offering a fictional
pseudo-code example and its hypothetical compiled program.

Assume this fictional [somewhat] high-level language expects one contract per
source file, where each contract defines its storage layout, high-level logic,
and other metadata as top-level statements or blocks.

The following source code might be used to define a contract that
increments a state variable if the caller pays at least 1 finney (0.001 ETH).

<Viewer />

</ProgramExampleContextProvider>
19 changes: 19 additions & 0 deletions packages/web/src/theme/ProgramExample/HighlightedInstruction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React, { useEffect, useState } from "react";
import Admonition from "@theme/Admonition";
import Link from "@docusaurus/Link";
import { useProgramExampleContext } from "./ProgramExampleContext";

import { ShikiCodeBlock } from "@theme/ShikiCodeBlock";

export function HighlightedInstruction(): JSX.Element {
const { highlightedInstruction } = useProgramExampleContext();

return <>
<ShikiCodeBlock
language="javascript"
code={
JSON.stringify(highlightedInstruction, undefined, 2)
}
/>
</>;
}
38 changes: 38 additions & 0 deletions packages/web/src/theme/ProgramExample/Opcodes.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@


dl.opcodes {
display: grid;
grid-template-columns: max-content max-content;
margin: 0;
padding: 0;
align-items: justify;
}

dl.opcodes dt {
grid-column-start: 1;
border-radius: var(--ifm-global-radius);
padding: 5px 10px;
margin: 0px;
border-bottom-left-radius: 0px;
border-bottom-right-radius: 0px;
cursor: pointer;
}

dl.opcodes dt, dl.opcodes dt + dd{
margin-top: 5px;
border-bottom: 1px solid var(--ifm-color-primary-light);
}

dl.opcodes dd {
grid-column-start: 2;
margin: 0px;
padding: 5px 5px;
}

dl.opcodes dt.active {
background-color: var(--ifm-color-primary-lighter);
}

dl.opcodes dt:not(.active):hover {
background-color: var(--ifm-hover-overlay);
}
Loading