This commit is contained in:
Georges KABBOUCHI 2021-08-24 02:07:53 +03:00
parent 60e1cfb5ca
commit b1b221876c
7 changed files with 146 additions and 49 deletions

View File

@ -212,6 +212,7 @@ async function getBalances(
} }
const { name, symbol, decimals, type, isStableCoin, key } = tokenData; const { name, symbol, decimals, type, isStableCoin, key } = tokenData;
tokensBalObj[tokenAddress] = { tokensBalObj[tokenAddress] = {
address: tokenAddress,
name, name,
symbol, symbol,
decimals, decimals,

View File

@ -18,13 +18,13 @@ export function useStrategy(defineStrategy: DefineStrategy) {
} = useNotification(); } = useNotification();
const strategy = buildStrategy(defineStrategy); const strategy = buildStrategy(defineStrategy);
const inputs = ref(strategy.getInputs()); const inputs = ref(strategy.inputs);
const error = ref(""); const error = ref("");
strategy.onUpdated(async () => { strategy.onUpdated(async () => {
await nextTick(); await nextTick();
inputs.value = strategy.getInputs(); inputs.value = strategy.inputs;
console.log("onUpdated"); console.log("onUpdated");
}); });

View File

@ -6,8 +6,8 @@ export interface IStrategyContext {
dsa: DSA; dsa: DSA;
web3: Web3; web3: Web3;
inputs: IStrategyInput<StrategyInputType>[]; inputs: IStrategyInput<StrategyInputType>[];
dsaTokens?: IStrategyToken, dsaTokens?: { [address: string]: IStrategyToken };
userTokens?: IStrategyToken, userTokens?: { [address: string]: IStrategyToken };
} }
export interface IStrategyToken { export interface IStrategyToken {
@ -46,6 +46,9 @@ export interface IStrategyInput<InputType extends StrategyInputType> {
input: IStrategyInput<InputType> & StrategyInputParameterMap[InputType]; input: IStrategyInput<InputType> & StrategyInputParameterMap[InputType];
} }
) => string | void; ) => string | void;
defaults?: (context: Omit<IStrategyContext, 'inputs'>) => object;
value?: any; value?: any;
[key: string]: any; [key: string]: any;
@ -78,7 +81,7 @@ export function defineStrategy(strategy: IStrategy) {
} }
export function buildStrategy(schema: DefineStrategy) { export function buildStrategy(schema: DefineStrategy) {
return new Strategy(schema) return new Strategy(schema);
} }
export type DefineStrategy = ReturnType<typeof defineStrategy>; export type DefineStrategy = ReturnType<typeof defineStrategy>;

View File

