Skip to content
24 changes: 24 additions & 0 deletions components/Editor/DownloadProof.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
export const DownloadProof = ({ proof }: { proof: string }) => {
function handleDownloadProof() {
const content = proof
const blob = new Blob([content], { type: 'application/json' })
const url = window.URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = 'proof.json'
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
window.URL.revokeObjectURL(url)
}

return (
<>
Click{' '}
<button className="underline" onClick={handleDownloadProof}>
here
</button>{' '}
to download the proof
</>
)
}
21 changes: 16 additions & 5 deletions components/Editor/EditorControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Priority, useRegisterActions } from 'kbar'
import { OnChangeValue } from 'react-select'

import { Button, Input } from 'components/ui'
import MultiButton from 'components/ui/MultiButton'

import { cn } from '../../util/styles'

Expand All @@ -23,7 +24,7 @@ type EditorControlsProps = {
option: OnChangeValue<SelectOption, false>,
) => void
onCopyPermalink: () => void
onCompileRun: () => void
onCompileRun: (variant: 'run' | 'run-prove-verify') => void
onProgramArgumentsUpdate: (args: string) => void
onShowArgumentsHelper: () => void
}
Expand All @@ -48,7 +49,7 @@ const EditorControls = ({
keywords: 'compile run',
section: 'Execution',
perform: () => {
onCompileRun()
onCompileRun('run')
},
subtitle: 'Run execution',
priority: Priority.HIGH,
Expand Down Expand Up @@ -119,16 +120,26 @@ const EditorControls = ({
})}
/>

<div>
<Button
{/* <div> */}
<MultiButton onCompileRun={onCompileRun} />
{/* <div className="flex flex-row gap-x-2"> */}
{/* <Button
onClick={onCompileRun}
disabled={isCompileDisabled || !areProgramArgumentsValid}
size="sm"
contentClassName="justify-center"
>
Run
</Button>
</div>
<Button
onClick={onProveAndVerify}
disabled={isCompileDisabled || !areProgramArgumentsValid}
size="sm"
contentClassName="justify-center"
>
Prove & Verify
</Button> */}
{/* </div> */}
</div>
</div>
)
Expand Down
2 changes: 1 addition & 1 deletion components/Editor/EditorFooter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function EditorFooter({ withoutContent = false }) {
!isFullScreen && 'rounded-b-lg',
)}
>
<span>Cairo Compiler v2.8.0</span>
<span>Cairo Compiler v2.10.0</span>

