otomato-sdk 1.0.1 → 1.2.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/dist/examples/create-action.js +21 -0
- package/dist/examples/create-automation.js +42 -0
- package/dist/src/constants/Blocks.js +391 -0
- package/dist/src/constants/tokens.js +40 -0
- package/dist/src/index.js +3 -2
- package/dist/src/models/Action.js +6 -1
- package/dist/src/models/Automation.js +44 -1
- package/dist/src/models/Edge.js +25 -0
- package/dist/src/models/Node.js +92 -0
- package/dist/src/models/Trigger.js +3 -88
- package/dist/src/services/ApiService.js +39 -1
- package/dist/src/utils/typeValidator.js +70 -0
- package/dist/test/action.spec.js +74 -0
- package/dist/test/automation.spec.js +71 -0
- package/dist/test/node.spec.js +126 -0
- package/dist/test/trigger.spec.js +3 -3
- package/dist/test/typeValidator.spec.js +59 -0
- package/dist/types/examples/create-action.d.ts +1 -0
- package/dist/types/examples/create-automation.d.ts +1 -0
- package/dist/types/src/constants/Blocks.d.ts +118 -0
- package/dist/types/src/constants/tokens.d.ts +9 -0
- package/dist/types/src/index.d.ts +3 -2
- package/dist/types/src/models/Action.d.ts +11 -5
- package/dist/types/src/models/Automation.d.ts +22 -5
- package/dist/types/src/models/Edge.d.ts +14 -0
- package/dist/types/src/models/Node.d.ts +42 -0
- package/dist/types/src/models/Trigger.d.ts +4 -24
- package/dist/types/src/services/ApiService.d.ts +3 -6
- package/dist/types/src/utils/typeValidator.d.ts +4 -0
- package/dist/types/test/action.spec.d.ts +1 -0
- package/dist/types/test/automation.spec.d.ts +1 -0
- package/dist/types/test/node.spec.d.ts +1 -0
- package/dist/types/test/typeValidator.spec.d.ts +1 -0
- package/examples/create-action.ts +28 -0
- package/examples/create-automation.ts +41 -0
- package/package.json +4 -3
- package/src/constants/{ActionBlocks.ts → Blocks.ts} +73 -2
- package/src/constants/chains.ts +1 -1
- package/src/constants/json.json +16 -0
- package/src/constants/tokens.ts +56 -0
- package/src/index.ts +3 -2
- package/src/models/Action.ts +8 -6
- package/src/models/Automation.ts +47 -6
- package/src/models/Edge.ts +33 -0
- package/src/models/Node.ts +118 -0
- package/src/models/Trigger.ts +5 -101
- package/src/services/ApiService.ts +31 -6
- package/src/utils/typeValidator.ts +65 -0
- package/test/action.spec.ts +90 -0
- package/test/automation.spec.ts +88 -0
- package/test/node.spec.ts +143 -0
- package/test/trigger.spec.ts +3 -3
- package/test/typeValidator.spec.ts +71 -0
- package/src/services/AutomationService.ts +0 -6
package/src/models/Automation.ts
CHANGED
|
@@ -1,6 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { Node } from './Node.js';
|
|
2
|
+
import { Edge } from './Edge.js';
|
|
3
|
+
import { apiServices } from '../services/ApiService.js';
|
|
4
|
+
|
|
5
|
+
export class Automation {
|
|
6
|
+
name: string;
|
|
7
|
+
nodes: Node[];
|
|
8
|
+
edges: Edge[];
|
|
9
|
+
|
|
10
|
+
constructor(name: string, nodes: Node[] = [], edges: Edge[] = []) {
|
|
11
|
+
this.name = name;
|
|
12
|
+
this.nodes = nodes;
|
|
13
|
+
this.edges = edges;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
setName(name: string): void {
|
|
17
|
+
this.name = name;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
addNode(node: Node): void {
|
|
21
|
+
this.nodes.push(node);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
addNodes(nodes: Node[]): void {
|
|
25
|
+
this.nodes.push(...nodes);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
addEdge(edge: Edge): void {
|
|
29
|
+
this.edges.push(edge);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
addEdges(edges: Edge[]): void {
|
|
33
|
+
this.edges.push(...edges);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
toJSON() {
|
|
37
|
+
return {
|
|
38
|
+
name: this.name,
|
|
39
|
+
nodes: this.nodes.map(node => node.toJSON()),
|
|
40
|
+
edges: this.edges.map(edge => edge.toJSON()),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async save() {
|
|
45
|
+
return apiServices.post('/workflows', this.toJSON());
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Node } from './Node.js';
|
|
2
|
+
|
|
3
|
+
let edgeCounter = 0;
|
|
4
|
+
const generatedEdgeIds = new Set<string>();
|
|
5
|
+
|
|
6
|
+
export class Edge {
|
|
7
|
+
id: string;
|
|
8
|
+
source: Node;
|
|
9
|
+
target: Node;
|
|
10
|
+
|
|
11
|
+
constructor(edge: { id?: string, source: Node, target: Node }) {
|
|
12
|
+
if (edge.id) {
|
|
13
|
+
this.id = edge.id;
|
|
14
|
+
} else {
|
|
15
|
+
this.id = `e-${++edgeCounter}`;
|
|
16
|
+
while (generatedEdgeIds.has(this.id)) {
|
|
17
|
+
this.id = `e-${++edgeCounter}`;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
generatedEdgeIds.add(this.id);
|
|
21
|
+
|
|
22
|
+
this.source = edge.source;
|
|
23
|
+
this.target = edge.target;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
toJSON(): { [key: string]: any } {
|
|
27
|
+
return {
|
|
28
|
+
id: this.id,
|
|
29
|
+
source: this.source.getRef(),
|
|
30
|
+
target: this.target.getRef(),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Parameter } from './Parameter.js';
|
|
2
|
+
import { validateType } from '../utils/typeValidator.js';
|
|
3
|
+
|
|
4
|
+
export interface Position {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
let nodeCounter = 0;
|
|
10
|
+
const generatedRefs = new Set<string>();
|
|
11
|
+
|
|
12
|
+
export class Node {
|
|
13
|
+
id: number;
|
|
14
|
+
name: string;
|
|
15
|
+
description: string;
|
|
16
|
+
parameters: { [key: string]: Parameter };
|
|
17
|
+
keyMap: { [key: string]: string };
|
|
18
|
+
position?: Position;
|
|
19
|
+
ref: string;
|
|
20
|
+
class: string; // Updated to use class instead of type
|
|
21
|
+
|
|
22
|
+
constructor(node: { id: number; name: string; description: string; parameters: Parameter[], ref?: string, position?: Position, class: string }) {
|
|
23
|
+
this.id = node.id;
|
|
24
|
+
this.name = node.name;
|
|
25
|
+
this.description = node.description;
|
|
26
|
+
this.parameters = {};
|
|
27
|
+
this.keyMap = {};
|
|
28
|
+
this.class = node.class; // Set class property
|
|
29
|
+
|
|
30
|
+
if (node.ref) {
|
|
31
|
+
this.ref = node.ref;
|
|
32
|
+
} else {
|
|
33
|
+
this.ref = `n-${++nodeCounter}`;
|
|
34
|
+
while (generatedRefs.has(this.ref)) {
|
|
35
|
+
this.ref = `n-${++nodeCounter}`;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
generatedRefs.add(this.ref);
|
|
39
|
+
|
|
40
|
+
node.parameters.forEach(param => {
|
|
41
|
+
this.parameters[param.key] = { ...param, value: null };
|
|
42
|
+
const simplifiedKey = this.getSimplifiedKey(param.key);
|
|
43
|
+
this.keyMap[simplifiedKey] = param.key;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (node.position) {
|
|
47
|
+
this.position = node.position;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
setChainId(value: number): void {
|
|
52
|
+
this.setParameter('chainId', value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
setContractAddress(value: string): void {
|
|
56
|
+
this.setParameter('contractAddress', value);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
setParams(key: string, value: any): void {
|
|
60
|
+
const fullKey = this.parameters[`abiParams.${key}`] ? `abiParams.${key}` : key;
|
|
61
|
+
this.setParameter(fullKey, value);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
setPosition(x: number, y: number): void {
|
|
65
|
+
this.position = { x, y };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
getRef(): string {
|
|
69
|
+
return this.ref;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
protected setParameter(key: string, value: any): void {
|
|
73
|
+
if (key in this.parameters) {
|
|
74
|
+
const param = this.parameters[key];
|
|
75
|
+
if (validateType(param.type, value)) {
|
|
76
|
+
this.parameters[key].value = value;
|
|
77
|
+
} else {
|
|
78
|
+
throw new Error(`Invalid type for parameter ${key}. Expected ${param.type}.`);
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
throw new Error(`Parameter with key ${key} not found`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
getParameter(key: string): any {
|
|
86
|
+
if (key in this.parameters) {
|
|
87
|
+
return this.parameters[key].value;
|
|
88
|
+
} else {
|
|
89
|
+
throw new Error(`Parameter with key ${key} not found`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
getParameters(): { [key: string]: any } {
|
|
94
|
+
return Object.keys(this.parameters).reduce((acc, key) => {
|
|
95
|
+
acc[key] = this.parameters[key].value;
|
|
96
|
+
return acc;
|
|
97
|
+
}, {} as { [key: string]: any });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
toJSON(): { [key: string]: any } {
|
|
101
|
+
const json: { [key: string]: any } = {
|
|
102
|
+
id: this.id,
|
|
103
|
+
ref: this.ref,
|
|
104
|
+
type: this.class,
|
|
105
|
+
data: {
|
|
106
|
+
parameters: this.getParameters(),
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
if (this.position) {
|
|
110
|
+
json.position = this.position;
|
|
111
|
+
}
|
|
112
|
+
return json;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private getSimplifiedKey(key: string): string {
|
|
116
|
+
return key.replace(/[.\[\]]/g, '_');
|
|
117
|
+
}
|
|
118
|
+
}
|
package/src/models/Trigger.ts
CHANGED
|
@@ -1,34 +1,12 @@
|
|
|
1
1
|
import { Parameter } from './Parameter.js';
|
|
2
|
-
import {
|
|
2
|
+
import { Node, Position } from './Node.js';
|
|
3
3
|
|
|
4
|
-
export class Trigger {
|
|
5
|
-
id: number;
|
|
6
|
-
name: string;
|
|
7
|
-
description: string;
|
|
4
|
+
export class Trigger extends Node {
|
|
8
5
|
type: number;
|
|
9
|
-
parameters: { [key: string]: Parameter };
|
|
10
|
-
keyMap: { [key: string]: string };
|
|
11
6
|
|
|
12
|
-
constructor(trigger: { id: number; name: string; description: string; type: number; parameters: Parameter[] }) {
|
|
13
|
-
|
|
14
|
-
this.name = trigger.name;
|
|
15
|
-
this.description = trigger.description;
|
|
7
|
+
constructor(trigger: { id: number; name: string; description: string; type: number; parameters: Parameter[], ref?: string, position?: Position }) {
|
|
8
|
+
super({ ...trigger, class: 'trigger' });
|
|
16
9
|
this.type = trigger.type;
|
|
17
|
-
this.parameters = {};
|
|
18
|
-
this.keyMap = {};
|
|
19
|
-
trigger.parameters.forEach(param => {
|
|
20
|
-
this.parameters[param.key] = { ...param, value: null };
|
|
21
|
-
const simplifiedKey = this.getSimplifiedKey(param.key);
|
|
22
|
-
this.keyMap[simplifiedKey] = param.key;
|
|
23
|
-
});
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
setChainId(value: number): void {
|
|
27
|
-
this.setParameter('chainId', value);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
setContractAddress(value: string): void {
|
|
31
|
-
this.setParameter('contractAddress', value);
|
|
32
10
|
}
|
|
33
11
|
|
|
34
12
|
setCondition(value: string): void {
|
|
@@ -51,78 +29,4 @@ export class Trigger {
|
|
|
51
29
|
}
|
|
52
30
|
this.setParameter('interval', value);
|
|
53
31
|
}
|
|
54
|
-
|
|
55
|
-
setParams(key: string, value: any): void {
|
|
56
|
-
const fullKey = `abiParams.${key}`;
|
|
57
|
-
if (fullKey in this.parameters) {
|
|
58
|
-
this.setParameter(fullKey, value);
|
|
59
|
-
} else {
|
|
60
|
-
throw new Error(`Parameter with simplified key ${key} not found in abiParams`);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
private setParameter(key: string, value: any): void {
|
|
65
|
-
if (key in this.parameters) {
|
|
66
|
-
const param = this.parameters[key];
|
|
67
|
-
if (this.validateType(param.type, value)) {
|
|
68
|
-
this.parameters[key].value = value;
|
|
69
|
-
} else {
|
|
70
|
-
throw new Error(`Invalid type for parameter ${key}. Expected ${param.type}.`);
|
|
71
|
-
}
|
|
72
|
-
} else {
|
|
73
|
-
throw new Error(`Parameter with key ${key} not found`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
private validateType(expectedType: string, value: any): boolean {
|
|
78
|
-
switch (expectedType) {
|
|
79
|
-
case 'int':
|
|
80
|
-
case 'integer':
|
|
81
|
-
case 'uint256':
|
|
82
|
-
case 'int256':
|
|
83
|
-
return Number.isInteger(value);
|
|
84
|
-
case 'address':
|
|
85
|
-
return typeof value === 'string' && this.isAddress(value);
|
|
86
|
-
case 'float':
|
|
87
|
-
return typeof value === 'number';
|
|
88
|
-
case 'logic_operator':
|
|
89
|
-
const validOperators = new Set(['<', '>', '<=', '>=', '==']);
|
|
90
|
-
return typeof value === 'string' && validOperators.has(value);
|
|
91
|
-
case 'any':
|
|
92
|
-
return true;
|
|
93
|
-
default:
|
|
94
|
-
return false;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
private isAddress(value: string): boolean {
|
|
99
|
-
return ethers.isAddress(value);
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
getParameter(key: string): any {
|
|
103
|
-
if (key in this.parameters) {
|
|
104
|
-
return this.parameters[key].value;
|
|
105
|
-
} else {
|
|
106
|
-
throw new Error(`Parameter with key ${key} not found`);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
getParameters(): { [key: string]: any } {
|
|
111
|
-
return Object.keys(this.parameters).reduce((acc, key) => {
|
|
112
|
-
acc[key] = this.parameters[key].value;
|
|
113
|
-
return acc;
|
|
114
|
-
}, {} as { [key: string]: any });
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
toJSON(): { [key: string]: any } {
|
|
118
|
-
const json: { [key: string]: any } = {
|
|
119
|
-
id: this.id,
|
|
120
|
-
parameters: this.getParameters(),
|
|
121
|
-
};
|
|
122
|
-
return json;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
private getSimplifiedKey(key: string): string {
|
|
126
|
-
return key.replace(/[.\[\]]/g, '_');
|
|
127
|
-
}
|
|
128
|
-
}
|
|
32
|
+
}
|
|
@@ -1,6 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
// networkService.ts
|
|
2
|
+
import axios from 'axios';
|
|
3
|
+
|
|
4
|
+
const API_CONFIG = {
|
|
5
|
+
BASE_URL: 'http://localhost:3040/api',
|
|
6
|
+
HEADERS: {
|
|
7
|
+
'Content-Type': 'application/json'
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const axiosInstance = axios.create({
|
|
12
|
+
baseURL: API_CONFIG.BASE_URL,
|
|
13
|
+
headers: API_CONFIG.HEADERS
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const apiServices = {
|
|
17
|
+
async post(endpoint: string, data: any) {
|
|
18
|
+
try {
|
|
19
|
+
const response = await axiosInstance.post(endpoint, data);
|
|
20
|
+
return response.data;
|
|
21
|
+
} catch (error) {
|
|
22
|
+
console.error('Network request failed', error);
|
|
23
|
+
throw error;
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
|
|
27
|
+
// Add other HTTP methods if needed
|
|
28
|
+
// async get(endpoint: string) { ... }
|
|
29
|
+
// async put(endpoint: string, data: any) { ... }
|
|
30
|
+
// async delete(endpoint: string) { ... }
|
|
31
|
+
};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ethers } from 'ethers';
|
|
2
|
+
|
|
3
|
+
export function validateType(expectedType: string, value: any): boolean {
|
|
4
|
+
switch (expectedType) {
|
|
5
|
+
case 'bool':
|
|
6
|
+
case 'boolean':
|
|
7
|
+
return typeof value === 'boolean';
|
|
8
|
+
case 'chainId':
|
|
9
|
+
case 'integer':
|
|
10
|
+
return Number.isInteger(value)
|
|
11
|
+
case 'int8': case 'int16': case 'int32': case 'int64': case 'int128': case 'int256':
|
|
12
|
+
return Number.isInteger(value) && isIntInRange(value, parseInt(expectedType.replace('int', '')));
|
|
13
|
+
case 'uint8': case 'uint16': case 'uint32': case 'uint64': case 'uint128': case 'uint256':
|
|
14
|
+
return Number.isInteger(value) && isUintInRange(value, parseInt(expectedType.replace('uint', '')));
|
|
15
|
+
case 'erc20':
|
|
16
|
+
case 'nftCollection':
|
|
17
|
+
case 'address':
|
|
18
|
+
return typeof value === 'string' && isAddress(value);
|
|
19
|
+
case 'float':
|
|
20
|
+
case 'fixed':
|
|
21
|
+
case 'ufixed':
|
|
22
|
+
return typeof value === 'number';
|
|
23
|
+
case 'url':
|
|
24
|
+
return typeof value === 'string' && isValidUrl(value);
|
|
25
|
+
case 'phone_number':
|
|
26
|
+
return typeof value === 'string' && isValidPhoneNumber(value);
|
|
27
|
+
case 'paragraph':
|
|
28
|
+
return typeof value === 'string';
|
|
29
|
+
case 'logic_operator':
|
|
30
|
+
const validOperators = new Set(['<', '>', '<=', '>=', '==', '!=']);
|
|
31
|
+
return typeof value === 'string' && validOperators.has(value);
|
|
32
|
+
case 'any':
|
|
33
|
+
return true;
|
|
34
|
+
default:
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function isIntInRange(value: number, bits: number): boolean {
|
|
40
|
+
const min = -(2 ** (bits - 1));
|
|
41
|
+
const max = (2 ** (bits - 1)) - 1;
|
|
42
|
+
return value >= min && value <= max;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function isUintInRange(value: number, bits: number): boolean {
|
|
46
|
+
const max = (2 ** bits) - 1;
|
|
47
|
+
return value >= 0 && value <= max;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function isAddress(value: string): boolean {
|
|
51
|
+
return ethers.isAddress(value);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function isValidUrl(value: string): boolean {
|
|
55
|
+
try {
|
|
56
|
+
new URL(value);
|
|
57
|
+
return true;
|
|
58
|
+
} catch (_) {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function isValidPhoneNumber(value: string): boolean {
|
|
64
|
+
return /^[\+]?[0-9]{0,3}\W?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/im.test(value);
|
|
65
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { Action, ACTIONS, getToken, CHAINS } from '../src/index';
|
|
3
|
+
|
|
4
|
+
const DEFAULT_ADDRESS = "0x0000000000000000000000000000000000000000";
|
|
5
|
+
|
|
6
|
+
describe('Action Class', () => {
|
|
7
|
+
|
|
8
|
+
it('should create a transfer action without parameters', () => {
|
|
9
|
+
const transferAction = new Action(ACTIONS.TOKENS.ERC20.TRANSFER);
|
|
10
|
+
const params = transferAction.getParameters();
|
|
11
|
+
|
|
12
|
+
expect(params.chainId).to.be.null;
|
|
13
|
+
expect(params['abiParams.value']).to.be.null;
|
|
14
|
+
expect(params['abiParams.to']).to.be.null;
|
|
15
|
+
expect(params.contractAddress).to.be.null;
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should create a transfer action and set parameters correctly', () => {
|
|
19
|
+
const transferAction = new Action(ACTIONS.TOKENS.ERC20.TRANSFER);
|
|
20
|
+
transferAction.setChainId(CHAINS.ETHEREUM);
|
|
21
|
+
transferAction.setParams("value", 1000);
|
|
22
|
+
transferAction.setParams("to", DEFAULT_ADDRESS);
|
|
23
|
+
transferAction.setContractAddress(getToken(CHAINS.ETHEREUM, 'USDC').contractAddress);
|
|
24
|
+
|
|
25
|
+
const params = transferAction.getParameters();
|
|
26
|
+
expect(params.chainId).to.equal(CHAINS.ETHEREUM);
|
|
27
|
+
expect(params['abiParams.value']).to.equal(1000);
|
|
28
|
+
expect(params['abiParams.to']).to.equal(DEFAULT_ADDRESS);
|
|
29
|
+
expect(params.contractAddress).to.equal(getToken(CHAINS.ETHEREUM, 'USDC').contractAddress);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should be able to export an action as json', () => {
|
|
33
|
+
const transferAction = new Action(ACTIONS.TOKENS.ERC20.TRANSFER);
|
|
34
|
+
transferAction.setChainId(CHAINS.ETHEREUM);
|
|
35
|
+
transferAction.setParams("value", 1000);
|
|
36
|
+
transferAction.setParams("to", DEFAULT_ADDRESS);
|
|
37
|
+
transferAction.setContractAddress(getToken(CHAINS.ETHEREUM, 'USDC').contractAddress);
|
|
38
|
+
|
|
39
|
+
const json = transferAction.toJSON();
|
|
40
|
+
expect(json).to.deep.equal({
|
|
41
|
+
id: ACTIONS.TOKENS.ERC20.TRANSFER.id,
|
|
42
|
+
parameters: {
|
|
43
|
+
chainId: CHAINS.ETHEREUM,
|
|
44
|
+
'abiParams.value': 1000,
|
|
45
|
+
'abiParams.to': DEFAULT_ADDRESS,
|
|
46
|
+
contractAddress: getToken(CHAINS.ETHEREUM, 'USDC').contractAddress
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('should create an SMS action and set parameters correctly', () => {
|
|
52
|
+
const smsAction = new Action(ACTIONS.NOTIFICATIONS.SMS);
|
|
53
|
+
smsAction.setParams("phoneNumber", "+1234567890");
|
|
54
|
+
smsAction.setParams("text", "Hello, this is a test message!");
|
|
55
|
+
|
|
56
|
+
const params = smsAction.getParameters();
|
|
57
|
+
expect(params.phoneNumber).to.equal("+1234567890");
|
|
58
|
+
expect(params.text).to.equal("Hello, this is a test message!");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should create a Slack action and set parameters correctly', () => {
|
|
62
|
+
const slackAction = new Action(ACTIONS.NOTIFICATIONS.SLACK);
|
|
63
|
+
slackAction.setParams("webhook", "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX");
|
|
64
|
+
slackAction.setParams("text", "This is a test message!");
|
|
65
|
+
|
|
66
|
+
const params = slackAction.getParameters();
|
|
67
|
+
expect(params.webhook).to.equal("https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX");
|
|
68
|
+
expect(params.text).to.equal("This is a test message!");
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('should throw an error for invalid parameter type', () => {
|
|
72
|
+
const transferAction = new Action(ACTIONS.TOKENS.ERC20.TRANSFER);
|
|
73
|
+
expect(() => transferAction.setParams("value", "invalid")).to.throw('Invalid type for parameter abiParams.value. Expected uint256.');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should throw an error for invalid address', () => {
|
|
77
|
+
const transferAction = new Action(ACTIONS.TOKENS.ERC20.TRANSFER);
|
|
78
|
+
expect(() => transferAction.setParams("to", "invalid_address")).to.throw('Invalid type for parameter abiParams.to. Expected address.');
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('should throw an error for invalid URL', () => {
|
|
82
|
+
const slackAction = new Action(ACTIONS.NOTIFICATIONS.SLACK);
|
|
83
|
+
expect(() => slackAction.setParams("webhook", "invalid_url")).to.throw('Invalid type for parameter webhook. Expected url.');
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('should throw an error for invalid phone number', () => {
|
|
87
|
+
const smsAction = new Action(ACTIONS.NOTIFICATIONS.SMS);
|
|
88
|
+
expect(() => smsAction.setParams("phoneNumber", "invalid_phone_number")).to.throw('Invalid type for parameter phoneNumber. Expected phone_number.');
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { Automation } from '../src/models/Automation.js';
|
|
3
|
+
import { Trigger } from '../src/models/Trigger.js';
|
|
4
|
+
import { Action } from '../src/models/Action.js';
|
|
5
|
+
import { TRIGGERS, ACTIONS, getToken, CHAINS } from '../src/index.js';
|
|
6
|
+
|
|
7
|
+
describe('Automation Class', () => {
|
|
8
|
+
it('should create an automation with a trigger and actions', () => {
|
|
9
|
+
const trigger = new Trigger(TRIGGERS.TOKENS.ERC20.TRANSFER);
|
|
10
|
+
trigger.setChainId(CHAINS.ETHEREUM);
|
|
11
|
+
trigger.setContractAddress(getToken(CHAINS.ETHEREUM, 'USDC').contractAddress);
|
|
12
|
+
trigger.setPosition(0, 0);
|
|
13
|
+
|
|
14
|
+
const action1 = new Action(ACTIONS.TOKENS.ERC20.TRANSFER);
|
|
15
|
+
action1.setChainId(CHAINS.ETHEREUM);
|
|
16
|
+
action1.setParams("value", 1000);
|
|
17
|
+
action1.setParams("to", "0xe1432599B51d9BE1b5A27E2A2FB8e5dF684749C6");
|
|
18
|
+
action1.setContractAddress(getToken(CHAINS.ETHEREUM, 'USDC').contractAddress);
|
|
19
|
+
action1.setPosition(1, 0);
|
|
20
|
+
|
|
21
|
+
const action2 = new Action(ACTIONS.NOTIFICATIONS.SMS);
|
|
22
|
+
action2.setParams("phoneNumber", "+1234567890");
|
|
23
|
+
action2.setParams("text", "This is a test message");
|
|
24
|
+
action2.setPosition(2, 0);
|
|
25
|
+
|
|
26
|
+
const automation = new Automation("Test Automation", [trigger, action1, action2]);
|
|
27
|
+
|
|
28
|
+
const json = automation.toJSON();
|
|
29
|
+
expect(json).to.deep.equal({
|
|
30
|
+
name: "Test Automation",
|
|
31
|
+
nodes: [trigger.toJSON(), action1.toJSON(), action2.toJSON()],
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should set the name of the automation', () => {
|
|
36
|
+
const trigger = new Trigger(TRIGGERS.TOKENS.ERC20.TRANSFER);
|
|
37
|
+
trigger.setChainId(CHAINS.ETHEREUM);
|
|
38
|
+
trigger.setContractAddress(getToken(CHAINS.ETHEREUM, 'USDC').contractAddress);
|
|
39
|
+
trigger.setPosition(0, 0);
|
|
40
|
+
|
|
41
|
+
const automation = new Automation("Initial Name", [trigger]);
|
|
42
|
+
automation.setName("Updated Name");
|
|
43
|
+
|
|
44
|
+
expect(automation.name).to.equal("Updated Name");
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should add a trigger to the automation', () => {
|
|
48
|
+
const initialTrigger = new Trigger(TRIGGERS.TOKENS.ERC20.TRANSFER);
|
|
49
|
+
initialTrigger.setChainId(CHAINS.ETHEREUM);
|
|
50
|
+
initialTrigger.setContractAddress(getToken(CHAINS.ETHEREUM, 'USDC').contractAddress);
|
|
51
|
+
initialTrigger.setPosition(0, 0);
|
|
52
|
+
|
|
53
|
+
const newTrigger = new Trigger(TRIGGERS.TOKENS.ERC20.TRANSFER);
|
|
54
|
+
newTrigger.setChainId(CHAINS.ETHEREUM);
|
|
55
|
+
newTrigger.setContractAddress(getToken(CHAINS.ETHEREUM, 'USDC').contractAddress);
|
|
56
|
+
newTrigger.setPosition(1, 0);
|
|
57
|
+
|
|
58
|
+
const automation = new Automation("Test Automation", [initialTrigger]);
|
|
59
|
+
automation.addNode(newTrigger);
|
|
60
|
+
|
|
61
|
+
expect(automation.nodes).to.deep.equal([initialTrigger, newTrigger]);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should add actions to the automation', () => {
|
|
65
|
+
const trigger = new Trigger(TRIGGERS.TOKENS.ERC20.TRANSFER);
|
|
66
|
+
trigger.setChainId(CHAINS.ETHEREUM);
|
|
67
|
+
trigger.setContractAddress(getToken(CHAINS.ETHEREUM, 'USDC').contractAddress);
|
|
68
|
+
trigger.setPosition(0, 0);
|
|
69
|
+
|
|
70
|
+
const action1 = new Action(ACTIONS.TOKENS.ERC20.TRANSFER);
|
|
71
|
+
action1.setChainId(CHAINS.ETHEREUM);
|
|
72
|
+
action1.setParams("value", 1000);
|
|
73
|
+
action1.setParams("to", "0xe1432599B51d9BE1b5A27E2A2FB8e5dF684749C6");
|
|
74
|
+
action1.setContractAddress(getToken(CHAINS.ETHEREUM, 'USDC').contractAddress);
|
|
75
|
+
action1.setPosition(1, 0);
|
|
76
|
+
|
|
77
|
+
const action2 = new Action(ACTIONS.NOTIFICATIONS.SMS);
|
|
78
|
+
action2.setParams("phoneNumber", "+1234567890");
|
|
79
|
+
action2.setParams("text", "This is a test message");
|
|
80
|
+
action2.setPosition(2, 0);
|
|
81
|
+
|
|
82
|
+
const automation = new Automation("Test Automation", [trigger]);
|
|
83
|
+
automation.addNode(action1);
|
|
84
|
+
automation.addNode(action2);
|
|
85
|
+
|
|
86
|
+
expect(automation.nodes).to.deep.equal([trigger, action1, action2]);
|
|
87
|
+
});
|
|
88
|
+
});
|