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

Purs 0.15 #10

Merged
merged 13 commits into from
Sep 8, 2023
25 changes: 25 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Run test suite

on:
push:
branches:
- '*'
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: setup node
uses: actions/setup-node@v3
with:
node-version-file: .nvmrc
- name: run tests
run: |
npm install
npm run build
npm run test
25 changes: 25 additions & 0 deletions .github/workflows/tidy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Code style and lint

on:
pull_request:
branches:
- master

workflow_dispatch:

jobs:
tidy:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: setup node
uses: actions/setup-node@v3
with:
node-version-file: .nvmrc
- name: run tidy
run: |
npm install
npm run tidy-check
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v20.6
8 changes: 8 additions & 0 deletions .tidyrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"indent": 2,
"operatorsFile": null,
"ribbon": 1,
"typeArrowPlacement": "first",
"unicode": "never",
"width": null
}
13 changes: 0 additions & 13 deletions .travis.yml

This file was deleted.

12 changes: 8 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
{
"private": true,
"scripts": {
"build": "spago build"
"build": "spago build",
"test": "spago -x test.dhall test",
"tidy": "purs-tidy format-in-place \"src/**/*.purs\" \"test/**/*.purs\"",
"tidy-check": "purs-tidy check \"src/**/*.purs\" \"test/**/*.purs\""
},
"dependencies": {
"bn.js": "^4.11.0",
Expand All @@ -11,11 +14,12 @@
"pulp": "^15.0.0",
"rlp": "^2.0.0",
"secp256k1": "^3.0.1",
"solc": "^0.5"
"solc": "^0.8"
},
"devDependencies": {
"purescript": "^0.15.8",
"purescript-psa": "^0.8.2",
"purescript": "^0.14.2",
"spago": "^0.20.3"
"spago": "^0.20.9",
"purs-tidy": "^0.10.0"
}
}
78 changes: 3 additions & 75 deletions packages.dhall
Original file line number Diff line number Diff line change
@@ -1,81 +1,9 @@
let upstream =
https://github.com/purescript/package-sets/releases/download/psc-0.14.2-20210629/packages.dhall sha256:534c490bb73cae75adb5a39871142fd8db5c2d74c90509797a80b8bb0d5c3f7b
https://raw.githubusercontent.com/f-o-a-m/package-sets/purs-0.15/purs-0.15.7-web3.dhall
sha256:2d868539460c47c2bf5ecf4c6b68c3ea3162849f2da9cd3f263b740299448d8f

let overrides = {=}

let additions =
{ web3 =
{ dependencies =
[ "aff"
, "avar"
, "console"
, "coroutines"
, "coroutine-transducers"
, "debug"
, "effect"
, "errors"
, "eth-core"
, "foreign"
, "foreign-generic"
, "fork"
, "free"
, "heterogeneous"
, "identity"
, "parsing"
, "partial"
, "profunctor-lenses"
, "psci-support"
, "tagged"
, "transformers"
, "typelevel-prelude"
, "variant"
]
, repo = "https://github.com/f-o-a-m/purescript-web3"
, version = "v4.0.0"
}
, eth-core =
{ dependencies =
[ "argonaut"
, "bytestrings"
, "console"
, "debug"
, "effect"
, "foreign-generic"
, "ordered-collections"
, "parsing"
, "prelude"
, "psci-support"
, "ring-modules"
, "simple-json"
]
, repo =
"https://github.com/f-o-a-m/purescript-eth-core.git"
, version =
"v7.0.0"
}
, coroutine-transducers =
{ dependencies =
[ "aff"
, "coroutines"
, "effect"
, "maybe"
, "psci-support"
]
, repo =
"https://github.com/blinky3713/purescript-coroutine-transducers"
, version =
"v1.0.0"
}
, tagged =
{ dependencies =
[ "identity"
, "profunctor"
]
, repo =
"https://github.com/kejace/purescript-tagged"
, version =
"v0.14"
}
}
let additions = {=}

in upstream // overrides // additions
1 change: 0 additions & 1 deletion spago.dhall
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ You can edit this file as you like.
, "newtype"
, "node-path"
, "prelude"
, "psci-support"
, "strings"
, "transformers"
, "tuples"
Expand Down
81 changes: 63 additions & 18 deletions src/Language/Solidity/Compiler.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"use strict";

const solcMod = require('solc');
import solcMod from "solc";

