Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapt to starknet 0.11.0 #328

Merged
merged 62 commits into from
Apr 17, 2023
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
47b3e38
Update to cairo-lang 0.11.0a0 [skip ci]
Nathan-SL Mar 2, 2023
bf858aa
Support cairo1 compilation with manifest path [skip ci]
Nathan-SL Mar 15, 2023
41dbf34
WIP: Support for cairo1 compilation with docker [skip ci]
Nathan-SL Mar 15, 2023
80b8fe3
Merge branch 'master' into addapt-0.11.0
Nathan-SL Mar 15, 2023
c95c950
Set conditional volume to mount [skip ci]
Nathan-SL Mar 15, 2023
4f5c72d
Update python version
Nathan-SL Mar 27, 2023
f168d36
Change contract_address to sender_address
Nathan-SL Mar 27, 2023
9614128
Support declare v2 [skip ci]
Nathan-SL Mar 30, 2023
28904d9
Update to latest cairo-lang and starknet-devnet
Nathan-SL Mar 31, 2023
d15f9f7
Add declare v2 test
Nathan-SL Mar 31, 2023
3c8a467
Remove cargo_run func from starknet_cli_wrapper
Nathan-SL Apr 4, 2023
d6455a6
Update cairo1-compiler with docker
Nathan-SL Apr 4, 2023
a489ca1
Update cli funcs in test
Nathan-SL Apr 4, 2023
2830638
Adapt inputs and outputs based on new data types
Nathan-SL Apr 4, 2023
5a95efc
Support dokerized compilation for cairo1
Nathan-SL Apr 4, 2023
270add3
Update docs [skip ci]
Nathan-SL Apr 4, 2023
e5836b3
Recompiler support cairo1 constracts
Nathan-SL Apr 4, 2023
ddef382
Silent vmlang-rust test
Nathan-SL Apr 4, 2023
31b7e86
Adapt with starknet-devnet
Nathan-SL Apr 4, 2023
93d9bd2
Skip old cairo contracts on cairo1 compilation
Nathan-SL Apr 6, 2023
4b771e7
Add docs [skip ci]
Nathan-SL Apr 6, 2023
cc9c7f7
Remove arg [skip ci]
Nathan-SL Apr 6, 2023
5ec0369
Avoid cairo contract checking
Nathan-SL Apr 6, 2023
f138758
Update python version
Nathan-SL Apr 6, 2023
46aef66
Rename declare v2 constant
Nathan-SL Apr 7, 2023
63c0fbb
Add more common types
Nathan-SL Apr 7, 2023
d71f442
Add jsdoc for function formatSpaces
Nathan-SL Apr 7, 2023
50863de
Use separate interface for cairo1 compiler options
Nathan-SL Apr 7, 2023
da1e614
Set declarev2 private
Nathan-SL Apr 7, 2023
97ff6b3
Update cli docs
Nathan-SL Apr 11, 2023
f8e9fd4
Change type ContractClass to ts class
Nathan-SL Apr 11, 2023
cb381b8
Add function to check a constructor
Nathan-SL Apr 11, 2023
bdbfc95
Require maxFee for declareV2
Nathan-SL Apr 11, 2023
ac1a879
Add extra test
Nathan-SL Apr 12, 2023
886446a
Add cairo1-compiler to CI/CD
Nathan-SL Apr 12, 2023
bb6621f
Set file executable
Nathan-SL Apr 12, 2023
1f0cc05
Update script
Nathan-SL Apr 12, 2023
ff7d0d6
Update script
Nathan-SL Apr 12, 2023
f651a72
Update script
Nathan-SL Apr 12, 2023
719d609
Remove unused variable [skip ci]
Nathan-SL Apr 12, 2023
3b315c7
Update script
Nathan-SL Apr 12, 2023
47d7821
Update manifestPath
Nathan-SL Apr 12, 2023
d9e027c
Update script
Nathan-SL Apr 13, 2023
96eff06
Setup cairo1-compiler from package.json
Nathan-SL Apr 13, 2023
8637744
Remove source from scripts
Nathan-SL Apr 13, 2023
6ee1082
Update script
Nathan-SL Apr 14, 2023
eba36cb
Fix path
Nathan-SL Apr 14, 2023
dc78ddf
Add check for test subdir [skip ci]
Nathan-SL Apr 14, 2023
504c950
Add more type [skip ci]
Nathan-SL Apr 14, 2023
9ba7e4e
Avoid unnecessary venvPath checking
Nathan-SL Apr 17, 2023
556fa3b
Rename funcs
Nathan-SL Apr 17, 2023
299bf57
Remove unnecessary class property
Nathan-SL Apr 17, 2023
4e34b4a
Avoid if block
Nathan-SL Apr 17, 2023
83def43
Avoid duplicate logs
Nathan-SL Apr 17, 2023
12a7704
Remove optional param from start func
Nathan-SL Apr 17, 2023
9fa8a45
Enhance error message
Nathan-SL Apr 17, 2023
920f33e
Change class name
Nathan-SL Apr 17, 2023
84528c0
Update docs [skip ci]
Nathan-SL Apr 17, 2023
3dc9d4d
Remove bool from common types
Nathan-SL Apr 17, 2023
dd9a11f
Avoid use of docker server on DockerCairo1Compiler
Nathan-SL Apr 17, 2023
35247d5
Restore branch [skip ci]
Nathan-SL Apr 17, 2023
d118675
Update docs [skip ci]
Nathan-SL Apr 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions config.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"CAIRO_LANG": "0.10.3",
"STARKNET_DEVNET": "0.4.6"
"CAIRO_LANG": "0.11.0.1",
"STARKNET_DEVNET": "0.5.0a1"
}
2 changes: 1 addition & 1 deletion scripts/ensure-python.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