{isFullScreen && (
<div className="flex items-center justify-end divide-x divide-gray-200 dark:divide-black-500">
Expand Down
88 changes: 49 additions & 39 deletions components/Editor/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const Examples: ExampleCode = {
Cairo: [
`use core::felt252;

#[executable]
fn main() -> felt252 {
let n = 2 + 3;
n
Expand All @@ -12,6 +13,7 @@ fn main() -> felt252 {

const my_constant: felt252 = 42;

#[executable]
fn main() {

// non-mutable variable
Expand All @@ -34,25 +36,27 @@ fn main() {

// my_mut_var = 'hello world' <-- fails to compile
}`,
`use core::felt252;

fn main() {
let my_felt252 = 10;

// Since a felt252 might not fit in a u8, we need to unwrap the Option<T> type
let my_u8: u8 = my_felt252.try_into().unwrap();

let my_u16: u16 = my_u8.into();
let my_u32: u32 = my_u16.into();
let my_u64: u64 = my_u32.into();
let _my_u128: u128 = my_u64.into();

// As a felt252 is smaller than a u256, we can use the into() method
let _my_u256: u256 = my_felt252.into();
let _my_usize: usize = my_felt252.try_into().unwrap();
let _my_other_felt252: felt252 = my_u8.into();
let _my_third_felt252: felt252 = my_u16.into();
}`,
// ,
// `use core::felt252;

// #[executable]
// fn main() {
// let my_felt252 = 10;

// // Since a felt252 might not fit in a u8, we need to unwrap the Option<T> type
// let my_u8: u8 = my_felt252.try_into().unwrap();

// let my_u16: u16 = my_u8.into();
// let my_u32: u32 = my_u16.into();
// let my_u64: u64 = my_u32.into();
// let _my_u128: u128 = my_u64.into();

// // As a felt252 is smaller than a u256, we can use the into() method
// let _my_u256: u256 = my_felt252.into();
// let _my_usize: usize = my_felt252.try_into().unwrap();
// let _my_other_felt252: felt252 = my_u8.into();
// let _my_third_felt252: felt252 = my_u16.into();
// }`
`#[derive(Drop)]
enum Direction {
Up,
Expand All @@ -61,6 +65,7 @@ enum Direction {
Right
}

#[executable]
fn main() {

// if / else expression
Expand Down Expand Up @@ -126,6 +131,7 @@ fn add(a: u32, b: u32) -> u64 {
}

// This functions doesn't return anything.
#[executable]
fn main() {
let a = 1;
let b = 2;
Expand All @@ -137,28 +143,30 @@ fn main() {
let _z = add(a: x, b: y);
}
`,
`use array::ArrayTrait;
// `use array::ArrayTrait;

fn main () {
let mut a = ArrayTrait::new();
// #[executable]
// fn main () {
// let mut a = ArrayTrait::new();

// add some items in the array
a.append(1);
a.append(2);

// get array length
assert!(a.len() == 2, "wrong array length");
// // add some items in the array
// a.append(1);
// a.append(2);

// 2 ways to read an item from the array
// * get() returns an Option so you can handle out-of-bounds error
// * at() panics in case of out-of-bounds error
let first_element = *a.get(0).unwrap().unbox();
// a.get(2) will return None
// // get array length
// assert!(a.len() == 2, "wrong array length");

let second_element = *a.at(1);
// a.at(2) will cause an error
}`,
`fn main () {
// // 2 ways to read an item from the array
// // * get() returns an Option so you can handle out-of-bounds error
// // * at() panics in case of out-of-bounds error
// let first_element = *a.get(0).unwrap().unbox();
// // a.get(2) will return None

// let second_element = *a.at(1);
// // a.at(2) will cause an error
// }`
`#[executable]
fn main () {
let mut balances: Felt252Dict<u64> = Default::default();

balances.insert('Alex', 100);
Expand All @@ -182,6 +190,7 @@ fn foo_receives_ref(ref arr: Array<u128>) {
// keeps the ownership of the array.
}

#[executable]
fn main() {
// as the creator of arr, the main function owns the array
let mut arr = ArrayTrait::<u128>::new();
Expand All @@ -197,6 +206,7 @@ fn main() {
}`,
`use core::felt252;

#[executable]
fn main() -> felt252 {
let n = 10;
let result = fib(1, 1, n);
Expand Down Expand Up @@ -494,10 +504,10 @@ ret;
export const CairoExampleNames = [
'Simple',
'Variables & mutability',
'Type casting',
// 'Type casting',
'Control flow',
'Functions',
'Arrays',
// 'Arrays',
'Dictionaries',
'Ownership',
'Fibonacci',
Expand Down
57 changes: 50 additions & 7 deletions components/Editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,12 @@ import { Setting, SettingsContext } from 'context/settingsContext'

import { getAbsoluteURL } from 'util/browser'
import { isArgumentStringValid } from 'util/compiler'
import { codeHighlight, isEmpty, objToQueryString } from 'util/string'
import {
codeHighlight,
formatTime,
isEmpty,
objToQueryString,
} from 'util/string'

import { Examples } from 'components/Editor/examples'
import { Tracer } from 'components/Tracer'
Expand All @@ -36,11 +41,13 @@ import { cn } from '../../util/styles'
import { ArgumentsHelperModal } from './ArgumentsHelperModal'
import { registerCairoLanguageSupport } from './cairoLangConfig'
import Console from './Console'
import { DownloadProof } from './DownloadProof'
import EditorControls from './EditorControls'
import EditorFooter from './EditorFooter'
import ExtraColumn from './ExtraColumn'
import Header from './Header'
import { InstructionsTable } from './InstructionsTable'

// @ts-ignore - Cairo is not part of the official highlightjs package
type Props = {
readOnly?: boolean
Expand Down Expand Up @@ -83,6 +90,10 @@ const Editor = ({ readOnly = false, isCairoLangPage = false }: Props) => {
debugMode,
activeSierraIndexes,
setDebugMode,
proof,
proofTime,
verificationTime,
provingIsNotSupported,
} = useContext(CairoVMApiContext)

const { addToConsoleLog, isThreeColumnLayout } = useContext(AppUiContext)
Expand Down Expand Up @@ -247,10 +258,34 @@ const Editor = ({ readOnly = false, isCairoLangPage = false }: Props) => {
}

if (executionState === ProgramExecutionState.Error) {
if (executionPanicMessage && executionPanicMessage.length > 0) {
addToConsoleLog(
'Runtime error: ' + executionPanicMessage,
LogType.Error,
)
} else {
addToConsoleLog('Runtime error', LogType.Error)
}
}

if (proof && proofTime) {
addToConsoleLog('Generating proof...', LogType.Info)
addToConsoleLog(
'Runtime error: ' + executionPanicMessage,
LogType.Error,
`Proof generation successful (finished in ${formatTime(proofTime)})`,
LogType.Info,
)
addToConsoleLog(<DownloadProof proof={proof} />, LogType.Info)
if (verificationTime) {
addToConsoleLog('Verifying proof...', LogType.Info)
addToConsoleLog(
`Verification successful (finished in ${formatTime(
verificationTime,
)})`,
LogType.Info,
)
}
} else if (provingIsNotSupported) {
addToConsoleLog('Proving is not supported for contracts', LogType.Error)
}
} else if (compilationState === ProgramCompilationState.CompilationErr) {
addToConsoleLog('Compilation failed', LogType.Error)
Expand Down Expand Up @@ -333,10 +368,18 @@ const Editor = ({ readOnly = false, isCairoLangPage = false }: Props) => {
[setProgramArguments],
)

const handleCompileRun = useCallback(() => {
compileCairoCode(cairoCode, removeExtraWhitespaces(programArguments))
setCompiledCairoCode(cairoCode)
}, [cairoCode, programArguments, compileCairoCode])
const handleCompileRun = useCallback(
async (variant: 'run' | 'run-prove-verify' | 'prove') => {
await compileCairoCode(
cairoCode,
removeExtraWhitespaces(programArguments),
variant === 'run-prove-verify',
variant === 'run-prove-verify',
)
setCompiledCairoCode(cairoCode)
},
[compileCairoCode, cairoCode, programArguments],
)

const handleCopyPermalink = useCallback(() => {
const params = {
Expand Down
Loading