function stringify(input) {
if (typeof input !== 'string') {
Expand All @@ -16,34 +16,79 @@ function objectify(input) {
return JSON.parse(input);
}

exports.defaultCompiler = solcMod;
export const defaultCompiler = solcMod;

exports.version = function(solc) {
export const version = function(solc) {
return solc.version();
}

exports.useCompiler = function(source) {
const requireFromString = function(str) {
const filename = "__solc_useCompiler";
const Module = module.constructor;
var m = new Module(filename, module);
m.filename = filename
m.paths = module.paths;
m._compile(source, "__solc_useCompiler");
return m.exports;
// Because PureScript 0.15+ forces all its modules to be ES modules, we can't just
// use require() like in a CJS module. Nor do we have the CommonJS `Module` API, where we can
// synthesize CJS modules at runtime. This is how useCompiler previously worked.
// import()ing from a data URI will make Node's loader assume we're trying to load an ES module, and there's
// no way to actually tell it to treat it as a CJS module -- `await import(..., { assert: { type: 'commonjs' }})`
// is actually an unsupported assertion (only `import assert { type: 'json' }` is supported by node).
//
// All of this is really unfortunate since solc is shipped as CommonJS. To get around this, we create a loader hook
// that forces Node to treat certain URLs as CommonJS.
//
// This unfortunately requires Node v20.6+
//
// Because we are a PureScript package and can't assume anything about where any relative
// "pure" JS files will be, but we do know our own module's URL, we keep this function here
// and in _useCompiler, we register this file (output/Language.Solidity.Compiler/foreign.js) as a Node loader.
const __DATA_JS_BASE64 = "data:text/javascript;base64,";
const __SOLC_CJS_MARKER = "/solc_cjs";
export function load(spec, context, next) {
if (typeof spec === 'string' && spec.startsWith(__DATA_JS_BASE64) && spec.endsWith(__SOLC_CJS_MARKER)) {
const cleanedSpec = spec.substring(__DATA_JS_BASE64.length, spec.length - __SOLC_CJS_MARKER.length);
return {
format: 'commonjs',
shortCircuit: true,
source: atob(cleanedSpec),
};
} else {
return next(spec, context);
}
return solcMod.setupMethods(requireFromString(source));
}

exports.callbackSuccess = function (contents) {
export const _useCompiler = function(source) {
return function (onError, onSuccess) {
const mkMod = async () => {
try {
// todo: this is obv. unusable in a browser. `purescript-solc` only really exists to
// to support Chanterelle, so this is fine for now...
const NodeModule = await import("node:module");
NodeModule.register(import.meta.url);
const url = __DATA_JS_BASE64 + btoa(source) + __SOLC_CJS_MARKER;
const mod = await import(url);
return mod.default;
} catch(e) {
console.error(e);
throw e;
}
};

const cancel = mkMod().then(m => onSuccess(solcMod.setupMethods(m)), e => {
onError(e);
});

return function(cancelError, onCancelerError, onCancelerSuccess) {
cancel();
onCancelerSuccess();
};
};
}

export const callbackSuccess = function (contents) {
return { "contents": contents }
};

exports.callbackFailure = function (error) {
export const callbackFailure = function (error) {
return { "error": error }
};

exports._loadRemoteVersion = function(version) {
export const _loadRemoteVersion = function(version) {
return function (onError, onSuccess) {
var cancel = solcMod.loadRemoteVersion(version, function(err, solcSnapshot) {
if (err) {
Expand All @@ -59,7 +104,7 @@ exports._loadRemoteVersion = function(version) {
}
};

exports._compile = function (solc, input, readCallback) {
export const _compile = function (solc, input, readCallback) {
return function() {
// support different versions of solc-js
// to understand what's going on here, keep this in mind:
Expand Down Expand Up @@ -156,4 +201,4 @@ exports._compile = function (solc, input, readCallback) {
return readCallback(requestedFile)();
}));
}
};
};
12 changes: 10 additions & 2 deletions src/Language/Solidity/Compiler.purs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ foreign import callbackSuccess :: String -> SolcReadFileCallbackResult
foreign import callbackFailure :: String -> SolcReadFileCallbackResult
foreign import defaultCompiler :: SolidityCompiler
foreign import version :: SolidityCompiler -> String
foreign import useCompiler :: String -> SolidityCompiler
foreign import _useCompiler :: String -> EffectFnAff SolidityCompiler
foreign import _loadRemoteVersion :: String -> EffectFnAff SolidityCompiler
foreign import _compile :: Fn3 SolidityCompiler Json (FilePath -> Effect SolcReadFileCallbackResult) (Effect Json)

Expand All @@ -42,11 +42,19 @@ compile
compile solc input readFile = liftEffect $ map (lmap printJsonDecodeError) $
A.decodeJson <$> runFn3 _compile solc (encodeJson input) liftedCallback

where liftedCallback = map (either callbackFailure callbackSuccess) <<< readFile
where
liftedCallback = map (either callbackFailure callbackSuccess) <<< readFile

loadRemoteVersion
:: forall m
. MonadAff m
=> String
-> m SolidityCompiler
loadRemoteVersion = liftAff <<< fromEffectFnAff <<< _loadRemoteVersion

useCompiler
:: forall m
. MonadAff m
=> String
-> m SolidityCompiler
useCompiler = liftAff <<< fromEffectFnAff <<< _useCompiler
10 changes: 5 additions & 5 deletions src/Language/Solidity/Compiler/Releases.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
"use strict";

const http = require('http');
const https = require('https');
const MemoryStream = require('memorystream');
import http from "http";
import https from "https";
import MemoryStream from "memorystream";

exports._getURL = function(url) {
export const _getURL = function(url) {
const httpImpl = url.startsWith("https:") ? https : http;
return function(onError, onSuccess) {
var cancel = httpImpl.get(url, function (res) {
var error;
if (res.statusCode != 200) {
error = new Error("Request failed, status code " + statusCode);
error = new Error("Request failed to " + url + " status code " + res.statusCode);
}

if (error) {
Expand Down