skittles 0.1.1 → 0.1.2
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/lib/compiler.js +24 -0
- package/lib/data/yul-template.js +85 -0
- package/lib/get-abi.js +30 -0
- package/lib/get-ast.js +15 -0
- package/lib/get-bytecode.js +23 -0
- package/lib/get-selector.js +19 -0
- package/lib/get-skittles-class.js +218 -0
- package/lib/get-yul.js +200 -0
- package/lib/helpers/ast-helper.js +53 -0
- package/lib/helpers/file-helper.js +23 -0
- package/lib/index.js +41 -0
- package/lib/types/skittles-class.js +31 -0
- package/package.json +1 -1
package/lib/compiler.js
ADDED
|
@@ -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_skittles_class_1 = __importDefault(require("./get-skittles-class"));
|
|
18
|
+
const get_yul_1 = __importDefault(require("./get-yul"));
|
|
19
|
+
const compileTypeScriptToBytecode = (fileName) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
const skittlesClass = (0, get_skittles_class_1.default)(fileName);
|
|
21
|
+
const yul = (0, get_yul_1.default)(fileName);
|
|
22
|
+
return (0, get_bytecode_1.default)(skittlesClass.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 = (skittlesClass) => {
|
|
25
|
+
return [
|
|
26
|
+
...skittlesClass.properties.filter((p) => !p.private).map(getPropertyAbi),
|
|
27
|
+
...skittlesClass.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,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;
|
|
@@ -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.getSkittlesParameters = 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 skittles_class_1 = require("./types/skittles-class");
|
|
11
|
+
const getSkittlesType = (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 getSkittlesOperator = (syntaxKind) => {
|
|
30
|
+
switch (syntaxKind) {
|
|
31
|
+
case typescript_1.SyntaxKind.PlusToken:
|
|
32
|
+
return skittles_class_1.SkittlesOperator.Plus;
|
|
33
|
+
case typescript_1.SyntaxKind.MinusToken:
|
|
34
|
+
return skittles_class_1.SkittlesOperator.Minus;
|
|
35
|
+
case typescript_1.SyntaxKind.AsteriskToken:
|
|
36
|
+
return skittles_class_1.SkittlesOperator.Multiply;
|
|
37
|
+
case typescript_1.SyntaxKind.SlashToken:
|
|
38
|
+
return skittles_class_1.SkittlesOperator.Divide;
|
|
39
|
+
case typescript_1.SyntaxKind.PercentToken:
|
|
40
|
+
return skittles_class_1.SkittlesOperator.Modulo;
|
|
41
|
+
case typescript_1.SyntaxKind.AmpersandAmpersandToken:
|
|
42
|
+
return skittles_class_1.SkittlesOperator.And;
|
|
43
|
+
case typescript_1.SyntaxKind.BarBarToken:
|
|
44
|
+
return skittles_class_1.SkittlesOperator.Or;
|
|
45
|
+
case typescript_1.SyntaxKind.EqualsEqualsToken:
|
|
46
|
+
return skittles_class_1.SkittlesOperator.Equals;
|
|
47
|
+
case typescript_1.SyntaxKind.ExclamationEqualsToken:
|
|
48
|
+
return skittles_class_1.SkittlesOperator.NotEquals;
|
|
49
|
+
case typescript_1.SyntaxKind.LessThanToken:
|
|
50
|
+
return skittles_class_1.SkittlesOperator.LessThan;
|
|
51
|
+
case typescript_1.SyntaxKind.LessThanEqualsToken:
|
|
52
|
+
return skittles_class_1.SkittlesOperator.LessThanOrEqual;
|
|
53
|
+
case typescript_1.SyntaxKind.GreaterThanToken:
|
|
54
|
+
return skittles_class_1.SkittlesOperator.GreaterThan;
|
|
55
|
+
case typescript_1.SyntaxKind.GreaterThanEqualsToken:
|
|
56
|
+
return skittles_class_1.SkittlesOperator.GreaterThanOrEqual;
|
|
57
|
+
default:
|
|
58
|
+
throw new Error(`Unknown syntax kind: ${syntaxKind}`);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const getSkittlesExpression = (expression) => {
|
|
62
|
+
if ((0, typescript_1.isLiteralExpression)(expression)) {
|
|
63
|
+
return {
|
|
64
|
+
expressionType: skittles_class_1.SkittlesExpressionType.Value,
|
|
65
|
+
value: expression.text,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
if ((0, typescript_1.isIdentifier)(expression)) {
|
|
69
|
+
return {
|
|
70
|
+
expressionType: skittles_class_1.SkittlesExpressionType.Value,
|
|
71
|
+
value: expression.escapedText,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
if ((0, typescript_1.isPropertyAccessExpression)(expression)) {
|
|
75
|
+
return {
|
|
76
|
+
expressionType: skittles_class_1.SkittlesExpressionType.Storage,
|
|
77
|
+
variable: (0, ast_helper_1.getNodeName)(expression),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if ((0, typescript_1.isBinaryExpression)(expression)) {
|
|
81
|
+
return {
|
|
82
|
+
expressionType: skittles_class_1.SkittlesExpressionType.Binary,
|
|
83
|
+
left: getSkittlesExpression(expression.left),
|
|
84
|
+
right: getSkittlesExpression(expression.right),
|
|
85
|
+
operator: getSkittlesOperator(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 getSkittlesProperty = (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: getSkittlesType(astProperty.type.kind),
|
|
106
|
+
value: initializer ? getSkittlesExpression(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 getSkittlesParameters = (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: getSkittlesType((_a = node.type) === null || _a === void 0 ? void 0 : _a.kind),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
return inputs;
|
|
138
|
+
};
|
|
139
|
+
exports.getSkittlesParameters = getSkittlesParameters;
|
|
140
|
+
const getSkittlesStatement = (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: skittles_class_1.SkittlesStatementType.StorageUpdate,
|
|
148
|
+
variable: (0, ast_helper_1.getNodeName)(expression.left),
|
|
149
|
+
value: getSkittlesExpression(expression.right),
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
if ((0, ast_helper_1.isPlusEquals)(expression)) {
|
|
153
|
+
return {
|
|
154
|
+
statementType: skittles_class_1.SkittlesStatementType.StorageUpdate,
|
|
155
|
+
variable: (0, ast_helper_1.getNodeName)(expression.left),
|
|
156
|
+
value: {
|
|
157
|
+
expressionType: skittles_class_1.SkittlesExpressionType.Binary,
|
|
158
|
+
operator: skittles_class_1.SkittlesOperator.Plus,
|
|
159
|
+
left: getSkittlesExpression(expression.left),
|
|
160
|
+
right: getSkittlesExpression(expression.right),
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
if ((0, ast_helper_1.isMinusEquals)(expression)) {
|
|
165
|
+
return {
|
|
166
|
+
statementType: skittles_class_1.SkittlesStatementType.StorageUpdate,
|
|
167
|
+
variable: (0, ast_helper_1.getNodeName)(expression.left),
|
|
168
|
+
value: {
|
|
169
|
+
expressionType: skittles_class_1.SkittlesExpressionType.Binary,
|
|
170
|
+
operator: skittles_class_1.SkittlesOperator.Minus,
|
|
171
|
+
left: getSkittlesExpression(expression.left),
|
|
172
|
+
right: getSkittlesExpression(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: skittles_class_1.SkittlesStatementType.Return,
|
|
189
|
+
type: returnType,
|
|
190
|
+
value: getSkittlesExpression(node.expression),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
throw new Error(`Unknown statement type: ${node.kind}`);
|
|
195
|
+
};
|
|
196
|
+
const getSkittlesMethod = (astMethod) => {
|
|
197
|
+
var _a, _b;
|
|
198
|
+
return {
|
|
199
|
+
name: (0, ast_helper_1.getNodeName)(astMethod),
|
|
200
|
+
returns: getSkittlesType((_a = astMethod.type) === null || _a === void 0 ? void 0 : _a.kind),
|
|
201
|
+
private: isNodePrivate(astMethod),
|
|
202
|
+
view: isNodeView(astMethod),
|
|
203
|
+
parameters: (0, exports.getSkittlesParameters)(astMethod),
|
|
204
|
+
statements: ((_b = astMethod.body) === null || _b === void 0 ? void 0 : _b.statements.map((statement) => { var _a; return getSkittlesStatement(statement, getSkittlesType((_a = astMethod.type) === null || _a === void 0 ? void 0 : _a.kind)); })) || [],
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
const getSkittlesClass = (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(getSkittlesProperty),
|
|
215
|
+
methods: astMethods.map(getSkittlesMethod),
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
exports.default = getSkittlesClass;
|
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_skittles_class_1 = __importDefault(require("./get-skittles-class"));
|
|
33
|
+
const skittles_class_1 = require("./types/skittles-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 skittles_class_1.SkittlesOperator.Plus:
|
|
86
|
+
return `safeAdd(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
87
|
+
case skittles_class_1.SkittlesOperator.Minus:
|
|
88
|
+
return `sub(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
89
|
+
case skittles_class_1.SkittlesOperator.Multiply:
|
|
90
|
+
return `mul(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
91
|
+
case skittles_class_1.SkittlesOperator.Divide:
|
|
92
|
+
return `div(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
93
|
+
case skittles_class_1.SkittlesOperator.Modulo:
|
|
94
|
+
return `mod(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
95
|
+
case skittles_class_1.SkittlesOperator.Equals:
|
|
96
|
+
return `eq(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
97
|
+
case skittles_class_1.SkittlesOperator.NotEquals:
|
|
98
|
+
return `not(eq(${getExpressionYul(left)}, ${getExpressionYul(right)}))`;
|
|
99
|
+
case skittles_class_1.SkittlesOperator.GreaterThan:
|
|
100
|
+
return `gt(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
101
|
+
case skittles_class_1.SkittlesOperator.LessThan:
|
|
102
|
+
return `lt(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
103
|
+
case skittles_class_1.SkittlesOperator.GreaterThanOrEqual:
|
|
104
|
+
return `gte(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
105
|
+
case skittles_class_1.SkittlesOperator.LessThanOrEqual:
|
|
106
|
+
return `lte(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
107
|
+
case skittles_class_1.SkittlesOperator.And:
|
|
108
|
+
return `and(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
109
|
+
case skittles_class_1.SkittlesOperator.Or:
|
|
110
|
+
return `or(${getExpressionYul(left)}, ${getExpressionYul(right)})`;
|
|
111
|
+
case skittles_class_1.SkittlesOperator.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 skittles_class_1.SkittlesExpressionType.Binary:
|
|
120
|
+
return getBinaryYul(expression);
|
|
121
|
+
case skittles_class_1.SkittlesExpressionType.Value:
|
|
122
|
+
return expression.value;
|
|
123
|
+
case skittles_class_1.SkittlesExpressionType.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 skittles_class_1.SkittlesStatementType.StorageUpdate:
|
|
140
|
+
return getStorageUpdateYul(statement);
|
|
141
|
+
case skittles_class_1.SkittlesStatementType.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 skittlesClass = (0, get_skittles_class_1.default)(file);
|
|
182
|
+
const abi = (0, get_abi_1.default)(skittlesClass);
|
|
183
|
+
let yul = getBaseYul(skittlesClass.name);
|
|
184
|
+
// Adding properties
|
|
185
|
+
skittlesClass.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
|
+
skittlesClass.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,41 @@
|
|
|
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("skittles-cli", { horizontalLayout: "full" }))
|
|
19
|
+
// );
|
|
20
|
+
commander_1.program
|
|
21
|
+
.name("skittles")
|
|
22
|
+
.description("CLI for the Skittles compiler")
|
|
23
|
+
.version("0.1.0");
|
|
24
|
+
// program
|
|
25
|
+
// .command("compile")
|
|
26
|
+
// .description("Compile TypeScript file")
|
|
27
|
+
// .argument("<string>", "file name")
|
|
28
|
+
// .action(async (str, options) => {
|
|
29
|
+
// console.log(await compileTypeScriptToBytecode(str));
|
|
30
|
+
// });
|
|
31
|
+
commander_1.program
|
|
32
|
+
.command("compile")
|
|
33
|
+
.description("Compile all TypeScript file")
|
|
34
|
+
.action((str, options) => __awaiter(void 0, void 0, void 0, function* () {
|
|
35
|
+
const files = (0, file_helper_1.getAllContractFiles)();
|
|
36
|
+
const promises = files.map((file) => __awaiter(void 0, void 0, void 0, function* () {
|
|
37
|
+
console.log(yield (0, compiler_1.compileTypeScriptToBytecode)(file));
|
|
38
|
+
}));
|
|
39
|
+
yield Promise.all(promises);
|
|
40
|
+
}));
|
|
41
|
+
commander_1.program.parse();
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SkittlesStatementType = exports.SkittlesOperator = exports.SkittlesExpressionType = void 0;
|
|
4
|
+
var SkittlesExpressionType;
|
|
5
|
+
(function (SkittlesExpressionType) {
|
|
6
|
+
SkittlesExpressionType["Binary"] = "Binary";
|
|
7
|
+
SkittlesExpressionType["Value"] = "Value";
|
|
8
|
+
SkittlesExpressionType["Storage"] = "Storage";
|
|
9
|
+
})(SkittlesExpressionType = exports.SkittlesExpressionType || (exports.SkittlesExpressionType = {}));
|
|
10
|
+
var SkittlesOperator;
|
|
11
|
+
(function (SkittlesOperator) {
|
|
12
|
+
SkittlesOperator["Plus"] = "+";
|
|
13
|
+
SkittlesOperator["Minus"] = "-";
|
|
14
|
+
SkittlesOperator["Multiply"] = "*";
|
|
15
|
+
SkittlesOperator["Divide"] = "/";
|
|
16
|
+
SkittlesOperator["Modulo"] = "%";
|
|
17
|
+
SkittlesOperator["Equals"] = "==";
|
|
18
|
+
SkittlesOperator["NotEquals"] = "!=";
|
|
19
|
+
SkittlesOperator["GreaterThan"] = ">";
|
|
20
|
+
SkittlesOperator["LessThan"] = "<";
|
|
21
|
+
SkittlesOperator["GreaterThanOrEqual"] = ">=";
|
|
22
|
+
SkittlesOperator["LessThanOrEqual"] = "<=";
|
|
23
|
+
SkittlesOperator["And"] = "&&";
|
|
24
|
+
SkittlesOperator["Or"] = "||";
|
|
25
|
+
SkittlesOperator["Not"] = "!";
|
|
26
|
+
})(SkittlesOperator = exports.SkittlesOperator || (exports.SkittlesOperator = {}));
|
|
27
|
+
var SkittlesStatementType;
|
|
28
|
+
(function (SkittlesStatementType) {
|
|
29
|
+
SkittlesStatementType["StorageUpdate"] = "StorageUpdate";
|
|
30
|
+
SkittlesStatementType["Return"] = "Return";
|
|
31
|
+
})(SkittlesStatementType = exports.SkittlesStatementType || (exports.SkittlesStatementType = {}));
|