skittles 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,14 @@
1
+ Make it a cli app
2
+ Create and deploy package
3
+ save artifacts/build
4
+ Remove tabs in yul, surely this can be automated or somethign
5
+ Use the `FoxOperator` strings for the assemby stuff
6
+ Try changing balance to 1 in the contract and run tests
7
+ add prepublish
8
+
9
+ Add more support
10
+ remove Token.yul
11
+
12
+ add readme
13
+
14
+ Add other normal repo things
@@ -0,0 +1,29 @@
1
+ import * as dotenv from "dotenv";
2
+
3
+ import { HardhatUserConfig } from "hardhat/config";
4
+ import "@nomiclabs/hardhat-etherscan";
5
+ import "@nomiclabs/hardhat-waffle";
6
+ import "@typechain/hardhat";
7
+ import "hardhat-gas-reporter";
8
+
9
+ dotenv.config();
10
+
11
+ const config: HardhatUserConfig = {
12
+ solidity: "0.8.4",
13
+ networks: {
14
+ ropsten: {
15
+ url: process.env.ROPSTEN_URL || "",
16
+ accounts:
17
+ process.env.PRIVATE_KEY !== undefined ? [process.env.PRIVATE_KEY] : [],
18
+ },
19
+ },
20
+ gasReporter: {
21
+ enabled: process.env.REPORT_GAS !== undefined,
22
+ currency: "USD",
23
+ },
24
+ etherscan: {
25
+ apiKey: process.env.ETHERSCAN_API_KEY,
26
+ },
27
+ };
28
+
29
+ export default config;
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.compileTypeScriptToBytecode = void 0;
16
+ const get_bytecode_1 = __importDefault(require("./get-bytecode"));
17
+ const get_fox_class_1 = __importDefault(require("./get-fox-class"));
18
+ const get_yul_1 = __importDefault(require("./get-yul"));
19
+ const compileTypeScriptToBytecode = (fileName) => __awaiter(void 0, void 0, void 0, function* () {
20
+ const foxClass = (0, get_fox_class_1.default)(fileName);
21
+ const yul = (0, get_yul_1.default)(fileName);
22
+ return (0, get_bytecode_1.default)(foxClass.name, yul);
23
+ });
24
+ exports.compileTypeScriptToBytecode = compileTypeScriptToBytecode;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.YulSection = void 0;
4
+ var YulSection;
5
+ (function (YulSection) {
6
+ YulSection["Dispatchers"] = "dispatchers";
7
+ YulSection["Functions"] = "functions";
8
+ YulSection["StorageLayout"] = "storage layout";
9
+ YulSection["StorageAccess"] = "storage access";
10
+ })(YulSection = exports.YulSection || (exports.YulSection = {}));
11
+ const yulTemplate = [
12
+ ` code {`,
13
+ ` // Deploy the contract`,
14
+ ` datacopy(0, dataoffset("runtime"), datasize("runtime"))`,
15
+ ` return(0, datasize("runtime"))`,
16
+ ` }`,
17
+ ` object "runtime" {`,
18
+ ` code {`,
19
+ ` switch selector()`,
20
+ ` /* ---------- dispatchers ----------- */`,
21
+ ` default {`,
22
+ ` revert(0, 0)`,
23
+ ` }`,
24
+ ``,
25
+ ``,
26
+ ` /* ---------- functions ----------- */`,
27
+ ``,
28
+ ``,
29
+ ` /* ---------- calldata decoding functions ----------- */`,
30
+ ` function selector() -> s {`,
31
+ ` s := div(calldataload(0), 0x100000000000000000000000000000000000000000000000000000000)`,
32
+ ` }`,
33
+ ` function decodeAsAddress(offset) -> v {`,
34
+ ` v := decodeAsUint(offset)`,
35
+ ` if iszero(iszero(and(v, not(0xffffffffffffffffffffffffffffffffffffffff)))) {`,
36
+ ` revert(0, 0)`,
37
+ ` }`,
38
+ ` }`,
39
+ ` function decodeAsUint(offset) -> v {`,
40
+ ` let pos := add(4, mul(offset, 0x20))`,
41
+ ` if lt(calldatasize(), add(pos, 0x20)) {`,
42
+ ` revert(0, 0)`,
43
+ ` }`,
44
+ ` v := calldataload(pos)`,
45
+ ` }`,
46
+ ``,
47
+ ``,
48
+ ` /* ---------- calldata encoding functions ---------- */`,
49
+ ` function returnUint(v) {`,
50
+ ` mstore(0, v)`,
51
+ ` return(0, 0x20)`,
52
+ ` }`,
53
+ ` function returnTrue() {`,
54
+ ` returnUint(1)`,
55
+ ` }`,
56
+ ``,
57
+ ``,
58
+ ` /* -------- storage layout ---------- */`,
59
+ ``,
60
+ ``,
61
+ ` /* -------- storage access ---------- */`,
62
+ ``,
63
+ ``,
64
+ ` /* ---------- utility functions start ---------- */`,
65
+ ` function lte(a, b) -> r {`,
66
+ ` r := iszero(gt(a, b))`,
67
+ ` }`,
68
+ ` function gte(a, b) -> r {`,
69
+ ` r := iszero(lt(a, b))`,
70
+ ` }`,
71
+ ` function safeAdd(a, b) -> r {`,
72
+ ` r := add(a, b)`,
73
+ ` if or(lt(r, a), lt(r, b)) { revert(0, 0) }`,
74
+ ` }`,
75
+ ` function revertIfZeroAddress(addr) {`,
76
+ ` require(addr)`,
77
+ ` }`,
78
+ ` function require(condition) {`,
79
+ ` if iszero(condition) { revert(0, 0) }`,
80
+ ` }`,
81
+ ` }`,
82
+ ` }`,
83
+ `}`,
84
+ ];
85
+ exports.default = yulTemplate;
package/lib/get-abi.js ADDED
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const getPropertyAbi = (property) => {
4
+ return {
5
+ type: "function",
6
+ name: property.name,
7
+ inputs: [],
8
+ outputs: [{ name: "", type: property.type }],
9
+ stateMutability: "view",
10
+ };
11
+ };
12
+ const getMethodAbi = (method) => {
13
+ return {
14
+ type: "function",
15
+ name: method.name,
16
+ inputs: method.parameters.map((i) => ({
17
+ name: i.name,
18
+ type: i.type,
19
+ })),
20
+ outputs: [{ name: "", type: method.returns }],
21
+ stateMutability: method.view ? "view" : "payable",
22
+ };
23
+ };
24
+ const getAbi = (foxClass) => {
25
+ return [
26
+ ...foxClass.properties.filter((p) => !p.private).map(getPropertyAbi),
27
+ ...foxClass.methods.filter((p) => !p.private).map(getMethodAbi),
28
+ ];
29
+ };
30
+ exports.default = getAbi;
package/lib/get-ast.js ADDED
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const typescript_1 = require("typescript");
4
+ const getAst = (file) => {
5
+ let program = (0, typescript_1.createProgram)([file], {
6
+ allowJs: true,
7
+ target: typescript_1.ScriptTarget.ES5,
8
+ module: typescript_1.ModuleKind.CommonJS,
9
+ });
10
+ const ast = program.getSourceFile(file);
11
+ if (!ast)
12
+ throw new Error("Could not get AST");
13
+ return ast;
14
+ };
15
+ exports.default = getAst;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const solc = require("solc");
4
+ const getBytecode = (className, content) => {
5
+ const input = {
6
+ language: "Yul",
7
+ sources: {
8
+ main: {
9
+ content,
10
+ },
11
+ },
12
+ settings: {
13
+ outputSelection: {
14
+ "*": {
15
+ "*": ["*"],
16
+ },
17
+ },
18
+ },
19
+ };
20
+ const compiled = JSON.parse(solc.compile(JSON.stringify(input)));
21
+ return compiled.contracts["main"][className].evm.bytecode.object;
22
+ };
23
+ exports.default = getBytecode;
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getFoxParameters = void 0;
7
+ const typescript_1 = require("typescript");
8
+ const get_ast_1 = __importDefault(require("./get-ast"));
9
+ const ast_helper_1 = require("./helpers/ast-helper");
10
+ const fox_class_1 = require("./types/fox-class");
11
+ const getFoxType = (syntaxKind) => {
12
+ if (!syntaxKind)
13
+ return "void";
14
+ switch (syntaxKind) {
15
+ case typescript_1.SyntaxKind.StringKeyword:
16
+ return "string";
17
+ case typescript_1.SyntaxKind.NumberKeyword:
18
+ return "uint256";
19
+ case typescript_1.SyntaxKind.BooleanKeyword:
20
+ return "boolean";
21
+ case typescript_1.SyntaxKind.VoidKeyword:
22
+ return "void";
23
+ case typescript_1.SyntaxKind.AnyKeyword:
24
+ return "any";
25
+ default:
26
+ throw new Error(`Unknown syntax kind: ${syntaxKind}`);
27
+ }
28
+ };
29
+ const getFoxOperator = (syntaxKind) => {
30
+ switch (syntaxKind) {
31
+ case typescript_1.SyntaxKind.PlusToken:
32
+ return fox_class_1.FoxOperator.Plus;
33
+ case typescript_1.SyntaxKind.MinusToken:
34
+ return fox_class_1.FoxOperator.Minus;
35
+ case typescript_1.SyntaxKind.AsteriskToken:
36
+ return fox_class_1.FoxOperator.Multiply;
37
+ case typescript_1.SyntaxKind.SlashToken:
38
+ return fox_class_1.FoxOperator.Divide;
39
+ case typescript_1.SyntaxKind.PercentToken:
40
+ return fox_class_1.FoxOperator.Modulo;
41
+ case typescript_1.SyntaxKind.AmpersandAmpersandToken:
42
+ return fox_class_1.FoxOperator.And;
43
+ case typescript_1.SyntaxKind.BarBarToken:
44
+ return fox_class_1.FoxOperator.Or;
45
+ case typescript_1.SyntaxKind.EqualsEqualsToken:
46
+ return fox_class_1.FoxOperator.Equals;
47
+ case typescript_1.SyntaxKind.ExclamationEqualsToken:
48
+ return fox_class_1.FoxOperator.NotEquals;
49
+ case typescript_1.SyntaxKind.LessThanToken:
50
+ return fox_class_1.FoxOperator.LessThan;
51
+ case typescript_1.SyntaxKind.LessThanEqualsToken:
52
+ return fox_class_1.FoxOperator.LessThanOrEqual;
53
+ case typescript_1.SyntaxKind.GreaterThanToken:
54
+ return fox_class_1.FoxOperator.GreaterThan;
55
+ case typescript_1.SyntaxKind.GreaterThanEqualsToken:
56
+ return fox_class_1.FoxOperator.GreaterThanOrEqual;
57
+ default:
58
+ throw new Error(`Unknown syntax kind: ${syntaxKind}`);
59
+ }
60
+ };
61
+ const getFoxExpression = (expression) => {
62
+ if ((0, typescript_1.isLiteralExpression)(expression)) {
63
+ return {
64
+ expressionType: fox_class_1.FoxExpressionType.Value,
65
+ value: expression.text,
66
+ };
67
+ }
68
+ if ((0, typescript_1.isIdentifier)(expression)) {
69
+ return {
70
+ expressionType: fox_class_1.FoxExpressionType.Value,
71
+ value: expression.escapedText,
72
+ };
73
+ }
74
+ if ((0, typescript_1.isPropertyAccessExpression)(expression)) {
75
+ return {
76
+ expressionType: fox_class_1.FoxExpressionType.Storage,
77
+ variable: (0, ast_helper_1.getNodeName)(expression),
78
+ };
79
+ }
80
+ if ((0, typescript_1.isBinaryExpression)(expression)) {
81
+ return {
82
+ expressionType: fox_class_1.FoxExpressionType.Binary,
83
+ left: getFoxExpression(expression.left),
84
+ right: getFoxExpression(expression.right),
85
+ operator: getFoxOperator(expression.operatorToken.kind),
86
+ };
87
+ }
88
+ throw new Error(`Unknown expression type: ${expression.kind}`);
89
+ };
90
+ const isNodePrivate = (node) => {
91
+ let isPrivate = false;
92
+ (0, typescript_1.forEachChild)(node, (node) => {
93
+ if (node.kind === typescript_1.SyntaxKind.PrivateKeyword) {
94
+ isPrivate = true;
95
+ }
96
+ });
97
+ return isPrivate;
98
+ };
99
+ const getFoxProperty = (astProperty) => {
100
+ if (!astProperty.type)
101
+ throw new Error("Could not get property type");
102
+ const initializer = astProperty.initializer;
103
+ return {
104
+ name: (0, ast_helper_1.getNodeName)(astProperty),
105
+ type: getFoxType(astProperty.type.kind),
106
+ value: initializer ? getFoxExpression(initializer) : undefined,
107
+ private: isNodePrivate(astProperty),
108
+ };
109
+ };
110
+ const isNodeView = (node) => {
111
+ let isView = true;
112
+ (0, typescript_1.forEachChild)(node, (child) => {
113
+ if ((0, typescript_1.isBinaryExpression)(child)) {
114
+ if ((0, typescript_1.isPropertyAccessExpression)(child.left)) {
115
+ if ((0, ast_helper_1.isPlusEquals)(child) || (0, ast_helper_1.isEquals)(child) || (0, ast_helper_1.isMinusEquals)(child)) {
116
+ isView = false;
117
+ }
118
+ }
119
+ }
120
+ if (!isNodeView(child)) {
121
+ isView = false;
122
+ }
123
+ });
124
+ return isView;
125
+ };
126
+ const getFoxParameters = (node) => {
127
+ const inputs = [];
128
+ (0, typescript_1.forEachChild)(node, (node) => {
129
+ var _a;
130
+ if ((0, typescript_1.isParameter)(node)) {
131
+ inputs.push({
132
+ name: (0, ast_helper_1.getNodeName)(node),
133
+ type: getFoxType((_a = node.type) === null || _a === void 0 ? void 0 : _a.kind),
134
+ });
135
+ }
136
+ });
137
+ return inputs;
138
+ };
139
+ exports.getFoxParameters = getFoxParameters;
140
+ const getFoxStatement = (node, returnType) => {
141
+ if ((0, typescript_1.isExpressionStatement)(node)) {
142
+ const expression = node.expression;
143
+ if ((0, typescript_1.isBinaryExpression)(expression)) {
144
+ if ((0, typescript_1.isPropertyAccessExpression)(expression.left)) {
145
+ if ((0, ast_helper_1.isEquals)(expression)) {
146
+ return {
147
+ statementType: fox_class_1.FoxStatementType.StorageUpdate,
148
+ variable: (0, ast_helper_1.getNodeName)(expression.left),
149
+ value: getFoxExpression(expression.right),
150
+ };
151
+ }
152
+ if ((0, ast_helper_1.isPlusEquals)(expression)) {
153
+ return {
154
+ statementType: fox_class_1.FoxStatementType.StorageUpdate,
155
+ variable: (0, ast_helper_1.getNodeName)(expression.left),
156
+ value: {
157
+ expressionType: fox_class_1.FoxExpressionType.Binary,
158
+ operator: fox_class_1.FoxOperator.Plus,
159
+ left: getFoxExpression(expression.left),
160
+ right: getFoxExpression(expression.right),
161
+ },
162
+ };
163
+ }
164
+ if ((0, ast_helper_1.isMinusEquals)(expression)) {
165
+ return {
166
+ statementType: fox_class_1.FoxStatementType.StorageUpdate,
167
+ variable: (0, ast_helper_1.getNodeName)(expression.left),
168
+ value: {
169
+ expressionType: fox_class_1.FoxExpressionType.Binary,
170
+ operator: fox_class_1.FoxOperator.Minus,
171
+ left: getFoxExpression(expression.left),
172
+ right: getFoxExpression(expression.right),
173
+ },
174
+ };
175
+ }
176
+ throw new Error(`Unknown binary expression: ${expression.operatorToken.kind}`);
177
+ }
178
+ throw new Error(`Unknown binary expression type: ${expression.kind}`);
179
+ }
180
+ throw new Error("Not implemented expression statement handling");
181
+ }
182
+ if ((0, typescript_1.isReturnStatement)(node)) {
183
+ const expression = node.expression;
184
+ if (!expression)
185
+ throw new Error("Return statement has no expression");
186
+ if ((0, typescript_1.isBinaryExpression)(expression)) {
187
+ return {
188
+ statementType: fox_class_1.FoxStatementType.Return,
189
+ type: returnType,
190
+ value: getFoxExpression(node.expression),
191
+ };
192
+ }
193
+ }
194
+ throw new Error(`Unknown statement type: ${node.kind}`);
195
+ };
196
+ const getFoxMethod = (astMethod) => {
197
+ var _a, _b;
198
+ return {
199
+ name: (0, ast_helper_1.getNodeName)(astMethod),
200
+ returns: getFoxType((_a = astMethod.type) === null || _a === void 0 ? void 0 : _a.kind),
201
+ private: isNodePrivate(astMethod),
202
+ view: isNodeView(astMethod),
203
+ parameters: (0, exports.getFoxParameters)(astMethod),
204
+ statements: ((_b = astMethod.body) === null || _b === void 0 ? void 0 : _b.statements.map((statement) => { var _a; return getFoxStatement(statement, getFoxType((_a = astMethod.type) === null || _a === void 0 ? void 0 : _a.kind)); })) || [],
205
+ };
206
+ };
207
+ const getFoxClass = (file) => {
208
+ const ast = (0, get_ast_1.default)(file);
209
+ const classNode = (0, ast_helper_1.getClassNode)(ast);
210
+ const astProperties = classNode.members.filter(typescript_1.isPropertyDeclaration);
211
+ const astMethods = classNode.members.filter(typescript_1.isMethodDeclaration);
212
+ return {
213
+ name: (0, ast_helper_1.getNodeName)(classNode),
214
+ properties: astProperties.map(getFoxProperty),
215
+ methods: astMethods.map(getFoxMethod),
216
+ };
217
+ };
218
+ exports.default = getFoxClass;
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const ethers_1 = require("ethers");
4
+ const exampleValues = {
5
+ uint256: 1,
6
+ bool: true,
7
+ string: "hello",
8
+ address: "0x1234567890123456789012345678901234567890",
9
+ };
10
+ const getSelector = (abi, func) => {
11
+ const iface = new ethers_1.utils.Interface(abi);
12
+ const abiFunction = abi.find((f) => f.name === func);
13
+ if (!abiFunction)
14
+ throw new Error(`Could not find function ${func}`);
15
+ const params = abiFunction.inputs.map((input) => exampleValues[input.type]);
16
+ const data = iface.encodeFunctionData(func, params);
17
+ return data.substring(0, 10);
18
+ };
19
+ exports.default = getSelector;
package/lib/get-yul.js ADDED
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ const yul_template_1 = __importStar(require("./data/yul-template"));
30
+ const get_abi_1 = __importDefault(require("./get-abi"));
31
+ const get_selector_1 = __importDefault(require("./get-selector"));
32
+ const get_fox_class_1 = __importDefault(require("./get-fox-class"));
33
+ const fox_class_1 = require("./types/fox-class");
34
+ const addToSection = (yul, section, lines) => {
35
+ const sectionIndex = yul.findIndex((line) => line.includes(`- ${section} -`));
36
+ if (sectionIndex === -1) {
37
+ yul.push(`${section}:`);
38
+ yul.push(...lines);
39
+ }
40
+ else {
41
+ yul.splice(sectionIndex + 1, 0, ...lines);
42
+ }
43
+ return yul;
44
+ };
45
+ const decoderFunctions = {
46
+ address: "decodeAsAddress",
47
+ uint256: "decodeAsUint",
48
+ };
49
+ const returnFunctions = {
50
+ uint256: "returnUint",
51
+ boolean: "returnTrue",
52
+ };
53
+ const getBaseYul = (name) => {
54
+ const base = yul_template_1.default;
55
+ base.unshift(`object "${name}" {`);
56
+ return base;
57
+ };
58
+ const addPropertyDispatcher = (yul, abi, property) => {
59
+ const { name, type } = property;
60
+ const selector = (0, get_selector_1.default)(abi, name);
61
+ return addToSection(yul, yul_template_1.YulSection.Dispatchers, [
62
+ ` case ${selector} /* "${name}()" */ {`,
63
+ ` ${returnFunctions[type]}(${name}Storage())`,
64
+ ` }`,
65
+ ]);
66
+ };
67
+ const addMethodDispatcher = (yul, abi, method) => {
68
+ const { name, parameters, returns } = method;
69
+ const selector = (0, get_selector_1.default)(abi, name);
70
+ return addToSection(yul, yul_template_1.YulSection.Dispatchers, [
71
+ ` case ${selector} /* "${name}(${parameters
72
+ .map((p) => p.type)
73
+ .join(",")})" */ {`,
74
+ returns === "void"
75
+ ? ` ${name}Function(${parameters
76
+ .map((input, index) => `${decoderFunctions[input.type]}(${index})`)
77
+ .join(", ")})`
78
+ : ` ${returnFunctions[returns]}(${name}Function())`,
79
+ ` }`,
80
+ ]);
81
+ };
82
+ const getBinaryYul = (expression) => {
83
+ const { left, right, operator } = expression;
84
+ switch (operator) {
85
+ case fox_class_1.FoxOperator.Plus:
86
+ return `safeAdd(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
87
+ case fox_class_1.FoxOperator.Minus:
88
+ return `sub(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
89
+ case fox_class_1.FoxOperator.Multiply:
90
+ return `mul(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
91
+ case fox_class_1.FoxOperator.Divide:
92
+ return `div(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
93
+ case fox_class_1.FoxOperator.Modulo:
94
+ return `mod(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
95
+ case fox_class_1.FoxOperator.Equals:
96
+ return `eq(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
97
+ case fox_class_1.FoxOperator.NotEquals:
98
+ return `not(eq(${getExpressionYul(left)}, ${getExpressionYul(right)}))`;
99
+ case fox_class_1.FoxOperator.GreaterThan:
100
+ return `gt(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
101
+ case fox_class_1.FoxOperator.LessThan:
102
+ return `lt(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
103
+ case fox_class_1.FoxOperator.GreaterThanOrEqual:
104
+ return `gte(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
105
+ case fox_class_1.FoxOperator.LessThanOrEqual:
106
+ return `lte(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
107
+ case fox_class_1.FoxOperator.And:
108
+ return `and(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
109
+ case fox_class_1.FoxOperator.Or:
110
+ return `or(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
111
+ case fox_class_1.FoxOperator.Not:
112
+ return `not(${getExpressionYul(left)})`;
113
+ default:
114
+ throw new Error(`Unsupported binary operator ${operator}`);
115
+ }
116
+ };
117
+ const getExpressionYul = (expression) => {
118
+ switch (expression.expressionType) {
119
+ case fox_class_1.FoxExpressionType.Binary:
120
+ return getBinaryYul(expression);
121
+ case fox_class_1.FoxExpressionType.Value:
122
+ return expression.value;
123
+ case fox_class_1.FoxExpressionType.Storage:
124
+ return `${expression.variable}Storage()`;
125
+ default:
126
+ throw new Error("Unsupported expression");
127
+ }
128
+ };
129
+ const getStorageUpdateYul = (statement) => {
130
+ const { variable, value } = statement;
131
+ return ` ${variable}Set(${getExpressionYul(value)})`;
132
+ };
133
+ const getReturnYul = (statement) => {
134
+ const { value } = statement;
135
+ return ` v := ${getExpressionYul(value)}`;
136
+ };
137
+ const getStatementYul = (statement) => {
138
+ switch (statement.statementType) {
139
+ case fox_class_1.FoxStatementType.StorageUpdate:
140
+ return getStorageUpdateYul(statement);
141
+ case fox_class_1.FoxStatementType.Return:
142
+ return getReturnYul(statement);
143
+ default:
144
+ throw new Error("Unsupported statement");
145
+ }
146
+ };
147
+ const getBlockYul = (statements) => {
148
+ return statements.map((statement) => getStatementYul(statement));
149
+ };
150
+ const addMethodFunction = (yul, method) => {
151
+ const { name, parameters, returns, statements } = method;
152
+ const hasReturn = returns !== "void";
153
+ return addToSection(yul, yul_template_1.YulSection.Functions, [
154
+ ` function ${name}Function(${parameters
155
+ .map((input) => input.name)
156
+ .join(", ")}) ${hasReturn ? `-> v ` : ""}{`,
157
+ ...getBlockYul(statements),
158
+ ` }`,
159
+ ]);
160
+ };
161
+ const addStorageLayout = (yul, property, index) => {
162
+ const { name } = property;
163
+ return addToSection(yul, yul_template_1.YulSection.StorageLayout, [
164
+ ` function ${name}Pos() -> p { p := ${index} }`,
165
+ ]);
166
+ };
167
+ const addStorageAccess = (yul, property) => {
168
+ const { name } = property;
169
+ const initial = name.substring(0, 1);
170
+ return addToSection(yul, yul_template_1.YulSection.StorageAccess, [
171
+ ` function ${name}Storage() -> ${initial} {`,
172
+ ` ${initial} := sload(${name}Pos())`,
173
+ ` }`,
174
+ ` function ${name}Set(value) {`,
175
+ ` sstore(${name}Pos(), value)`,
176
+ ` }`,
177
+ ]);
178
+ };
179
+ const getYul = (file) => {
180
+ // Getting base data
181
+ const foxClass = (0, get_fox_class_1.default)(file);
182
+ const abi = (0, get_abi_1.default)(foxClass);
183
+ let yul = getBaseYul(foxClass.name);
184
+ // Adding properties
185
+ foxClass.properties.forEach((property, index) => {
186
+ yul = addPropertyDispatcher(yul, abi, property);
187
+ yul = addStorageLayout(yul, property, index);
188
+ yul = addStorageAccess(yul, property);
189
+ // TODO Handle private properties
190
+ });
191
+ // Adding methods
192
+ foxClass.methods.forEach((method) => {
193
+ yul = addMethodDispatcher(yul, abi, method);
194
+ yul = addMethodFunction(yul, method);
195
+ // TODO Handle private methods
196
+ });
197
+ // forEachChild(ast, process);
198
+ return yul.join("\n");
199
+ };
200
+ exports.default = getYul;
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isMinusEquals = exports.isEquals = exports.isPlusEquals = exports.getNodeReturnType = exports.getNodeName = exports.getClassNode = void 0;
4
+ const typescript_1 = require("typescript");
5
+ const getClassNode = (node) => {
6
+ if ((0, typescript_1.isClassDeclaration)(node)) {
7
+ return node;
8
+ }
9
+ let classNode = undefined;
10
+ (0, typescript_1.forEachChild)(node, (child) => {
11
+ if ((0, typescript_1.isClassDeclaration)(child)) {
12
+ classNode = child;
13
+ }
14
+ });
15
+ if (!classNode)
16
+ throw new Error("Could not find class");
17
+ return classNode;
18
+ };
19
+ exports.getClassNode = getClassNode;
20
+ const getNodeName = (node) => {
21
+ if (node.text)
22
+ return node.text;
23
+ if (node.escapedText)
24
+ return node.escapedText;
25
+ return node.name.escapedText;
26
+ };
27
+ exports.getNodeName = getNodeName;
28
+ const getNodeReturnType = (node) => {
29
+ const type = node.type;
30
+ if (!type)
31
+ return "void";
32
+ if (type.kind === typescript_1.SyntaxKind.NumberKeyword) {
33
+ return "uint256";
34
+ }
35
+ if (type.kind === typescript_1.SyntaxKind.VoidKeyword) {
36
+ return "void";
37
+ }
38
+ // TODO Add more types
39
+ throw new Error("Unsupported type");
40
+ };
41
+ exports.getNodeReturnType = getNodeReturnType;
42
+ const isPlusEquals = (expression) => {
43
+ return expression.operatorToken.kind === typescript_1.SyntaxKind.PlusEqualsToken;
44
+ };
45
+ exports.isPlusEquals = isPlusEquals;
46
+ const isEquals = (expression) => {
47
+ return expression.operatorToken.kind === typescript_1.SyntaxKind.EqualsToken;
48
+ };
49
+ exports.isEquals = isEquals;
50
+ const isMinusEquals = (expression) => {
51
+ return expression.operatorToken.kind === typescript_1.SyntaxKind.MinusEqualsToken;
52
+ };
53
+ exports.isMinusEquals = isMinusEquals;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getAllContractFiles = void 0;
7
+ const path_1 = __importDefault(require("path"));
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const CONTRCT_PATH = "./contracts";
10
+ const getAllContractFiles = () => {
11
+ return fs_1.default
12
+ .readdirSync(CONTRCT_PATH)
13
+ .filter((file) => {
14
+ return fs_1.default.statSync(path_1.default.join(CONTRCT_PATH, file)).isFile();
15
+ })
16
+ .map((file) => {
17
+ return path_1.default.join(CONTRCT_PATH, file);
18
+ })
19
+ .filter((file) => {
20
+ return file.endsWith(".ts") || file.endsWith(".js");
21
+ });
22
+ };
23
+ exports.getAllContractFiles = getAllContractFiles;
package/lib/index.js ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
4
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5
+ return new (P || (P = Promise))(function (resolve, reject) {
6
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
7
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
8
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
9
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
10
+ });
11
+ };
12
+ Object.defineProperty(exports, "__esModule", { value: true });
13
+ const commander_1 = require("commander");
14
+ const compiler_1 = require("./compiler");
15
+ const file_helper_1 = require("./helpers/file-helper");
16
+ // clear();
17
+ // console.log(
18
+ // chalk.red(figlet.textSync("fox-cli", { horizontalLayout: "full" }))
19
+ // );
20
+ commander_1.program.name("fox").description("CLI for the Fox compiler").version("0.1.0");
21
+ // program
22
+ // .command("compile")
23
+ // .description("Compile TypeScript file")
24
+ // .argument("<string>", "file name")
25
+ // .action(async (str, options) => {
26
+ // console.log(await compileTypeScriptToBytecode(str));
27
+ // });
28
+ commander_1.program
29
+ .command("compile")
30
+ .description("Compile all TypeScript file")
31
+ .action((str, options) => __awaiter(void 0, void 0, void 0, function* () {
32
+ const files = (0, file_helper_1.getAllContractFiles)();
33
+ const promises = files.map((file) => __awaiter(void 0, void 0, void 0, function* () {
34
+ console.log(yield (0, compiler_1.compileTypeScriptToBytecode)(file));
35
+ }));
36
+ yield Promise.all(promises);
37
+ }));
38
+ commander_1.program.parse();
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FoxStatementType = exports.FoxOperator = exports.FoxExpressionType = void 0;
4
+ var FoxExpressionType;
5
+ (function (FoxExpressionType) {
6
+ FoxExpressionType["Binary"] = "Binary";
7
+ FoxExpressionType["Value"] = "Value";
8
+ FoxExpressionType["Storage"] = "Storage";
9
+ })(FoxExpressionType = exports.FoxExpressionType || (exports.FoxExpressionType = {}));
10
+ var FoxOperator;
11
+ (function (FoxOperator) {
12
+ FoxOperator["Plus"] = "+";
13
+ FoxOperator["Minus"] = "-";
14
+ FoxOperator["Multiply"] = "*";
15
+ FoxOperator["Divide"] = "/";
16
+ FoxOperator["Modulo"] = "%";
17
+ FoxOperator["Equals"] = "==";
18
+ FoxOperator["NotEquals"] = "!=";
19
+ FoxOperator["GreaterThan"] = ">";
20
+ FoxOperator["LessThan"] = "<";
21
+ FoxOperator["GreaterThanOrEqual"] = ">=";
22
+ FoxOperator["LessThanOrEqual"] = "<=";
23
+ FoxOperator["And"] = "&&";
24
+ FoxOperator["Or"] = "||";
25
+ FoxOperator["Not"] = "!";
26
+ })(FoxOperator = exports.FoxOperator || (exports.FoxOperator = {}));
27
+ var FoxStatementType;
28
+ (function (FoxStatementType) {
29
+ FoxStatementType["StorageUpdate"] = "StorageUpdate";
30
+ FoxStatementType["Return"] = "Return";
31
+ })(FoxStatementType = exports.FoxStatementType || (exports.FoxStatementType = {}));
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "skittles",
3
+ "version": "0.1.0",
4
+ "description": "TypeScript Smart Contract Language for the EVM",
5
+ "main": "./lib/index.js",
6
+ "bin": {
7
+ "fox": "./lib/index.js"
8
+ },
9
+ "scripts": {
10
+ "start": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts",
11
+ "create": "yarn run build && yarn run test",
12
+ "build": "tsc -p .",
13
+ "refresh": "rm -rf ./node_modules ./package-lock.json && yarn",
14
+ "local": "sudo yarn global add && fox",
15
+ "test": "hardhat test"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/chase-manning/fox.git"
20
+ },
21
+ "author": "Chase Manning",
22
+ "license": "MIT",
23
+ "bugs": {
24
+ "url": "https://github.com/chase-manning/fox/issues"
25
+ },
26
+ "homepage": "https://github.com/chase-manning/fox#readme",
27
+ "dependencies": {
28
+ "chalk": "4.1.2",
29
+ "clear": "^0.1.0",
30
+ "commander": "^9.4.0",
31
+ "figlet": "^1.5.2",
32
+ "path": "^0.12.7",
33
+ "solc": "^0.8.16",
34
+ "typescript": "^4.7.4"
35
+ },
36
+ "devDependencies": {
37
+ "@nomiclabs/hardhat-ethers": "^2.1.0",
38
+ "@nomiclabs/hardhat-etherscan": "^3.1.0",
39
+ "@nomiclabs/hardhat-waffle": "^2.0.3",
40
+ "@typechain/ethers-v5": "^7.2.0",
41
+ "@typechain/hardhat": "^2.3.1",
42
+ "@types/chai": "^4.3.1",
43
+ "@types/clear": "^0.1.2",
44
+ "@types/figlet": "^1.5.4",
45
+ "@types/mocha": "^9.1.1",
46
+ "@types/node": "^18.6.4",
47
+ "@typescript-eslint/eslint-plugin": "^4.33.0",
48
+ "@typescript-eslint/parser": "^4.33.0",
49
+ "chai": "^4.3.6",
50
+ "dotenv": "^16.0.1",
51
+ "eslint": "^7.32.0",
52
+ "eslint-config-prettier": "^8.5.0",
53
+ "eslint-config-standard": "^16.0.3",
54
+ "eslint-plugin-import": "^2.26.0",
55
+ "eslint-plugin-node": "^11.1.0",
56
+ "eslint-plugin-prettier": "^3.4.1",
57
+ "eslint-plugin-promise": "^5.2.0",
58
+ "ethereum-waffle": "^3.4.4",
59
+ "ethers": "^5.6.9",
60
+ "hardhat": "^2.10.1",
61
+ "hardhat-gas-reporter": "^1.0.8",
62
+ "nodemon": "^2.0.19",
63
+ "prettier": "^2.7.1",
64
+ "prettier-plugin-solidity": "^1.0.0-beta.13",
65
+ "solhint": "^3.3.7",
66
+ "solidity-coverage": "^0.7.21",
67
+ "ts-node": "^10.9.1",
68
+ "typechain": "^5.2.0"
69
+ }
70
+ }