2021-08-22 15:45:37 +00:00
|
|
|
import DSA, { Spell } from "dsa-connect";
|
2021-08-22 11:27:02 +00:00
|
|
|
import Web3 from "web3";
|
2021-08-22 13:49:31 +00:00
|
|
|
import slugify from "slugify";
|
2021-08-22 11:27:02 +00:00
|
|
|
export interface IStrategyContext {
|
2021-08-22 15:45:37 +00:00
|
|
|
dsa: DSA;
|
2021-08-22 11:27:02 +00:00
|
|
|
web3: Web3;
|
2021-08-22 15:45:37 +00:00
|
|
|
inputs: IStrategyInput<StrategyInputType>[];
|
2021-08-22 11:27:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface IStrategyToken {
|
2021-08-22 13:49:31 +00:00
|
|
|
address: string;
|
|
|
|
key: string;
|
|
|
|
symbol: string;
|
|
|
|
balance: string;
|
2021-08-22 11:27:02 +00:00
|
|
|
|
2021-08-22 13:49:31 +00:00
|
|
|
supply: string;
|
|
|
|
borrow: string;
|
2021-08-22 11:27:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export enum StrategyInputType {
|
|
|
|
INPUT = "input",
|
|
|
|
INPUT_WITH_TOKEN = "input-with-token"
|
|
|
|
}
|
|
|
|
|
2021-08-22 15:45:37 +00:00
|
|
|
export type StrategyInputParameterMap = {
|
|
|
|
[StrategyInputType.INPUT]: {};
|
2021-08-22 12:54:23 +00:00
|
|
|
|
2021-08-22 15:45:37 +00:00
|
|
|
[StrategyInputType.INPUT_WITH_TOKEN]: {
|
|
|
|
token?: IStrategyToken;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
export interface IStrategyInput<InputType extends StrategyInputType> {
|
|
|
|
type: InputType;
|
2021-08-22 11:27:02 +00:00
|
|
|
name: string;
|
2021-08-22 15:45:37 +00:00
|
|
|
placeholder: (
|
|
|
|
context: IStrategyContext & {
|
|
|
|
input: IStrategyInput<InputType> & StrategyInputParameterMap[InputType];
|
|
|
|
}
|
|
|
|
) => string;
|
2021-08-22 13:49:31 +00:00
|
|
|
validate?: (
|
2021-08-22 15:45:37 +00:00
|
|
|
context: IStrategyContext & {
|
|
|
|
input: IStrategyInput<InputType> & StrategyInputParameterMap[InputType];
|
|
|
|
}
|
|
|
|
) => string | void;
|
2021-08-22 11:27:02 +00:00
|
|
|
value?: any;
|
2021-08-22 12:54:23 +00:00
|
|
|
|
|
|
|
[key: string]: any;
|
2021-08-22 11:27:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface IStrategy {
|
2021-08-22 12:54:23 +00:00
|
|
|
id?: string;
|
2021-08-22 11:27:02 +00:00
|
|
|
name: string;
|
|
|
|
description: string;
|
|
|
|
author?: string;
|
|
|
|
|
2021-08-22 15:45:37 +00:00
|
|
|
inputs: IStrategyInput<any>[];
|
2021-08-22 11:27:02 +00:00
|
|
|
|
2021-08-22 15:45:37 +00:00
|
|
|
spells: (context: IStrategyContext) => Promise<Spell[]> | Spell[];
|
2021-08-22 12:54:23 +00:00
|
|
|
|
|
|
|
submitText?: string;
|
2021-08-22 11:27:02 +00:00
|
|
|
}
|
|
|
|
|
2021-08-22 15:45:37 +00:00
|
|
|
export function defineInput<InputType extends StrategyInputType>(
|
|
|
|
input: IStrategyInput<InputType>
|
|
|
|
) {
|
|
|
|
return input as IStrategyInput<any>;
|
|
|
|
}
|
|
|
|
|
2021-08-22 13:49:31 +00:00
|
|
|
export function defineStrategy(strategy: IStrategy) {
|
2021-08-22 15:45:37 +00:00
|
|
|
const context = {
|
|
|
|
web3: null,
|
|
|
|
dsa: null
|
|
|
|
};
|
|
|
|
|
2021-08-22 13:49:31 +00:00
|
|
|
return {
|
|
|
|
...strategy,
|
2021-08-22 15:45:37 +00:00
|
|
|
id: strategy.id ? strategy.id : slugify(strategy.name).toLowerCase(),
|
2021-08-22 13:49:31 +00:00
|
|
|
inputs: strategy.inputs.map(input => ({
|
|
|
|
...input,
|
|
|
|
value: null,
|
2021-08-22 15:45:37 +00:00
|
|
|
placeholder: () =>
|
|
|
|
input.placeholder
|
|
|
|
? input.placeholder({
|
|
|
|
...context,
|
|
|
|
inputs: strategy.inputs,
|
|
|
|
input: {
|
|
|
|
...input,
|
|
|
|
token: {
|
|
|
|
// todo
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
: null,
|
2021-08-22 13:49:31 +00:00
|
|
|
onInput: (val: any) => {
|
|
|
|
input.value = val;
|
|
|
|
}
|
|
|
|
})),
|
2021-08-22 15:45:37 +00:00
|
|
|
submit: async () => {
|
2021-08-22 13:49:31 +00:00
|
|
|
await this.validate({
|
|
|
|
...context,
|
|
|
|
inputs: strategy.inputs
|
|
|
|
});
|
2021-08-22 12:54:23 +00:00
|
|
|
|
2021-08-22 15:45:37 +00:00
|
|
|
const allSpells = await strategy.spells({
|
2021-08-22 13:49:31 +00:00
|
|
|
...context,
|
|
|
|
inputs: strategy.inputs
|
|
|
|
});
|
2021-08-22 12:54:23 +00:00
|
|
|
|
2021-08-22 15:45:37 +00:00
|
|
|
const spells = context.dsa.Spell();
|
|
|
|
|
|
|
|
for (const spell of allSpells) {
|
|
|
|
spells.add(spell);
|
|
|
|
}
|
|
|
|
|
2021-08-22 13:49:31 +00:00
|
|
|
return await context.dsa.cast({
|
|
|
|
spells,
|
|
|
|
onReceipt: this.onReceipt
|
|
|
|
});
|
|
|
|
},
|
2021-08-22 15:45:37 +00:00
|
|
|
validate: async () => {
|
2021-08-22 13:49:31 +00:00
|
|
|
for (const input of this.inputs) {
|
|
|
|
const result = await input.validate({
|
|
|
|
...context,
|
|
|
|
inputs: strategy.inputs,
|
|
|
|
input
|
|
|
|
});
|
|
|
|
|
|
|
|
if (result !== true) {
|
|
|
|
throw new Error(result || "Error has occurred");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onReceipt: (txHash: string, txReceipt: any) => {
|
|
|
|
// do something
|
|
|
|
}
|
|
|
|
};
|
2021-08-22 11:27:02 +00:00
|
|
|
}
|
2021-08-22 13:49:31 +00:00
|
|
|
|
|
|
|
export type DefineStrategy = ReturnType<typeof defineStrategy>;
|