├── .github
├── FUNDING.yml
└── workflows
│ └── main.yml
├── .gitignore
├── .nosana-ci.yml
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── bindings
├── compile.ts
├── core.ts
├── helpers.ts
└── index.ts
├── common.ts
├── common_test.ts
├── deno.json
├── deno.lock
├── deps.ts
├── download.ts
├── download_test.ts
├── egg.json
├── examples
├── erc20
│ ├── ERC20.sol
│ ├── MyToken.sol
│ └── mod.ts
└── with-library
│ ├── Example.sol
│ ├── LibString.sol
│ └── mod.ts
├── helpers_test.ts
├── logo.png
├── mod.ts
├── mod_test.ts
└── types.ts
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: v1rtl
2 | liberapay: v1rtl
3 | custom: ["https://v1rtl.site/support"]
4 | issuehunt: talentlessguy
5 | github: [talentlessguy]
6 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | # Controls when the action will run. Triggers the workflow on push or pull request
4 | # events but only for the master branch
5 | on:
6 | push:
7 | branches: [master]
8 | pull_request:
9 | branches: [master]
10 |
11 | jobs:
12 | test:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/checkout@v4
16 |
17 | - name: Cache dependencies
18 | uses: actions/cache@v4
19 | with:
20 | key: ${{ runner.os }}-deno-${{ hashFiles('**/*') }}
21 | restore-keys: ${{ runner.os }}-deno-
22 | path: /home/runner/.cache/deno/deps/https/deno.land
23 |
24 | - uses: denoland/setup-deno@v2
25 | with:
26 | deno-version: v2.x
27 |
28 | - name: fetch any uncached dependencies
29 | run: |
30 | deno cache --reload=file: ./mod.ts
31 |
32 | - name: Run tests
33 | run: deno task test
34 | - name: Create coverage report
35 | run: deno task cov
36 | - name: Coveralls
37 | uses: coverallsapp/github-action@master
38 | with:
39 | github-token: ${{ secrets.GITHUB_TOKEN }}
40 | path-to-lcov: ./coverage.lcov
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.js
2 | *.cjs
3 | coverage*
--------------------------------------------------------------------------------
/.nosana-ci.yml:
--------------------------------------------------------------------------------
1 | # .nosana-ci.yml
2 | nosana:
3 | description: Nosana Deno Template
4 |
5 | global:
6 | image: denoland/deno:latest
7 |
8 | # Git, trigger on these branches
9 | trigger:
10 | branch:
11 | - master
12 |
13 | jobs:
14 | # Init Deno
15 | - name: install
16 | commands:
17 | - deno cache --reload=file: ./mod.ts
18 | - deno task test
19 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "deno.enable": true,
3 | "deno.lint": true,
4 | "deno.config": "./deno.json",
5 | "deno.suggest.imports.hosts": {
6 | "https://deno.land/x/": true,
7 | "https://x.nest.land/": true,
8 | "https://esm.sh": false
9 | },
10 | "[typescript]": {
11 | "editor.defaultFormatter": "denoland.vscode-deno"
12 | },
13 | "editor.formatOnSave": true
14 | }
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 deno-web3
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 | # solc
6 |
7 | [![GitHub Workflow Status][gh-actions-img]][github-actions]
8 | [![Codecov][cov-badge-url]][cov-url] [![][code-quality-img]][code-quality]
9 |
10 |
11 |
12 | Solidity bindings for Deno, based on [solc-js](https://github.com/ethereum/solc-js).
13 |
14 | Solidity 0.7+ is supported.
15 |
16 | For a CLI and a higher level API you can use [sol_build](https://github.com/deno-web3/sol_build).
17 |
18 | ## Docs
19 |
20 | See [solc-js README](https://github.com/ethereum/solc-js#readme) and [Deno doc](https://deno.land/x/solc/mod.ts).
21 |
22 | ## Example
23 |
24 | ```ts
25 | import { wrapper } from '@deno-web3/solc'
26 | import { Input } from '@deno-web3/solc/types'
27 | import { download } from '@deno-web3/solc/download'
28 | import { createRequire } from 'node:module'
29 |
30 | // Download latest Solidity compiler
31 | await download()
32 |
33 | const solc = wrapper(createRequire(import.meta.url)('./soljson.cjs'))
34 |
35 | const MyToken = await Deno.readTextFile('./MyToken.sol')
36 | const ERC20 = await Deno.readTextFile('./ERC20.sol')
37 |
38 | const input: Input = {
39 | language: 'Solidity',
40 | sources: {
41 | 'MyToken.sol': {
42 | content: MyToken,
43 | },
44 | 'ERC20.sol': {
45 | content: ERC20,
46 | },
47 | },
48 | settings: {
49 | outputSelection: {
50 | '*': {
51 | '*': ['*'],
52 | },
53 | },
54 | },
55 | }
56 | console.log(JSON.parse(solc.compile(JSON.stringify(input))))
57 | ```
58 |
59 | And then run with
60 |
61 | ```sh
62 | deno run --allow-net --allow-read --allow-write mod.ts
63 | ```
64 |
65 | [code-quality-img]: https://img.shields.io/codefactor/grade/github/deno-web3/solc?style=for-the-badge&color=626890&
66 | [code-quality]: https://www.codefactor.io/repository/github/deno-web3/solc
67 | [cov-badge-url]: https://img.shields.io/coveralls/github/deno-web3/solc?style=for-the-badge&color=626890&
68 | [cov-url]: https://coveralls.io/github/deno-web3/solc
69 | [github-actions]: https://github.com/tinyhttp/deno-web3/solc
70 | [gh-actions-img]: https://img.shields.io/github/actions/workflow/status/deno-web3/solc/main.yml?branch=master&style=for-the-badge&color=626890&label=&logo=github
71 |
--------------------------------------------------------------------------------
/bindings/compile.ts:
--------------------------------------------------------------------------------
1 | import assert from 'node:assert'
2 |
3 | import { bindSolcMethod } from './helpers.ts'
4 | import type { Callbacks, CompileBindings, CompileJsonStandard, CoreBindings, ReadCallback, SolJson } from 'solc/types'
5 |
6 | export function setupCompile(solJson: SolJson, core: CoreBindings): CompileBindings {
7 | return {
8 | compileStandard: bindCompileStandard(solJson, core),
9 | }
10 | }
11 |
12 | /**********************
13 | * COMPILE
14 | **********************/
15 |
16 | /**
17 | * Returns a binding to the solidity solidity_compile method.
18 | * input (jsontext), callback (optional >= v6 only - ptr) -> output (jsontext)
19 | *
20 | * @param solJson The Emscripten compiled Solidity object.
21 | * @param coreBindings The core bound Solidity methods.
22 | */
23 | function bindCompileStandard(solJson: SolJson, coreBindings: CoreBindings): CompileJsonStandard {
24 | // input (jsontext), callback (ptr), callback_context (ptr) -> output (jsontext)
25 | const boundFunctionSolidity: (jsontext: string, ptr?: number) => string = bindSolcMethod(
26 | solJson,
27 | 'solidity_compile',
28 | 'string',
29 | ['string', 'number', 'number'],
30 | null,
31 | )
32 |
33 | const boundFunctionStandard = function (input: string, callbacks: Callbacks) {
34 | return runWithCallbacks(solJson, coreBindings, callbacks, boundFunctionSolidity, [input])
35 | }
36 |
37 | return boundFunctionStandard as unknown as CompileJsonStandard
38 | }
39 |
40 | /**********************
41 | * CALL BACKS
42 | **********************/
43 |
44 | function wrapCallbackWithKind(
45 | coreBindings: CoreBindings,
46 | callback: (...args: Arg[]) => Partial<{ contents: unknown; error: unknown }>,
47 | ) {
48 | assert(typeof callback === 'function', 'Invalid callback specified.')
49 |
50 | return function (context: 0, kind: number, data: number, contents: number, error: number) {
51 | // Must be a null pointer.
52 | assert(context === 0, 'Callback context must be null.')
53 | console.log({ kind, data })
54 | const result = callback(coreBindings.copyFromCString(kind) as Arg, coreBindings.copyFromCString(data) as Arg)
55 | if (typeof result.contents === 'string') {
56 | coreBindings.copyToCString(result.contents, contents)
57 | }
58 | if (typeof result.error === 'string') {
59 | coreBindings.copyToCString(result.error, error)
60 | }
61 | }
62 | }
63 |
64 | // calls compile() with args || cb
65 | function runWithCallbacks(
66 | _solJson: SolJson,
67 | coreBindings: CoreBindings,
68 | callbacks?: Callbacks | ReadCallback,
69 | compile?: (...args: Args) => void,
70 | args: Args = [] as unknown as Args,
71 | ) {
72 | if (callbacks) {
73 | assert(typeof callbacks === 'object', 'Invalid callback object specified.')
74 | } else {
75 | callbacks = {}
76 | }
77 |
78 | let readCallback = callbacks.import
79 | if (readCallback === undefined) {
80 | readCallback = function () {
81 | return {
82 | error: 'File import callback not supported',
83 | }
84 | }
85 | }
86 |
87 | let singleCallback
88 | // After 0.6.x multiple kind of callbacks are supported.
89 | let smtSolverCallback = callbacks.smtSolver
90 | if (smtSolverCallback === undefined) {
91 | smtSolverCallback = function () {
92 | return {
93 | error: 'SMT solver callback not supported',
94 | }
95 | }
96 | }
97 |
98 | singleCallback = function (kind: 'source' | 'smt-query', data: string) {
99 | if (kind === 'source') {
100 | return readCallback(data)
101 | } else if (kind === 'smt-query') {
102 | return smtSolverCallback(data)
103 | } else {
104 | assert(false, 'Invalid callback kind specified.')
105 | }
106 | }
107 |
108 | singleCallback = wrapCallbackWithKind<'source' | 'smt-query'>(coreBindings, singleCallback)
109 |
110 | const cb = coreBindings.addFunction(singleCallback, 'viiiii')
111 | let output
112 | try {
113 | args.push(cb)
114 |
115 | // Callback context.
116 | args.push(null)
117 |
118 | output = compile?.(...args)
119 | } finally {
120 | coreBindings.removeFunction(cb)
121 | }
122 |
123 | if (coreBindings.reset) {
124 | // Explicitly free memory.
125 | //
126 | // NOTE: cwrap() of "compile" will copy the returned pointer into a
127 | // Javascript string and it is not possible to call free() on it.
128 | // reset() however will clear up all allocations.
129 | coreBindings.reset()
130 | }
131 | return output
132 | }
133 |
--------------------------------------------------------------------------------
/bindings/core.ts:
--------------------------------------------------------------------------------
1 | import type { Alloc, CoreBindings, License, Reset, SolJson } from 'solc/types'
2 | import { bindSolcMethod, bindSolcMethodWithFallbackFunc } from './helpers.ts'
3 |
4 | export function setupCore(solJson: SolJson): CoreBindings {
5 | const core = {
6 | alloc: bindAlloc(solJson),
7 | license: bindLicense(solJson),
8 | version: bindVersion<() => string>(solJson),
9 | reset: bindReset(solJson),
10 | }
11 |
12 | const helpers = {
13 | // @ts-expect-error binding to this
14 | addFunction: unboundAddFunction.bind(this, solJson),
15 | // @ts-expect-error binding to this
16 | removeFunction: unboundRemoveFunction.bind(this, solJson),
17 | // @ts-expect-error binding to this
18 | copyFromCString: unboundCopyFromCString.bind(this, solJson),
19 | // @ts-expect-error binding to this
20 | copyToCString: unboundCopyToCString.bind(this, solJson, core.alloc),
21 | }
22 |
23 | return {
24 | ...core,
25 | ...helpers,
26 | }
27 | }
28 |
29 | /**********************
30 | * Core Functions
31 | **********************/
32 |
33 | /**
34 | * Returns a binding to the solidity_alloc function.
35 | *
36 | * @param solJson The Emscripten compiled Solidity object.
37 | */
38 | function bindAlloc(solJson: SolJson) {
39 | const allocBinding = bindSolcMethod(
40 | solJson,
41 | 'solidity_alloc',
42 | 'number',
43 | ['number'],
44 | null,
45 | )
46 |
47 | return allocBinding
48 | }
49 |
50 | /**
51 | * Returns a binding to the solidity_version method.
52 | *
53 | * @param solJson The Emscripten compiled Solidity object.
54 | */
55 | function bindVersion(solJson: SolJson) {
56 | return bindSolcMethodWithFallbackFunc(
57 | solJson,
58 | 'solidity_version',
59 | 'string',
60 | [],
61 | 'version',
62 | )
63 | }
64 |
65 | /**
66 | * Returns a binding to the solidity_license method.
67 | *
68 | * If the current solJson version < 0.4.14 then this will bind an empty function.
69 | *
70 | * @param solJson The Emscripten compiled Solidity object.
71 | */
72 | function bindLicense(solJson: SolJson) {
73 | return bindSolcMethodWithFallbackFunc(
74 | solJson,
75 | 'solidity_license',
76 | 'string',
77 | [],
78 | 'license',
79 | () => {
80 | },
81 | )
82 | }
83 |
84 | /**
85 | * Returns a binding to the solidity_reset method.
86 | *
87 | * @param solJson The Emscripten compiled Solidity object.
88 | */
89 | function bindReset(solJson: SolJson) {
90 | return bindSolcMethod(
91 | solJson,
92 | 'solidity_reset',
93 | null,
94 | [],
95 | null,
96 | )
97 | }
98 |
99 | /**********************
100 | * Helpers Functions
101 | **********************/
102 |
103 | /**
104 | * Copy to a C string.
105 | *
106 | * Allocates memory using solc's allocator.
107 | *
108 | * Before 0.6.0:
109 | * Assuming copyToCString is only used in the context of wrapCallback, solc will free these pointers.
110 | * See https://github.com/ethereum/solidity/blob/v0.5.13/libsolc/libsolc.h#L37-L40
111 | *
112 | * After 0.6.0:
113 | * The duty is on solc-js to free these pointers. We accomplish that by calling `reset` at the end.
114 | *
115 | * @param solJson The Emscripten compiled Solidity object.
116 | * @param alloc The memory allocation function.
117 | * @param str The source string being copied to a C string.
118 | * @param ptr The pointer location where the C string will be set.
119 | */
120 | function unboundCopyToCString(solJson: SolJson, alloc: Alloc, str: string, ptr: number) {
121 | const length = solJson.lengthBytesUTF8(str)
122 |
123 | const buffer = alloc(length + 1)
124 |
125 | solJson.stringToUTF8(str, buffer, length + 1)
126 | solJson.setValue(ptr, buffer, '*')
127 |
128 | return str
129 | }
130 |
131 | /**
132 | * Wrapper over Emscripten's C String copying function (which can be different
133 | * on different versions).
134 | *
135 | * @param solJson The Emscripten compiled Solidity object.
136 | * @param ptr The pointer location where the C string will be referenced.
137 | */
138 | function unboundCopyFromCString(solJson: SolJson, ptr: number) {
139 | return solJson.UTF8ToString(ptr)
140 | }
141 |
142 | function unboundAddFunction(solJson: SolJson, func: (...args: unknown[]) => unknown, signature?: string) {
143 | return solJson.addFunction(func, signature)
144 | }
145 |
146 | function unboundRemoveFunction(solJson: SolJson, ptr: number) {
147 | return solJson.removeFunction(ptr)
148 | }
149 |
--------------------------------------------------------------------------------
/bindings/helpers.ts:
--------------------------------------------------------------------------------
1 | import { isNil } from '../common.ts'
2 | import type { SolJson } from 'solc/types'
3 |
4 | export function bindSolcMethod(
5 | solJson: SolJson,
6 | method: string,
7 | returnType: string | null,
8 | args: string[],
9 | defaultValue?: unknown,
10 | ): T {
11 | if (isNil(solJson[`_${method}` as keyof typeof solJson]) && defaultValue !== undefined) {
12 | return defaultValue as T
13 | }
14 |
15 | return solJson.cwrap(method, returnType, args)
16 | }
17 |
18 | export function bindSolcMethodWithFallbackFunc(
19 | solJson: SolJson,
20 | method: string,
21 | returnType: string | null,
22 | args: string[],
23 | fallbackMethod: string,
24 | finalFallback: (() => void) | undefined = undefined,
25 | ): T {
26 | const methodFunc = bindSolcMethod(solJson, method, returnType, args, null)
27 |
28 | if (!isNil(methodFunc)) {
29 | return methodFunc as T
30 | }
31 |
32 | return bindSolcMethod(solJson, fallbackMethod, returnType, args, finalFallback)
33 | }
34 |
35 | export function getSupportedMethods(solJson: SolJson) {
36 | return {
37 | licenseSupported: anyMethodExists(solJson, 'solidity_license'),
38 | versionSupported: anyMethodExists(solJson, 'solidity_version'),
39 | allocSupported: anyMethodExists(solJson, 'solidity_alloc'),
40 | resetSupported: anyMethodExists(solJson, 'solidity_reset'),
41 | compileJsonStandardSupported: anyMethodExists(solJson, 'compileStandard', 'solidity_compile'),
42 | }
43 | }
44 |
45 | function anyMethodExists(solJson: SolJson, ...names: string[]) {
46 | return names.some((name) => !isNil(solJson[`_${name}` as keyof typeof solJson]))
47 | }
48 |
--------------------------------------------------------------------------------
/bindings/index.ts:
--------------------------------------------------------------------------------
1 | import type { SolJson } from 'solc/types'
2 | import { setupCompile } from './compile.ts'
3 | import { setupCore } from './core.ts'
4 | import { getSupportedMethods } from './helpers.ts'
5 |
6 | export default function setupBindings(solJson: SolJson) {
7 | const coreBindings = setupCore(solJson)
8 |
9 | const compileBindings = setupCompile(solJson, coreBindings)
10 |
11 | const methodFlags = getSupportedMethods(solJson)
12 |
13 | return {
14 | methodFlags,
15 | coreBindings,
16 | compileBindings,
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/common.ts:
--------------------------------------------------------------------------------
1 | export const isNil = (value: unknown): value is null => value == null
2 |
--------------------------------------------------------------------------------
/common_test.ts:
--------------------------------------------------------------------------------
1 | import { isNil } from './common.ts'
2 | import { expect } from '@std/expect'
3 | import { describe, it } from '@std/testing/bdd'
4 |
5 | describe('common.ts', () => {
6 | it('isNil', () => {
7 | expect(isNil(null)).toBe(true)
8 | expect(isNil(undefined)).toBe(true)
9 | expect(isNil(0)).toBe(false)
10 | expect(isNil('')).toBe(false)
11 | })
12 | })
13 |
--------------------------------------------------------------------------------
/deno.json:
--------------------------------------------------------------------------------
1 | {
2 | "lint": {
3 | "include": ["./**/*.ts"],
4 | "exclude": ["./**/*.js"],
5 | "rules": {
6 | "exclude": ["no-explicit-any"]
7 | }
8 | },
9 | "fmt": {
10 | "include": ["./**/*.ts", "./**/*.md", "./**/*.json"],
11 | "exclude": ["./**/*.js"],
12 | "singleQuote": true,
13 | "semiColons": false,
14 | "useTabs": false,
15 | "indentWidth": 2,
16 | "lineWidth": 120
17 | },
18 | "imports": {
19 | "@std/expect": "jsr:@std/expect@^1.0.13",
20 | "@std/io": "jsr:@std/io@^0.225.2",
21 | "@std/testing": "jsr:@std/testing@^1.0.9",
22 | "solc": "./mod.ts",
23 | "solc/download": "./download.ts",
24 | "solc/types": "./types.ts"
25 | },
26 | "test": {
27 | "exclude": ["./**/*.js", "examples"]
28 | },
29 | "tasks": {
30 | "test": "deno test --no-check --allow-net --allow-read --allow-write --coverage=coverage",
31 | "cov": "deno coverage coverage --lcov > coverage.lcov"
32 | },
33 | "name": "@deno-web3/solc",
34 | "version": "3.0.0",
35 | "license": "MIT",
36 | "exports": {
37 | ".": "./mod.ts",
38 | "./download": "./download.ts",
39 | "./types": "./types.ts"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/deno.lock:
--------------------------------------------------------------------------------
1 | {
2 | "version": "4",
3 | "specifiers": {
4 | "jsr:@std/assert@^1.0.10": "1.0.11",
5 | "jsr:@std/assert@^1.0.11": "1.0.11",
6 | "jsr:@std/bytes@^1.0.5": "1.0.5",
7 | "jsr:@std/expect@^1.0.13": "1.0.13",
8 | "jsr:@std/internal@^1.0.5": "1.0.5",
9 | "jsr:@std/io@~0.225.2": "0.225.2",
10 | "jsr:@std/testing@^1.0.9": "1.0.9",
11 | "npm:@types/node@*": "22.12.0"
12 | },
13 | "jsr": {
14 | "@std/assert@1.0.11": {
15 | "integrity": "2461ef3c368fe88bc60e186e7744a93112f16fd110022e113a0849e94d1c83c1",
16 | "dependencies": [
17 | "jsr:@std/internal"
18 | ]
19 | },
20 | "@std/bytes@1.0.5": {
21 | "integrity": "4465dd739d7963d964c809202ebea6d5c6b8e3829ef25c6a224290fbb8a1021e"
22 | },
23 | "@std/expect@1.0.13": {
24 | "integrity": "d8e236c7089cd9fcf5e6032f27dadc3db6349d0aee48c15bc71d717bca5baa42",
25 | "dependencies": [
26 | "jsr:@std/assert@^1.0.11",
27 | "jsr:@std/internal"
28 | ]
29 | },
30 | "@std/internal@1.0.5": {
31 | "integrity": "54a546004f769c1ac9e025abd15a76b6671ddc9687e2313b67376125650dc7ba"
32 | },
33 | "@std/io@0.225.2": {
34 | "integrity": "3c740cd4ee4c082e6cfc86458f47e2ab7cb353dc6234d5e9b1f91a2de5f4d6c7",
35 | "dependencies": [
36 | "jsr:@std/bytes"
37 | ]
38 | },
39 | "@std/testing@1.0.9": {
40 | "integrity": "9bdd4ac07cb13e7594ac30e90f6ceef7254ac83a9aeaa089be0008f33aab5cd4",
41 | "dependencies": [
42 | "jsr:@std/assert@^1.0.10",
43 | "jsr:@std/internal"
44 | ]
45 | }
46 | },
47 | "npm": {
48 | "@types/node@22.12.0": {
49 | "integrity": "sha512-Fll2FZ1riMjNmlmJOdAyY5pUbkftXslB5DgEzlIuNaiWhXd00FhWxVC/r4yV/4wBb9JfImTu+jiSvXTkJ7F/gA==",
50 | "dependencies": [
51 | "undici-types"
52 | ]
53 | },
54 | "undici-types@6.20.0": {
55 | "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="
56 | }
57 | },
58 | "workspace": {
59 | "dependencies": [
60 | "jsr:@std/expect@^1.0.13",
61 | "jsr:@std/io@~0.225.2",
62 | "jsr:@std/testing@^1.0.9"
63 | ]
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/deps.ts:
--------------------------------------------------------------------------------
1 | export { readerFromStreamReader } from '@std/io/reader-from-stream-reader'
2 | export { copy } from '@std/io/copy'
3 |
--------------------------------------------------------------------------------
/download.ts:
--------------------------------------------------------------------------------
1 | import { copy, readerFromStreamReader } from './deps.ts'
2 |
3 | /**
4 | * Downloads Solidity compiler
5 | * @param path download destination
6 | * @param version compiler version. if not specified, latest is downloaded
7 | */
8 | export const download = async (path = './soljson.cjs', version?: string): Promise => {
9 | console.log(`Fetching releases...`)
10 | const { releases, latestRelease } =
11 | (await fetch('https://binaries.soliditylang.org/emscripten-wasm32/list.json').then((res) => res.json())) as {
12 | releases: Record
13 | latestRelease: string
14 | }
15 |
16 | const jsFile: string = releases[version || latestRelease]
17 |
18 | if (!jsFile) throw new Error(`version ${version} not found`)
19 |
20 | console.log(`Downloading soljson from https://binaries.soliditylang.org/emscripten-wasm32/${jsFile}...`)
21 |
22 | const res = await fetch(`https://binaries.soliditylang.org/emscripten-wasm32/${jsFile}`)
23 |
24 | const rdr = res.body?.getReader()
25 |
26 | if (rdr) {
27 | const r = readerFromStreamReader(rdr)
28 | const f = await Deno.open(path, { create: true, write: true })
29 | await copy(r, f)
30 | f.close()
31 | }
32 |
33 | return jsFile
34 | }
35 |
--------------------------------------------------------------------------------
/download_test.ts:
--------------------------------------------------------------------------------
1 | import { describe, it } from '@std/testing/bdd'
2 | import { expect } from '@std/expect'
3 | import { download } from 'solc/download'
4 | import { exists } from './helpers_test.ts'
5 |
6 | describe('solc/download.ts', () => {
7 | it('downloads latest version to soljson.cjs file', async () => {
8 | await download()
9 | expect(await exists('./soljson.cjs')).toBe(true)
10 | })
11 | it('downloads latest version to any file path', async () => {
12 | await download('./solc.cjs')
13 | expect(await exists('./solc.cjs')).toBe(true)
14 | await Deno.remove('./solc.cjs')
15 | })
16 | it('downloads a specific version', async () => {
17 | const jsFile = await download('./soljson.cjs', '0.8.17')
18 |
19 | expect(jsFile).toEqual('solc-emscripten-wasm32-v0.8.17+commit.8df45f5f.js')
20 | })
21 | it('throws if version does not exist', async () => {
22 | try {
23 | await download('./soljson.cjs', '12.456.789')
24 | } catch (e) {
25 | expect((e as Error).message).toEqual('version 12.456.789 not found')
26 | }
27 | })
28 | })
29 |
--------------------------------------------------------------------------------
/egg.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://x.nest.land/eggs@0.3.8/src/schema.json",
3 | "name": "solc",
4 | "entry": "./mod.ts",
5 | "description": "💎 Solidity v0.8.7 bindings for Deno",
6 | "homepage": "https://github.com/deno-libs/solc",
7 | "version": "2.1.4",
8 | "releaseType": "patch",
9 | "unstable": false,
10 | "unlisted": false,
11 | "files": [
12 | "README.md",
13 | "*.ts",
14 | "LICENSE"
15 | ],
16 | "ignore": [],
17 | "checkFormat": false,
18 | "checkTests": false,
19 | "checkInstallation": true,
20 | "check": true,
21 | "checkAll": true,
22 | "repository": "https://github.com/deno-libs/solc"
23 | }
24 |
--------------------------------------------------------------------------------
/examples/erc20/ERC20.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: AGPL-3.0-only
2 | pragma solidity >=0.8.0;
3 |
4 | /// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.
5 | /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC20.sol)
6 | /// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)
7 | /// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.
8 | abstract contract ERC20 {
9 | /*//////////////////////////////////////////////////////////////
10 | EVENTS
11 | //////////////////////////////////////////////////////////////*/
12 |
13 | event Transfer(address indexed from, address indexed to, uint256 amount);
14 |
15 | event Approval(address indexed owner, address indexed spender, uint256 amount);
16 |
17 | /*//////////////////////////////////////////////////////////////
18 | METADATA STORAGE
19 | //////////////////////////////////////////////////////////////*/
20 |
21 | string public name;
22 |
23 | string public symbol;
24 |
25 | uint8 public immutable decimals;
26 |
27 | /*//////////////////////////////////////////////////////////////
28 | ERC20 STORAGE
29 | //////////////////////////////////////////////////////////////*/
30 |
31 | uint256 public totalSupply;
32 |
33 | mapping(address => uint256) public balanceOf;
34 |
35 | mapping(address => mapping(address => uint256)) public allowance;
36 |
37 | /*//////////////////////////////////////////////////////////////
38 | EIP-2612 STORAGE
39 | //////////////////////////////////////////////////////////////*/
40 |
41 | uint256 internal immutable INITIAL_CHAIN_ID;
42 |
43 | bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;
44 |
45 | mapping(address => uint256) public nonces;
46 |
47 | /*//////////////////////////////////////////////////////////////
48 | CONSTRUCTOR
49 | //////////////////////////////////////////////////////////////*/
50 |
51 | constructor(
52 | string memory _name,
53 | string memory _symbol,
54 | uint8 _decimals
55 | ) {
56 | name = _name;
57 | symbol = _symbol;
58 | decimals = _decimals;
59 |
60 | INITIAL_CHAIN_ID = block.chainid;
61 | INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
62 | }
63 |
64 | /*//////////////////////////////////////////////////////////////
65 | ERC20 LOGIC
66 | //////////////////////////////////////////////////////////////*/
67 |
68 | function approve(address spender, uint256 amount) public virtual returns (bool) {
69 | allowance[msg.sender][spender] = amount;
70 |
71 | emit Approval(msg.sender, spender, amount);
72 |
73 | return true;
74 | }
75 |
76 | function transfer(address to, uint256 amount) public virtual returns (bool) {
77 | balanceOf[msg.sender] -= amount;
78 |
79 | // Cannot overflow because the sum of all user
80 | // balances can't exceed the max uint256 value.
81 | unchecked {
82 | balanceOf[to] += amount;
83 | }
84 |
85 | emit Transfer(msg.sender, to, amount);
86 |
87 | return true;
88 | }
89 |
90 | function transferFrom(
91 | address from,
92 | address to,
93 | uint256 amount
94 | ) public virtual returns (bool) {
95 | uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.
96 |
97 | if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;
98 |
99 | balanceOf[from] -= amount;
100 |
101 | // Cannot overflow because the sum of all user
102 | // balances can't exceed the max uint256 value.
103 | unchecked {
104 | balanceOf[to] += amount;
105 | }
106 |
107 | emit Transfer(from, to, amount);
108 |
109 | return true;
110 | }
111 |
112 | /*//////////////////////////////////////////////////////////////
113 | EIP-2612 LOGIC
114 | //////////////////////////////////////////////////////////////*/
115 |
116 | function permit(
117 | address owner,
118 | address spender,
119 | uint256 value,
120 | uint256 deadline,
121 | uint8 v,
122 | bytes32 r,
123 | bytes32 s
124 | ) public virtual {
125 | require(deadline >= block.timestamp, "PERMIT_DEADLINE_EXPIRED");
126 |
127 | // Unchecked because the only math done is incrementing
128 | // the owner's nonce which cannot realistically overflow.
129 | unchecked {
130 | address recoveredAddress = ecrecover(
131 | keccak256(
132 | abi.encodePacked(
133 | "\x19\x01",
134 | DOMAIN_SEPARATOR(),
135 | keccak256(
136 | abi.encode(
137 | keccak256(
138 | "Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)"
139 | ),
140 | owner,
141 | spender,
142 | value,
143 | nonces[owner]++,
144 | deadline
145 | )
146 | )
147 | )
148 | ),
149 | v,
150 | r,
151 | s
152 | );
153 |
154 | require(recoveredAddress != address(0) && recoveredAddress == owner, "INVALID_SIGNER");
155 |
156 | allowance[recoveredAddress][spender] = value;
157 | }
158 |
159 | emit Approval(owner, spender, value);
160 | }
161 |
162 | function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
163 | return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
164 | }
165 |
166 | function computeDomainSeparator() internal view virtual returns (bytes32) {
167 | return
168 | keccak256(
169 | abi.encode(
170 | keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"),
171 | keccak256(bytes(name)),
172 | keccak256("1"),
173 | block.chainid,
174 | address(this)
175 | )
176 | );
177 | }
178 |
179 | /*//////////////////////////////////////////////////////////////
180 | INTERNAL MINT/BURN LOGIC
181 | //////////////////////////////////////////////////////////////*/
182 |
183 | function _mint(address to, uint256 amount) internal virtual {
184 | totalSupply += amount;
185 |
186 | // Cannot overflow because the sum of all user
187 | // balances can't exceed the max uint256 value.
188 | unchecked {
189 | balanceOf[to] += amount;
190 | }
191 |
192 | emit Transfer(address(0), to, amount);
193 | }
194 |
195 | function _burn(address from, uint256 amount) internal virtual {
196 | balanceOf[from] -= amount;
197 |
198 | // Cannot underflow because a user's balance
199 | // will never be larger than the total supply.
200 | unchecked {
201 | totalSupply -= amount;
202 | }
203 |
204 | emit Transfer(from, address(0), amount);
205 | }
206 | }
207 |
--------------------------------------------------------------------------------
/examples/erc20/MyToken.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.8;
3 |
4 | import {ERC20} from "./ERC20.sol";
5 |
6 | /**
7 | * @dev This is an example contract implementation of NFToken with metadata extension.
8 | */
9 | contract MyToken is ERC20 {
10 | constructor() ERC20("MyToken", "MYTOKEN", 18) {}
11 |
12 | function mint(address to, uint256 value) external {
13 | _mint(to, value);
14 | }
15 |
16 | function burn(address from, uint256 value) external {
17 | _burn(from, value);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/examples/erc20/mod.ts:
--------------------------------------------------------------------------------
1 | import { wrapper } from 'solc'
2 | import type { Input, Output } from 'solc/types'
3 | import { download } from 'solc/download'
4 | import { exists } from '../../helpers_test.ts'
5 |
6 | if (!(await exists('./soljson.cjs'))) await download()
7 |
8 | const mod = await import('./soljson.cjs')
9 |
10 | const solc = wrapper(mod.default)
11 |
12 | const MyToken = await Deno.readTextFile('./MyToken.sol')
13 | const ERC20 = await Deno.readTextFile('./ERC20.sol')
14 |
15 | const input: Input = {
16 | language: 'Solidity',
17 | sources: {
18 | 'MyToken.sol': {
19 | content: MyToken,
20 | },
21 | 'ERC20.sol': {
22 | content: ERC20,
23 | },
24 | },
25 | settings: {
26 | outputSelection: {
27 | '*': {
28 | '*': ['*'],
29 | },
30 | },
31 | },
32 | }
33 |
34 | const result = JSON.parse(solc.compile(JSON.stringify(input))) as Output
35 |
36 | console.log(result)
37 |
--------------------------------------------------------------------------------
/examples/with-library/Example.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.8;
3 |
4 | import { LibString } from "./LibString.sol";
5 |
6 | contract Example {
7 | function stringify(int256 value) external pure returns (string memory) {
8 | return LibString.toString(value);
9 | }
10 | }
--------------------------------------------------------------------------------
/examples/with-library/LibString.sol:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: MIT
2 | pragma solidity >=0.8.0;
3 |
4 | /// @notice Efficient library for creating string representations of integers.
5 | /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
6 | /// @author Modified from Solady (https://github.com/Vectorized/solady/blob/main/src/utils/LibString.sol)
7 | library LibString {
8 | function toString(int256 value) internal pure returns (string memory str) {
9 | if (value >= 0) return toString(uint256(value));
10 |
11 | unchecked {
12 | str = toString(uint256(-value));
13 |
14 | /// @solidity memory-safe-assembly
15 | assembly {
16 | // Note: This is only safe because we over-allocate memory
17 | // and write the string from right to left in toString(uint256),
18 | // and thus can be sure that sub(str, 1) is an unused memory location.
19 |
20 | let length := mload(str) // Load the string length.
21 | // Put the - character at the start of the string contents.
22 | mstore(str, 45) // 45 is the ASCII code for the - character.
23 | str := sub(str, 1) // Move back the string pointer by a byte.
24 | mstore(str, add(length, 1)) // Update the string length.
25 | }
26 | }
27 | }
28 |
29 | function toString(uint256 value) internal pure returns (string memory str) {
30 | /// @solidity memory-safe-assembly
31 | assembly {
32 | // The maximum value of a uint256 contains 78 digits (1 byte per digit), but we allocate 160 bytes
33 | // to keep the free memory pointer word aligned. We'll need 1 word for the length, 1 word for the
34 | // trailing zeros padding, and 3 other words for a max of 78 digits. In total: 5 * 32 = 160 bytes.
35 | let newFreeMemoryPointer := add(mload(0x40), 160)
36 |
37 | // Update the free memory pointer to avoid overriding our string.
38 | mstore(0x40, newFreeMemoryPointer)
39 |
40 | // Assign str to the end of the zone of newly allocated memory.
41 | str := sub(newFreeMemoryPointer, 32)
42 |
43 | // Clean the last word of memory it may not be overwritten.
44 | mstore(str, 0)
45 |
46 | // Cache the end of the memory to calculate the length later.
47 | let end := str
48 |
49 | // We write the string from rightmost digit to leftmost digit.
50 | // The following is essentially a do-while loop that also handles the zero case.
51 | // prettier-ignore
52 | for { let temp := value } 1 {} {
53 | // Move the pointer 1 byte to the left.
54 | str := sub(str, 1)
55 |
56 | // Write the character to the pointer.
57 | // The ASCII index of the '0' character is 48.
58 | mstore8(str, add(48, mod(temp, 10)))
59 |
60 | // Keep dividing temp until zero.
61 | temp := div(temp, 10)
62 |
63 | // prettier-ignore
64 | if iszero(temp) { break }
65 | }
66 |
67 | // Compute and cache the final total length of the string.
68 | let length := sub(end, str)
69 |
70 | // Move the pointer 32 bytes leftwards to make room for the length.
71 | str := sub(str, 32)
72 |
73 | // Store the string's length at the start of memory allocated for our string.
74 | mstore(str, length)
75 | }
76 | }
77 | }
--------------------------------------------------------------------------------
/examples/with-library/mod.ts:
--------------------------------------------------------------------------------
1 | import { wrapper } from 'solc'
2 | import type { Input, Output } from 'solc/types'
3 | import { download } from 'solc/download'
4 | import { createRequire } from '../../helpers_test.ts'
5 | import { exists } from '../../helpers_test.ts'
6 |
7 | if (!(await exists('./soljson.cjs'))) await download()
8 |
9 | const require = createRequire(import.meta.url)
10 | const solc = wrapper(require('./soljson.cjs'))
11 |
12 | const Example = await Deno.readTextFile('./Example.sol')
13 | const LibString = await Deno.readTextFile('./LibString.sol')
14 |
15 | const input: Input = {
16 | language: 'Solidity',
17 | sources: {
18 | 'Example.sol': {
19 | content: Example,
20 | },
21 | 'LibString.sol': {
22 | content: LibString,
23 | },
24 | },
25 |
26 | settings: {
27 | outputSelection: {
28 | '*': {
29 | '*': ['*'],
30 | },
31 | },
32 | },
33 | }
34 |
35 | const result = JSON.parse(solc.compile(JSON.stringify(input))) as Output
36 |
37 | console.log(result.contracts['LibString.sol']['LibString'].evm.bytecode)
38 |
--------------------------------------------------------------------------------
/helpers_test.ts:
--------------------------------------------------------------------------------
1 | export const exists = async (filename: string): Promise => {
2 | try {
3 | await Deno.stat(filename)
4 | return true
5 | } catch (error) {
6 | if (error instanceof Deno.errors.NotFound) {
7 | return false
8 | } else {
9 | throw error
10 | }
11 | }
12 | }
13 |
14 | export { createRequire } from 'node:module'
15 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/deno-web3/solc/84e7bef2b7a1790806ecd13b2aa0a07e8fa4bfaa/logo.png
--------------------------------------------------------------------------------
/mod.ts:
--------------------------------------------------------------------------------
1 | import setupBindings from './bindings/index.ts'
2 | import type { CompileBindings, SolJson, Wrapper } from 'solc/types'
3 |
4 | function compileStandardWrapper(compile: CompileBindings, inputRaw: string, readCallback: unknown) {
5 | return compile.compileStandard(inputRaw, readCallback as number)
6 | }
7 |
8 | /**
9 | * Wrap Solidity compiler into a JS interface
10 | * @param soljson WebAssembly compiler module
11 | */
12 | export function wrapper(soljson: SolJson): Wrapper {
13 | const { coreBindings, compileBindings } = setupBindings(soljson)
14 |
15 | return {
16 | version: coreBindings.version,
17 | license: coreBindings.license,
18 | // @ts-ignore this stuff
19 | compile: compileStandardWrapper.bind(this, compileBindings),
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/mod_test.ts:
--------------------------------------------------------------------------------
1 | import { beforeAll, describe, it } from '@std/testing/bdd'
2 | import { expect } from '@std/expect'
3 | import { wrapper } from 'solc'
4 | import { createRequire } from './helpers_test.ts'
5 | import { download } from 'solc/download'
6 | import type { Input, Output, Wrapper } from 'solc/types'
7 |
8 | const require = createRequire(import.meta.url)
9 |
10 | globalThis.__dirname = import.meta.dirname!
11 |
12 | const contract = `
13 | // SPDX-License-Identifier: MIT
14 | pragma solidity >=0.8;
15 |
16 | contract HelloWorld {
17 | string public greet = "Hello World!";
18 | }
19 | `
20 |
21 | describe('Wrapper', () => {
22 | let solc: Wrapper
23 | beforeAll(async () => {
24 | await download('./soljson_test.cjs', '0.8.18')
25 | solc = wrapper(require('./soljson_test.cjs'))
26 | })
27 | it('returns JS interface', () => {
28 | expect(solc.compile).toBeDefined()
29 | expect(solc.version()).toBe('0.8.18+commit.87f61d96.Emscripten.clang')
30 | expect(solc.license()).toContain('Most of the code is licensed under GPLv3 (see below), the license for individual')
31 | })
32 | it('compiles a Solidity file', () => {
33 | const input: Input = {
34 | language: 'Solidity',
35 | sources: {
36 | 'Hello.sol': { content: contract },
37 | },
38 | settings: {
39 | outputSelection: {
40 | '*': {
41 | '*': ['*'],
42 | },
43 | },
44 | },
45 | }
46 | const output: Output = JSON.parse(solc.compile(JSON.stringify(input)))
47 |
48 | expect(output.sources!['Hello.sol'].id).toEqual(0)
49 | expect(output.contracts!['Hello.sol']['HelloWorld'].abi).toEqual([
50 | {
51 | inputs: [],
52 | name: 'greet',
53 | outputs: [{ internalType: 'string', name: '', type: 'string' }],
54 | stateMutability: 'view',
55 | type: 'function',
56 | },
57 | ])
58 | })
59 | })
60 |
--------------------------------------------------------------------------------
/types.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * A mapping between libraries and the addresses to which they were deployed.
3 | *
4 | * Containing support for two level configuration, These two level
5 | * configurations can be seen below.
6 | *
7 | * {
8 | * "lib.sol:L1": "0x...",
9 | * "lib.sol:L2": "0x...",
10 | * "lib.sol": {"L3": "0x..."}
11 | * }
12 | */
13 | export interface LibraryAddresses {
14 | [qualifiedNameOrSourceUnit: string]: string | { [unqualifiedLibraryName: string]: string }
15 | }
16 |
17 | /**
18 | * A mapping between libraries and lists of placeholder instances present in their hex-encoded bytecode.
19 | * For each placeholder its length and the position of the first character is stored.
20 | *
21 | * Each start and length entry will always directly refer to the position in
22 | * binary and not hex-encoded bytecode.
23 | */
24 | export interface LinkReferences {
25 | [libraryLabel: string]: Array<{ start: number; length: number }>
26 | }
27 |
28 | export interface SolJson {
29 | /**
30 | * Returns a native JavaScript wrapper for a C function.
31 | *
32 | * This is similar to ccall(), but returns a JavaScript function that can be
33 | * reused as many times as needed. The C function can be defined in a C file,
34 | * or be a C-compatible C++ function defined using extern "C" (to prevent
35 | * name mangling).
36 | *
37 | * @param ident The name of the C function to be called.
38 | *
39 | * @param returnType The return type of the function. This can be "number",
40 | * "string" or "array", which correspond to the appropriate JavaScript
41 | * types (use "number" for any C pointer, and "array" for JavaScript arrays
42 | * and typed arrays; note that arrays are 8-bit), or for a void function it
43 | * can be null (note: the JavaScript null value, * not a string containing
44 | * the word “null”).
45 | *
46 | * @param argTypes An array of the types of arguments for the function (if
47 | * there are no arguments, this can be omitted). Types are as in returnType,
48 | * except that array is not supported as there is no way for us to know the
49 | * length of the array).
50 | *
51 | * @returns A JavaScript function that can be used for running the C function.
52 | */
53 | cwrap(ident: string, returnType: string | null, argTypes: string[]): T
54 |
55 | /**
56 | * Sets a value at a specific memory address at run-time.
57 | *
58 | * Note:
59 | * setValue() and getValue() only do aligned writes and reads.
60 | *
61 | * The type is an LLVM IR type (one of i8, i16, i32, i64, float, double, or
62 | * a pointer type like i8* or just *), not JavaScript types as used in ccall()
63 | * or cwrap(). This is a lower-level operation, and we do need to care what
64 | * specific type is being used.
65 | *
66 | * @param ptr A pointer (number) representing the memory address.
67 | *
68 | * @param value The value to be stored
69 | *
70 | * @param type An LLVM IR type as a string (see “note” above).
71 | *
72 | * @param noSafe Developers should ignore this variable. It is only
73 | * used in SAFE_HEAP compilation mode, where it can help avoid infinite recursion
74 | * in some specialist use cases.
75 | */
76 | setValue(ptr: number, value: unknown, type: string, noSafe?: boolean): void
77 |
78 | /**
79 | * Given a pointer ptr to a null-terminated UTF8-encoded string in the
80 | * Emscripten HEAP, returns a copy of that string as a JavaScript String
81 | * object.
82 | *
83 | * @param ptr A pointer to a null-terminated UTF8-encoded string in the
84 | * Emscripten HEAP.
85 | *
86 | * @param maxBytesToRead An optional length that specifies the maximum number
87 | * of bytes to read. You can omit this parameter to scan the string until the
88 | * first 0 byte. If maxBytesToRead is passed, and the string at
89 | * [ptr, ptr+maxBytesToReadr) contains a null byte in the middle, then the
90 | * string will cut short at that byte index (i.e. maxBytesToRead will not
91 | * produce a string of exact length [ptr, ptr+maxBytesToRead)) N.B. mixing
92 | * frequent uses of UTF8ToString() with and without maxBytesToRead may throw
93 | * JS JIT optimizations off, so it is worth to consider consistently using
94 | * one style or the other.
95 | */
96 | UTF8ToString(ptr: number, maxBytesToRead?: number): string
97 |
98 | /**
99 | * v1.38.27: 02/10/2019 (emscripten)
100 | * --------------------
101 | * - Remove deprecated Pointer_stringify (use UTF8ToString instead). See #8011
102 | *
103 | * @param ptr
104 | * @param length
105 | * @constructor
106 | *
107 | * @deprecated use UTF8ToString instead
108 | */
109 | // eslint-disable-next-line camelcase
110 | Pointer_stringify(ptr: number, length?: number): string
111 |
112 | /**
113 | * Given a string input return the current length of the given UTF8 bytes.
114 | * Used when performing stringToUTF8 since stringToUTF8 will require at most
115 | * str.length*4+1 bytes of space in the HEAP.
116 | *
117 | * @param str The input string.
118 | */
119 | lengthBytesUTF8(str: string): number
120 |
121 | /**
122 | * Copies the given JavaScript String object str to the Emscripten HEAP at
123 | * address outPtr, null-terminated and encoded in UTF8 form.
124 | *
125 | * The copy will require at most str.length*4+1 bytes of space in the HEAP.
126 | * You can use the function lengthBytesUTF8() to compute the exact amount
127 | * of bytes (excluding the null terminator) needed to encode the string.
128 | *
129 | * @param str A JavaScript String object.
130 | *
131 | * @param outPtr Pointer to data copied from str, encoded in UTF8 format and
132 | * null-terminated.
133 | *
134 | * @param maxBytesToWrite A limit on the number of bytes that this function
135 | * can at most write out. If the string is longer than this, the output is
136 | * truncated. The outputted string will always be null terminated, even if
137 | * truncation occurred, as long as maxBytesToWrite > 0
138 | */
139 | stringToUTF8(str: string, outPtr: number, maxBytesToWrite?: number): void
140 |
141 | /**
142 | * Allocates size bytes of uninitialized storage.
143 | *
144 | * If allocation succeeds, returns a pointer that is suitably aligned for any
145 | * object type with fundamental alignment.
146 | *
147 | * @param size number of bytes to allocate
148 | *
149 | * @returns On success, returns the pointer to the beginning of newly
150 | * allocated memory. To avoid a memory leak, the returned pointer must be
151 | * deallocated with free() or realloc().
152 | */
153 | _malloc(size: number): number
154 |
155 | /**
156 | * Use addFunction to return an integer value that represents a function
157 | * pointer. Passing that integer to C code then lets it call that value as a
158 | * function pointer, and the JavaScript function you sent to addFunction will
159 | * be called.
160 | *
161 | * when using addFunction on LLVM wasm backend, you need to provide an
162 | * additional second argument, a Wasm function signature string. Each
163 | * character within a signature string represents a type. The first character
164 | * represents the return type of the function, and remaining characters are for
165 | * parameter types.
166 | *
167 | * 'v': void type
168 | * 'i': 32-bit integer type
169 | * 'j': 64-bit integer type (currently does not exist in JavaScript)
170 | * 'f': 32-bit float type
171 | * 'd': 64-bit float type
172 | *
173 | * @param func
174 | * @param signature
175 | */
176 | addFunction: CoreBindings['addFunction']
177 |
178 | /**
179 | * Removes an allocated function by the provided function pointer.
180 | *
181 | * @param funcPtr
182 | */
183 | removeFunction: CoreBindings['removeFunction']
184 | }
185 |
186 | /**************************
187 | * core binding functions
188 | *************************/
189 |
190 | /**
191 | * Allocates a chunk of memory of size bytes.
192 | *
193 | * Use this function inside callbacks to allocate data that is to be passed to
194 | * the compiler. You may use solidity_free() or solidity_reset() to free this
195 | * memory again, but it is not required as the compiler takes ownership for any
196 | * data passed to it via callbacks.
197 | *
198 | * This function will return NULL if the requested memory region could not be
199 | * allocated.
200 | *
201 | * @param size The size of bytes to be allocated.
202 | */
203 | export type Alloc = (size: number) => number
204 |
205 | /**
206 | * Returns the complete license document.
207 | */
208 | export type License = () => string | undefined
209 |
210 | /**
211 | * This should be called right before each compilation, but not at the end,
212 | * so additional memory can be freed.
213 | */
214 | export type Reset = () => string
215 |
216 | /**
217 | * Returns the compiler version.
218 | */
219 | export type Version = () => string
220 |
221 | // compile binding functions
222 | export type ReadCallbackResult = { contents: string } | { error: string }
223 | export type ReadCallback = (path: string) => ReadCallbackResult
224 | export type Callbacks = { [x: string]: ReadCallback }
225 |
226 | /**
227 | * Will attempt to bind into compileStandard before falling back to solidity_compile.
228 | * compileStandard - solidityMaxVersion 0.5.0
229 | *
230 | * @solidityMinVersion 0.4.11
231 | *
232 | * @param input
233 | * @param callbackPtr
234 | * @param contextPtr
235 | */
236 | export type CompileJsonStandard = (input: string, callbackPtr: number, contextPtr?: number) => string
237 |
238 | /**
239 | * Compile the provided input, using the best case implementation based on the
240 | * current binary.
241 | *
242 | * @param input
243 | * @param readCallback
244 | */
245 | export type CompileSolidity = (input: string, readCallback?: Callbacks) => string
246 |
247 | export interface CompileBindings {
248 | compileStandard: CompileJsonStandard
249 | }
250 |
251 | export interface CoreBindings {
252 | alloc: Alloc
253 | license: License
254 | reset: Reset
255 |
256 | version: Version
257 | copyFromCString: (ptr: number) => string
258 | copyToCString: (input: string, ptr: number) => string
259 |
260 | addFunction: void>(func: Func, signature?: string) => number
261 | removeFunction: (ptr: number) => void
262 | }
263 |
264 | export interface SupportedMethods {
265 | licenseSupported: boolean
266 | versionSupported: boolean
267 | allocSupported: boolean
268 | resetSupported: boolean
269 | compileJsonSupported: boolean
270 | compileJsonMultiSupported: boolean
271 | compileJsonCallbackSupported: boolean
272 | compileJsonStandardSupported: boolean
273 | }
274 |
275 | export interface Wrapper {
276 | /**
277 | * Returns the complete license document.
278 | */
279 | license(): string | undefined
280 |
281 | /**
282 | * Returns the compiler version.
283 | */
284 | version(): string
285 |
286 | /**
287 | * Compile the provided input, using the best case implementation based on the
288 | * current binary.
289 | *
290 | * @param input
291 | * @param readCallback
292 | */
293 | compile(input: string, readCallback?: Callbacks): string
294 | }
295 |
296 | export interface Input {
297 | language: 'Solidity' | 'Yul'
298 | sources: { [contractName: string]: { content: string } }
299 | settings?: {
300 | outputSelection?: { '*'?: { '*'?: string[] } }
301 | optimizer?: {
302 | enabled?: boolean
303 | runs?: number
304 | }
305 | evmVersion?: string
306 | libraries?: { [libraryName: string]: string }
307 | remappings?: string[]
308 | }
309 | }
310 |
311 | interface ContractABI {
312 | inputs: { internalType: string; name: string; type: string; indexed?: boolean }[]
313 | name: string
314 | outputs: { internalType: string; name: string; type: string }[]
315 | stateMutability: string
316 | type: string
317 | }
318 |
319 | interface DevDoc {
320 | kind: 'dev'
321 | methods: Record
322 | version: number
323 | details: string
324 | }
325 |
326 | interface UserDoc {
327 | kind: 'user'
328 | methods: Record
329 | version: number
330 | }
331 |
332 | interface AST {
333 | nativeSrc: string
334 | nodeType: string
335 | src: string
336 | statements: { body?: AST; name: string; nativeSrc: string; nodeType: string }[]
337 | }
338 |
339 | interface GeneratedSource {
340 | ast: AST
341 | contents: string
342 | id: number
343 | language: 'Yul'
344 | name: `${string}.yul`
345 | }
346 |
347 | interface Bytecode {
348 | linkReferences: LinkReferences
349 | object: string
350 | generatedSources: GeneratedSource[]
351 | }
352 |
353 | interface GasEstimates {
354 | creation: {
355 | codeDepositCost: string
356 | executionCost: string
357 | totalCost: string
358 | }
359 | external: {
360 | [functionName: string]: string
361 | }
362 | }
363 |
364 | interface LegacyAssemblyItem {
365 | begin: number
366 | end: number
367 | name: string
368 | source: number
369 | value: string
370 | }
371 |
372 | interface LegacyAssembly {
373 | '.code': LegacyAssemblyItem[]
374 | '.data': {
375 | '0': {
376 | '.auxdata': string
377 | '.code': LegacyAssemblyItem[]
378 | }
379 | }
380 | sourceList: string[]
381 | }
382 |
383 | interface EVM {
384 | assembly: string
385 | bytecode: Bytecode
386 | deployedBytecode: Bytecode
387 | gasEstimates: GasEstimates
388 | legacyAssembly: LegacyAssembly
389 | methodIdentifiers: Record
390 | }
391 |
392 | interface Ewasm {
393 | wasm: string
394 | }
395 |
396 | interface StorageItem {
397 | astId: number
398 | contract: string
399 | label: string
400 | offset: number
401 | slot: string
402 | type: string
403 | }
404 |
405 | interface StorageType {
406 | encoding: string
407 | label: string
408 | numberOfBytes: string
409 | }
410 |
411 | interface StorageLayout {
412 | storage: StorageItem[]
413 | types: Record
414 | }
415 |
416 | interface Contract {
417 | abi: ContractABI[]
418 | devdoc: DevDoc
419 | evm: EVM
420 | ewasm: Ewasm
421 | metadata: string
422 | storageLayout: StorageLayout
423 | transientStorageLayout?: StorageLayout
424 | userdoc: UserDoc
425 | }
426 |
427 | interface Contracts {
428 | [contractName: string]: {
429 | [contractInstance: string]: Contract
430 | }
431 | }
432 |
433 | interface Sources {
434 | [sourceName: string]: {
435 | id: number
436 | }
437 | }
438 |
439 | export interface Output {
440 | sources: Sources
441 | contracts: Contracts
442 | errors: unknown[]
443 | }
444 |
--------------------------------------------------------------------------------