set -eu

PY_VERSION=3.8.9
PY_VERSION=3.9.0
FabijanC marked this conversation as resolved.
Show resolved Hide resolved

if [[ "$OSTYPE" == "linux-gnu"* ]]; then
which "/opt/circleci/.pyenv/versions/$PY_VERSION/bin/python" || pyenv install "$PY_VERSION"
Expand Down
2 changes: 1 addition & 1 deletion scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ CONFIG_FILE_NAME="hardhat.config.ts"

# setup example repo
rm -rf starknet-hardhat-example
EXAMPLE_REPO_BRANCH="plugin"
EXAMPLE_REPO_BRANCH="adapt-0.11.0"
if [[ "$CIRCLE_BRANCH" == "master" ]] && [[ "$EXAMPLE_REPO_BRANCH" != "plugin" ]]; then
echo "Invalid example repo branch: $EXAMPLE_REPO_BRANCH"
exit 1
Expand Down
2 changes: 1 addition & 1 deletion scripts/update-oz-account.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ GIT_VERSION="v$VERSION"

# create a venv
rm -rf tmp-venv
python3.8 -m venv tmp-venv
python3.9 -m venv tmp-venv
source tmp-venv/bin/activate

# create a tmp OZ repo
Expand Down
69 changes: 66 additions & 3 deletions src/account-utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { iterativelyCheckStatus, StarknetContract, StringMap } from "./types";
import { toBN } from "starknet/utils/number";
import {
ContractClass,
iterativelyCheckStatus,
Numeric,
StarknetContract,
StringMap
} from "./types";
import { toBN, toHex } from "starknet/utils/number";
import * as ellipticCurve from "starknet/utils/ellipticCurve";
import { ec } from "elliptic";
import { HardhatRuntimeEnvironment } from "hardhat/types";
Expand All @@ -10,7 +16,8 @@ import {
INTERNAL_ARTIFACTS_DIR,
TransactionHashPrefix,
TRANSACTION_VERSION,
StarknetChainId
StarknetChainId,
TRANSACTION_VERSION_TWO
} from "./constants";
import { numericToHexString } from "./utils";
import * as crypto from "crypto";
Expand Down Expand Up @@ -187,6 +194,62 @@ export async function sendDeployAccountTx(
});
}

export function calculateDeclareV2TxHash(
accountAddress: string,
callData: string[],
maxFee: string,
chainId: StarknetChainId,
additionalData: string[]
) {
const calldataHash = hash.computeHashOnElements(callData);
return hash.computeHashOnElements([
TransactionHashPrefix.DECLARE,
numericToHexString(TRANSACTION_VERSION_TWO),
accountAddress,
0, // entrypoint selector is implied
calldataHash,
maxFee,
chainId,
...additionalData
]);
}

export async function sendDeclareV2Tx(
signatures: string[],
classHash: string,
maxFee: Numeric,
senderAddress: string,
version: Numeric,
nonce: Numeric,
contractClass: ContractClass
) {
const hre = await import("hardhat");
const resp = await axios
.post(`${hre.starknet.networkConfig.url}/gateway/add_transaction`, {
type: "DECLARE",
contract_class: contractClass,
signature: signatures,
sender_address: senderAddress,
compiled_class_hash: toHex(toBN(classHash)),
version: numericToHexString(version),
nonce: numericToHexString(nonce),
max_fee: numericToHexString(maxFee)
})
.catch((error: AxiosError) => {
const msg = `Declaring contract failed: ${error.response.data.message}`;
throw new StarknetPluginError(msg, error);
});

return new Promise<string>((resolve, reject) => {
iterativelyCheckStatus(
resp.data.transaction_hash,
hre.starknetWrapper,
() => resolve(resp.data.transaction_hash),
reject
);
});
}