@ -21,64 +21,94 @@ export class Strategy {
constructor(schema: DefineStrategy) { constructor(schema: DefineStrategy) {
this.schema = schema; this.schema = schema;
this.inputs = this.schema.inputs; this.inputs = this.generateInputs(this.schema.inputs);
}
getBaseContext(): Omit<IStrategyContext, "inputs"> {
return {
...this.context,
...this.props
};
} }
getContext(): IStrategyContext { getContext(): IStrategyContext {
return { return {
...this.context, ...this.context,
...this.props, ...this.props,
inputs: this.getInputs() inputs: this.inputs
}; };
} }
setProps(props: object) { setProps(props: object) {
Object.assign(this.props, props); Object.assign(this.props, props);
this.notifyListeners() const inputs = this.inputs;
for (const input of inputs) {
if (typeof input.defaults !== "function") {
continue;
}
Object.assign(input, input.defaults(this.getBaseContext()));
}
this.notifyListeners();
} }
getInputs() { generateInputs(inputs) {
return this.inputs.map(input => ({ return inputs.map((input, idx) => {
...input, const computedInput = {
value: input.value || "", ...input,
error: input.error || "", value: input.value || "",
placeholder: () => error: input.error || "",
input.placeholder placeholder: () => {
? input.placeholder({ console.log({
...this.context,
inputs: this.inputs,
input: {
token: {
// todo
},
...input
}
})
: null,
onInput: (val: any) => {
input.error = "";
input.value = val;
if (val) {
input.error = input.validate({
...this.getContext(), ...this.getContext(),
input input: this.inputs[idx]
}); });
return input.placeholder
? input.placeholder({
...this.getContext(),
input: this.inputs[idx]
})
: null;
},
onInput: (val: any) => {
this.inputs[idx].error = "";
this.inputs[idx].value = val;
if (val) {
this.inputs[idx].error = this.inputs[idx].validate({
...this.getContext(),
input: this.inputs[idx]
});
}
this.notifyListeners();
},
onCustomInput: (values: object) => {
this.inputs[idx] = Object.assign(this.inputs[idx], values);
this.inputs[idx].error = this.inputs[idx].validate({
...this.getContext(),
input: this.inputs[idx]
});
this.notifyListeners();
} }
};
this.notifyListeners(); let defaults = {};
},
onCustomInput: (values: object) => {
input = Object.assign(input, values);
input.error = input.validate({ if (input.defaults) {
...this.getContext(), defaults = input.defaults(this.getBaseContext());
input
});
this.notifyListeners();
} }
}));
return {
...computedInput,
...defaults
};
});
} }
async submit(options) { async submit(options) {
@ -100,7 +130,7 @@ export class Strategy {
} }
async validate() { async validate() {
const inputs = this.getInputs(); const inputs = this.inputs;
for (const input of inputs) { for (const input of inputs) {
if (typeof input.validate !== "function") { if (typeof input.validate !== "function") {
@ -120,10 +150,14 @@ export class Strategy {
setWeb3(web3: Web3) { setWeb3(web3: Web3) {
this.context.web3 = web3; this.context.web3 = web3;
this.notifyListeners();
} }
setDSA(dsa: DSA) { setDSA(dsa: DSA) {
this.context.dsa = dsa; this.context.dsa = dsa;
this.notifyListeners();
} }
async notifyListeners() { async notifyListeners() {

View File

@ -10,7 +10,7 @@ export default defineStrategy({
defineInput({ defineInput({
type: StrategyInputType.INPUT_WITH_TOKEN, type: StrategyInputType.INPUT_WITH_TOKEN,
name: "Debt", name: "Debt",
placeholder: ({ input }) => `${input.token.symbol} to Payback`, placeholder: ({ input }) => `${input.token?.symbol} to Payback`,
validate: ({ input }) => { validate: ({ input }) => {
if (!input.token) { if (!input.token) {
return "Token is required"; return "Token is required";
@ -20,13 +20,23 @@ export default defineStrategy({
return "Your amount exceeds your maximum limit."; return "Your amount exceeds your maximum limit.";
} }
}, },
token: tokens.mainnet.getTokenByKey("eth") defaults: context => {
return {
token: context.dsaTokens
? Object.values(context.dsaTokens).find(t => t.key === "eth")
: null
};
}
}), }),
defineInput({ defineInput({
type: StrategyInputType.INPUT_WITH_TOKEN, type: StrategyInputType.INPUT_WITH_TOKEN,
name: "Collateral", name: "Collateral",
placeholder: ({ input }) => `${input.token.symbol} to Withdraw`, placeholder: ({ input }) => `${input.token?.symbol} to Withdraw`,
token: tokens.mainnet.getTokenByKey("dai") defaults: ({ dsaTokens }) => ({
token: dsaTokens
? Object.values(dsaTokens).find(t => t.key === "dai")
: null
})
}) })
], ],

View File

@ -1,6 +1,8 @@
import depositAndBorrow from "./deposit-and-borrow" import depositAndBorrow from "./deposit-and-borrow"
import paybackAndWithdraw from "./payback-and-withdraw"
export default [ export default [
depositAndBorrow depositAndBorrow,
paybackAndWithdraw,
] ]

View File

@ -0,0 +1,47 @@
import tokens from "~/constant/tokens";
import { defineStrategy, defineInput, StrategyInputType } from "../../helpers";
export default defineStrategy({
name: "Payback & Withdraw",
description: "Payback debt & withdraw collateral in a single txn.",
author: "Instadapp Team",
inputs: [
defineInput({
type: StrategyInputType.INPUT_WITH_TOKEN,
name: "Debt",
placeholder: ({ input }) => `${input.token.symbol} to Payback`,
validate: ({ input }) => {
if (!input.token) {
return "Token is required";
}
if (input.token.balance < input.value) {
return "Your amount exceeds your maximum limit.";
}
},
token: tokens.mainnet.getTokenByKey("eth")
}),
defineInput({
type: StrategyInputType.INPUT_WITH_TOKEN,
name: "Collateral",
placeholder: ({ input }) => `${input.token.symbol} to Withdraw`,
token: tokens.mainnet.getTokenByKey("dai")
})
],
spells: async ({ inputs }) => {
return [
{
connector: "aave_v2",
method: "payback",
args: [inputs[0].token.address, inputs[0].value, 1, 0, 0]
},
{
connector: "aave_v2",
method: "withdraw",
args: [inputs[1].token.address, inputs[1].value, 0, 0]
}
];
}
});