export async function sendEstimateFeeTx(data: unknown) {
const hre = await import("hardhat");
// To resolve TypeError: Do not know how to serialize a BigInt
Expand Down
49 changes: 48 additions & 1 deletion src/account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@ import {
StarknetChainId,
TransactionHashPrefix,
TRANSACTION_VERSION,
TRANSACTION_VERSION_TWO,
UDC_DEPLOY_FUNCTION_NAME
} from "./constants";
import { StarknetPluginError } from "./starknet-plugin-error";
import * as ellipticCurve from "starknet/utils/ellipticCurve";
import { BigNumberish, toBN } from "starknet/utils/number";
import { ec } from "elliptic";
import {
calculateDeclareV2TxHash,
calculateDeployAccountHash,
CallParameters,
generateKeys,
handleInternalContractArtifacts,
sendDeclareV2Tx,
sendDeployAccountTx,
sendEstimateFeeTx,
signMultiCall
Expand All @@ -41,7 +44,8 @@ import {
UDC,
readContract,
bnToDecimalStringArray,
estimatedFeeToMaxFee
estimatedFeeToMaxFee,
readCairo1Contract
} from "./utils";
import { Call, hash, RawCalldata } from "starknet";
import { getTransactionReceiptUtil } from "./extend-utils";
Expand Down Expand Up @@ -442,6 +446,49 @@ export abstract class Account {
maxFee: BigInt(maxFee)
});
}

public async declareV2(
FabijanC marked this conversation as resolved.
Show resolved Hide resolved
contractFactory: StarknetContractFactory,
options: DeclareOptions = {}
): Promise<string> {
const maxFee = options?.maxFee || 1e18; // Hardcoded value need to change
FabijanC marked this conversation as resolved.
Show resolved Hide resolved
if (maxFee && options?.overhead) {
const msg = "maxFee and overhead cannot be specified together";
throw new StarknetPluginError(msg);
}

const version = TRANSACTION_VERSION_TWO;
const nonce = options.nonce == null ? await this.getNonce() : options.nonce;
const hre = await import("hardhat");
const chainId = hre.starknet.networkConfig.starknetChainId;

const compiledClassHash = await hre.starknetWrapper.getCompiledClassHash(
contractFactory.casmPath
);
const classHash = await hre.starknetWrapper.getSierraContractClassHash(
contractFactory.metadataPath
);

const calldata = [classHash];
const messageHash = calculateDeclareV2TxHash(
this.address,
calldata,
maxFee.toString(),
chainId,
[nonce.toString(), compiledClassHash]
);

const signatures = this.getSignatures(messageHash);
return sendDeclareV2Tx(
bnToDecimalStringArray(signatures),
compiledClassHash,
maxFee,
this.address,
version,
nonce,
readCairo1Contract(contractFactory.metadataPath)
);
}
}

/**
Expand Down
17 changes: 12 additions & 5 deletions src/adapt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import { StringMap } from "./types";

const NAMED_TUPLE_DELIMITER = ": ";
const ARGUMENTS_DELIMITER = ", ";
FabijanC marked this conversation as resolved.
Show resolved Hide resolved
const COMMON_TYPES = [
"felt",
"core::felt252",
FabijanC marked this conversation as resolved.
Show resolved Hide resolved
"core::integer::u8",
"core::integer::u256",
"core::starknet::contract_address::ContractAddress"
];

function isNumeric(value: { toString: () => string }) {
if (value === undefined || value === null) {
Expand Down Expand Up @@ -147,7 +154,7 @@ export function adaptInputUtil(
for (let i = 0; i < inputSpecs.length; ++i) {
const inputSpec = inputSpecs[i];
const currentValue = input[inputSpec.name];
if (inputSpec.type === "felt") {
if (COMMON_TYPES.includes(inputSpec.type)) {
const errorMsg =
`${functionName}: Expected "${inputSpec.name}" to be a felt (Numeric); ` +
`got: ${typeof currentValue}`;
Expand Down Expand Up @@ -220,8 +227,7 @@ function adaptComplexInput(
if (input === undefined || input === null) {
throw new StarknetPluginError(`${inputSpec.name} is ${input}`);
}

if (type === "felt") {
if (COMMON_TYPES.includes(type)) {
if (isNumeric(input)) {
adaptedArray.push(toNumericString(input));
return;
Expand Down Expand Up @@ -339,7 +345,8 @@ export function adaptOutputUtil(

for (const outputSpec of outputSpecs) {
const currentValue = result[resultIndex];
if (outputSpec.type === "felt") {
if (COMMON_TYPES.includes(outputSpec.type)) {
outputSpec.name = outputSpec.name ?? "response";
adapted[outputSpec.name] = currentValue;
resultIndex++;
} else if (outputSpec.type.endsWith("*")) {
Expand Down Expand Up @@ -391,7 +398,7 @@ export function adaptOutputUtil(
* @returns an object consisting of the next unused index and the generated tuple/struct itself
*/
function generateComplexOutput(raw: bigint[], rawIndex: number, type: string, abi: starknet.Abi) {
if (type === "felt") {
if (COMMON_TYPES.includes(type)) {
return {
generatedComplex: raw[rawIndex],
newRawIndex: rawIndex + 1
Expand Down
100 changes: 100 additions & 0 deletions src/cairo1-compiler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { ProcessResult } from "@nomiclabs/hardhat-docker";
import shell from "shelljs";
import { Image } from "@nomiclabs/hardhat-docker";
import { DockerServer } from "./external-server/docker-server";
import { getFreePort } from "./external-server/external-server";
import { CommonSpawnOptions } from "child_process";

export const exec = (args: string) => {
const result = shell.exec(args);
return {
statusCode: result.code,
stdout: Buffer.from(result.stderr),
stderr: Buffer.from(result.stdout)
} as ProcessResult;
};

export class DockerCairo1Compiler extends DockerServer {
FabijanC marked this conversation as resolved.
Show resolved Hide resolved
constructor(
image: Image,
private sources: string[],
private cairo1CompilerArgs?: string[],
stdout?: string,
stderr?: string
) {
super(
image,
"127.0.0.1",
null,
"",
"starknet-docker-cairo1-compiler",
cairo1CompilerArgs,
stdout,
stderr
);
}

protected async getDockerArgs(): Promise<string[]> {
const volumes = [];
for (const source of this.sources) {
volumes.push("-v", `${source}:${source}`);
}

const dockerArgs = [...volumes];

if (this.isDockerDesktop) {
this.port = await this.getPort();
dockerArgs.push("-p", `${this.port}:${this.port}`);
} else {
dockerArgs.push("--network", "host");
}

return dockerArgs;
}

protected async getContainerArgs(): Promise<string[]> {
this.port = await this.getPort();
return ["/bin/sh", "-c", `"${this.cairo1CompilerArgs.join(" ")}"`];
}

protected async getPort(): Promise<string> {
if (!this.port) {
this.port = await getFreePort();
}
return this.port;
}

async compileCairo1(options?: CommonSpawnOptions): Promise<ProcessResult> {
const res = await this.spawnChildProcess(options);
const stdout: string[] = [];
const stderr: string[] = [];
let statusCode;

res.stdout.on("data", (chunk) => {
stdout.push(chunk);
console.log(chunk.toString());
});

res.stderr.on("data", (chunk) => {
stderr.push(chunk);
console.log(chunk.toString());
});

await new Promise((resolve, reject) => {
res.on("close", (code) => {
statusCode = code;
resolve(code);
});

res.on("error", (error) => {
reject(error);
});
});

return {
statusCode,
stdout: Buffer.from(stdout.toString()),
stderr: Buffer.from(stderr.toString())
} as ProcessResult;
}
}
4 changes: 4 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import config from "../config.json";

export const PLUGIN_NAME = "Starknet";
export const ABI_SUFFIX = "_abi.json";
export const CAIRO_ASSEMBLY_SUFFIX = ".casm";
export const CARGO_FILE = "Cargo.toml";
export const DOCKER_HOST_BIN_PATH = "/usr/local/bin/target/release";
export const DEFAULT_STARKNET_SOURCES_PATH = "contracts";
export const DEFAULT_STARKNET_ARTIFACTS_PATH = "starknet-artifacts";
export const DEFAULT_STARKNET_ACCOUNT_PATH = "~/.starknet_accounts";
Expand Down Expand Up @@ -61,6 +64,7 @@ export enum StarknetChainId {
export const PREFIX_TRANSACTION = "Starknet Transaction";

export const TRANSACTION_VERSION = BigInt(1);
export const TRANSACTION_VERSION_TWO = BigInt(2);
FabijanC marked this conversation as resolved.
Show resolved Hide resolved
export const QUERY_VERSION = BigInt(2) ** BigInt(128) + TRANSACTION_VERSION;

export const HEXADECIMAL_REGEX = /^0x[0-9a-fA-F]+?$/;
Expand Down