From d2d6f48ac910e47cdd120acb3d385d305fca8032 Mon Sep 17 00:00:00 2001 From: JanBajecDev Date: Fri, 11 Oct 2024 15:46:41 +0200 Subject: [PATCH 1/8] Added 2 new strategies for staking that we need for our project --- src/strategies/index.ts | 6 +- .../README.md | 16 +++ .../examples.json | 21 ++++ .../index.ts | 103 ++++++++++++++++++ .../schema.json | 40 +++++++ .../staking-amount-duration-linear/README.md | 15 +++ .../examples.json | 20 ++++ .../staking-amount-duration-linear/index.ts | 102 +++++++++++++++++ .../schema.json | 34 ++++++ 9 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 src/strategies/staking-amount-duration-exponential/README.md create mode 100644 src/strategies/staking-amount-duration-exponential/examples.json create mode 100644 src/strategies/staking-amount-duration-exponential/index.ts create mode 100644 src/strategies/staking-amount-duration-exponential/schema.json create mode 100644 src/strategies/staking-amount-duration-linear/README.md create mode 100644 src/strategies/staking-amount-duration-linear/examples.json create mode 100644 src/strategies/staking-amount-duration-linear/index.ts create mode 100644 src/strategies/staking-amount-duration-linear/schema.json diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 50dc61925..e52889c76 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -456,6 +456,8 @@ import * as pom from './pom'; import * as superboring from './superboring'; import * as erableGovernanceV1 from './erable-governance-v1'; import * as snxMultichain from './snx-multichain'; +import * as stakingAmountDurationLinear from './staking-amount-duration-linear'; +import * as stakingAmountDurationExponential from './staking-amount-duration-exponential'; const strategies = { 'delegatexyz-erc721-balance-of': delegatexyzErc721BalanceOf, @@ -922,7 +924,9 @@ const strategies = { pom, superboring, 'erable-governance-v1': erableGovernanceV1, - 'snx-multichain': snxMultichain + 'snx-multichain': snxMultichain, + 'staking-amount-duration-linear': stakingAmountDurationLinear, + 'staking-amount-duration-exponential': stakingAmountDurationExponential }; Object.keys(strategies).forEach(function (strategyName) { diff --git a/src/strategies/staking-amount-duration-exponential/README.md b/src/strategies/staking-amount-duration-exponential/README.md new file mode 100644 index 000000000..e029c1d7e --- /dev/null +++ b/src/strategies/staking-amount-duration-exponential/README.md @@ -0,0 +1,16 @@ +# staking-amount-duration-exponential + +This is a strategy for calculating voting power with this formula + +Voting Power = Stake Amount × (1 + r) ^ Stake Duration + +Here is an example of parameters: + +```json +{ + "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "symbol": "DAI", + "decimals": 18, + "rate": 0.1 +} +``` diff --git a/src/strategies/staking-amount-duration-exponential/examples.json b/src/strategies/staking-amount-duration-exponential/examples.json new file mode 100644 index 000000000..b683fdab2 --- /dev/null +++ b/src/strategies/staking-amount-duration-exponential/examples.json @@ -0,0 +1,21 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "staking-amount-duration-exponential", + "params": { + "address": "0x520BDBFCe65CECa0813e51D724804BC7Fd6107dd", + "symbol": "STAKE", + "decimals": 18, + "rate": 0.1 + } + }, + "network": "11155111", + "addresses": [ + "0x57bABaf9E18587C2C1E97244729847604789fC81", + "0xc62BD6B53f46883038b5f018aE74155f07b0e6Db", + "0x6CcE789f04A3f0c291E97042765E07bccC6D73B3" + ], + "snapshot": 6856587 + } +] diff --git a/src/strategies/staking-amount-duration-exponential/index.ts b/src/strategies/staking-amount-duration-exponential/index.ts new file mode 100644 index 000000000..53142857b --- /dev/null +++ b/src/strategies/staking-amount-duration-exponential/index.ts @@ -0,0 +1,103 @@ +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'defactor'; +export const version = '0.1.1'; + +const abi = [ + { + inputs: [ + { + internalType: 'address', + name: 'user', + type: 'address' + } + ], + name: 'getUserStakes', + outputs: [ + { + components: [ + { + internalType: 'uint256', + name: 'amount', + type: 'uint256' + }, + { + internalType: 'uint256', + name: 'claimed', + type: 'uint256' + }, + { + internalType: 'uint48', + name: 'stakeTime', + type: 'uint48' + }, + { + internalType: 'uint8', + name: 'planId', + type: 'uint8' + }, + { + internalType: 'bool', + name: 'unstaked', + type: 'bool' + } + ], + internalType: 'struct IStaking.Stake[]', + name: '', + type: 'tuple[]' + } + ], + stateMutability: 'view', + type: 'function' + } +]; +const secondsInAMonth = 30.44 * 24 * 60 * 60; + +interface Stake { + amount: bigint; + claimed: bigint; + stakeTime: bigint; + planId: bigint; + unstaked: boolean; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const snapshotBlock = await provider.getBlock(blockTag); + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'getUserStakes', [address]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, stakes]) => { + let power = 0; + stakes.forEach((stake) => { + if (!stake.unstaked) { + if (snapshotBlock.timestamp > stake.stakeTime) { + const duration = + Number(snapshotBlock.timestamp - stake.stakeTime) / + secondsInAMonth; + const durationRateCalculated = Math.pow(1 + options.rate, duration); + power += + parseFloat(formatUnits(stake.amount, options.decimals)) * + durationRateCalculated; + } + } + }); + + return [address, power]; + }) + ); +} diff --git a/src/strategies/staking-amount-duration-exponential/schema.json b/src/strategies/staking-amount-duration-exponential/schema.json new file mode 100644 index 000000000..2535aefd5 --- /dev/null +++ b/src/strategies/staking-amount-duration-exponential/schema.json @@ -0,0 +1,40 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + }, + "rate": { + "type": "number", + "title": "Rate (Voting Power = Stake Amount × (1 + rate) ^ Stake Duration)", + "examples": ["e.g. 0.1"], + "minimum": 0 + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} diff --git a/src/strategies/staking-amount-duration-linear/README.md b/src/strategies/staking-amount-duration-linear/README.md new file mode 100644 index 000000000..5fecd3185 --- /dev/null +++ b/src/strategies/staking-amount-duration-linear/README.md @@ -0,0 +1,15 @@ +# staking-amount-duration-linear + +This is a strategy for calculating voting power with this formula + +Voting Power = Stake Amount × Stake Duration (in time units) + +Here is an example of parameters: + +```json +{ + "address": "0x6b175474e89094c44da98b954eedeac495271d0f", + "symbol": "DAI", + "decimals": 18 +} +``` diff --git a/src/strategies/staking-amount-duration-linear/examples.json b/src/strategies/staking-amount-duration-linear/examples.json new file mode 100644 index 000000000..e008d340b --- /dev/null +++ b/src/strategies/staking-amount-duration-linear/examples.json @@ -0,0 +1,20 @@ +[ + { + "name": "Example query", + "strategy": { + "name": "staking-amount-duration-linear", + "params": { + "address": "0x520BDBFCe65CECa0813e51D724804BC7Fd6107dd", + "symbol": "STAKE", + "decimals": 18 + } + }, + "network": "11155111", + "addresses": [ + "0x57bABaf9E18587C2C1E97244729847604789fC81", + "0xc62BD6B53f46883038b5f018aE74155f07b0e6Db", + "0x6CcE789f04A3f0c291E97042765E07bccC6D73B3" + ], + "snapshot": 6856587 + } +] diff --git a/src/strategies/staking-amount-duration-linear/index.ts b/src/strategies/staking-amount-duration-linear/index.ts new file mode 100644 index 000000000..81d729b3e --- /dev/null +++ b/src/strategies/staking-amount-duration-linear/index.ts @@ -0,0 +1,102 @@ +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'defactor'; +export const version = '0.1.1'; + +const abi = [ + { + inputs: [ + { + internalType: 'address', + name: 'user', + type: 'address' + } + ], + name: 'getUserStakes', + outputs: [ + { + components: [ + { + internalType: 'uint256', + name: 'amount', + type: 'uint256' + }, + { + internalType: 'uint256', + name: 'claimed', + type: 'uint256' + }, + { + internalType: 'uint48', + name: 'stakeTime', + type: 'uint48' + }, + { + internalType: 'uint8', + name: 'planId', + type: 'uint8' + }, + { + internalType: 'bool', + name: 'unstaked', + type: 'bool' + } + ], + internalType: 'struct IStaking.Stake[]', + name: '', + type: 'tuple[]' + } + ], + stateMutability: 'view', + type: 'function' + } +]; +const secondsInAMonth = 30.44 * 24 * 60 * 60; + +interface Stake { + amount: bigint; + claimed: bigint; + stakeTime: bigint; + planId: bigint; + unstaked: boolean; +} + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const snapshotBlock = await provider.getBlock(blockTag); + + const multi = new Multicaller(network, provider, abi, { blockTag }); + addresses.forEach((address) => + multi.call(address, options.address, 'getUserStakes', [address]) + ); + const result: Record = await multi.execute(); + + return Object.fromEntries( + Object.entries(result).map(([address, stakes]) => { + let power = 0; + stakes.forEach((stake) => { + if (!stake.unstaked) { + if (snapshotBlock.timestamp > stake.stakeTime) { + const duration = + Number(snapshotBlock.timestamp - stake.stakeTime) / + secondsInAMonth; + power += + parseFloat(formatUnits(stake.amount, options.decimals)) * + duration; + } + } + }); + + return [address, power]; + }) + ); +} diff --git a/src/strategies/staking-amount-duration-linear/schema.json b/src/strategies/staking-amount-duration-linear/schema.json new file mode 100644 index 000000000..0d5455492 --- /dev/null +++ b/src/strategies/staking-amount-duration-linear/schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$ref": "#/definitions/Strategy", + "definitions": { + "Strategy": { + "title": "Strategy", + "type": "object", + "properties": { + "symbol": { + "type": "string", + "title": "Symbol", + "examples": ["e.g. UNI"], + "maxLength": 16 + }, + "address": { + "type": "string", + "title": "Contract address", + "examples": ["e.g. 0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984"], + "pattern": "^0x[a-fA-F0-9]{40}$", + "minLength": 42, + "maxLength": 42 + }, + "decimals": { + "type": "number", + "title": "Decimals", + "examples": ["e.g. 18"], + "minimum": 0 + } + }, + "required": ["address", "decimals"], + "additionalProperties": false + } + } +} From fa95c358d5c91a3b46a1292acd98b070fd66cab2 Mon Sep 17 00:00:00 2001 From: JanBajecDev <139755528+JanBajecDev@users.noreply.github.com> Date: Mon, 14 Oct 2024 09:09:43 +0200 Subject: [PATCH 2/8] Update src/strategies/staking-amount-duration-exponential/index.ts Co-authored-by: Chaitanya --- src/strategies/staking-amount-duration-exponential/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/staking-amount-duration-exponential/index.ts b/src/strategies/staking-amount-duration-exponential/index.ts index 53142857b..a5e2cb445 100644 --- a/src/strategies/staking-amount-duration-exponential/index.ts +++ b/src/strategies/staking-amount-duration-exponential/index.ts @@ -1,7 +1,7 @@ import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; -export const author = 'defactor'; +export const author = 'JanBajecDev'; export const version = '0.1.1'; const abi = [ From 3c25dca0ef4902b54270eabd733c96da2081f05e Mon Sep 17 00:00:00 2001 From: JanBajecDev <139755528+JanBajecDev@users.noreply.github.com> Date: Mon, 14 Oct 2024 09:09:50 +0200 Subject: [PATCH 3/8] Update src/strategies/staking-amount-duration-exponential/index.ts Co-authored-by: Chaitanya --- src/strategies/staking-amount-duration-exponential/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/staking-amount-duration-exponential/index.ts b/src/strategies/staking-amount-duration-exponential/index.ts index a5e2cb445..c2cce1304 100644 --- a/src/strategies/staking-amount-duration-exponential/index.ts +++ b/src/strategies/staking-amount-duration-exponential/index.ts @@ -2,7 +2,7 @@ import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; export const author = 'JanBajecDev'; -export const version = '0.1.1'; +export const version = '0.1.0'; const abi = [ { From 4af373a1736d2c5a3b4107e373e7a5b65937314d Mon Sep 17 00:00:00 2001 From: JanBajecDev <139755528+JanBajecDev@users.noreply.github.com> Date: Mon, 14 Oct 2024 09:10:03 +0200 Subject: [PATCH 4/8] Update src/strategies/staking-amount-duration-exponential/index.ts Co-authored-by: Chaitanya --- .../index.ts | 47 +------------------ 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/src/strategies/staking-amount-duration-exponential/index.ts b/src/strategies/staking-amount-duration-exponential/index.ts index c2cce1304..9f0c7d4d8 100644 --- a/src/strategies/staking-amount-duration-exponential/index.ts +++ b/src/strategies/staking-amount-duration-exponential/index.ts @@ -5,52 +5,7 @@ export const author = 'JanBajecDev'; export const version = '0.1.0'; const abi = [ - { - inputs: [ - { - internalType: 'address', - name: 'user', - type: 'address' - } - ], - name: 'getUserStakes', - outputs: [ - { - components: [ - { - internalType: 'uint256', - name: 'amount', - type: 'uint256' - }, - { - internalType: 'uint256', - name: 'claimed', - type: 'uint256' - }, - { - internalType: 'uint48', - name: 'stakeTime', - type: 'uint48' - }, - { - internalType: 'uint8', - name: 'planId', - type: 'uint8' - }, - { - internalType: 'bool', - name: 'unstaked', - type: 'bool' - } - ], - internalType: 'struct IStaking.Stake[]', - name: '', - type: 'tuple[]' - } - ], - stateMutability: 'view', - type: 'function' - } + 'function getUserStakes(address user) view returns (tuple(uint256 amount, uint256 claimed, uint48 stakeTime, uint8 planId, bool unstaked)[])' ]; const secondsInAMonth = 30.44 * 24 * 60 * 60; From 41dc219845c699d71b62d7eabcaa42a955f93617 Mon Sep 17 00:00:00 2001 From: JanBajecDev <139755528+JanBajecDev@users.noreply.github.com> Date: Mon, 14 Oct 2024 09:10:09 +0200 Subject: [PATCH 5/8] Update src/strategies/staking-amount-duration-linear/index.ts Co-authored-by: Chaitanya --- src/strategies/staking-amount-duration-linear/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/staking-amount-duration-linear/index.ts b/src/strategies/staking-amount-duration-linear/index.ts index 81d729b3e..fda6a5ce2 100644 --- a/src/strategies/staking-amount-duration-linear/index.ts +++ b/src/strategies/staking-amount-duration-linear/index.ts @@ -2,7 +2,7 @@ import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; export const author = 'defactor'; -export const version = '0.1.1'; +export const version = '0.1.0'; const abi = [ { From 06dc93b36c85036db15b0781bd536e85c3e42f0b Mon Sep 17 00:00:00 2001 From: JanBajecDev <139755528+JanBajecDev@users.noreply.github.com> Date: Mon, 14 Oct 2024 09:10:16 +0200 Subject: [PATCH 6/8] Update src/strategies/staking-amount-duration-linear/index.ts Co-authored-by: Chaitanya --- src/strategies/staking-amount-duration-linear/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/strategies/staking-amount-duration-linear/index.ts b/src/strategies/staking-amount-duration-linear/index.ts index fda6a5ce2..426646a9b 100644 --- a/src/strategies/staking-amount-duration-linear/index.ts +++ b/src/strategies/staking-amount-duration-linear/index.ts @@ -1,7 +1,7 @@ import { formatUnits } from '@ethersproject/units'; import { Multicaller } from '../../utils'; -export const author = 'defactor'; +export const author = 'JanBajecDev'; export const version = '0.1.0'; const abi = [ From 23f2013a44bb560afe8b1cd640cbe0ad690186e5 Mon Sep 17 00:00:00 2001 From: JanBajecDev <139755528+JanBajecDev@users.noreply.github.com> Date: Mon, 14 Oct 2024 09:10:24 +0200 Subject: [PATCH 7/8] Update src/strategies/staking-amount-duration-linear/index.ts Co-authored-by: Chaitanya --- .../staking-amount-duration-linear/index.ts | 47 +------------------ 1 file changed, 1 insertion(+), 46 deletions(-) diff --git a/src/strategies/staking-amount-duration-linear/index.ts b/src/strategies/staking-amount-duration-linear/index.ts index 426646a9b..7e97ba72c 100644 --- a/src/strategies/staking-amount-duration-linear/index.ts +++ b/src/strategies/staking-amount-duration-linear/index.ts @@ -5,52 +5,7 @@ export const author = 'JanBajecDev'; export const version = '0.1.0'; const abi = [ - { - inputs: [ - { - internalType: 'address', - name: 'user', - type: 'address' - } - ], - name: 'getUserStakes', - outputs: [ - { - components: [ - { - internalType: 'uint256', - name: 'amount', - type: 'uint256' - }, - { - internalType: 'uint256', - name: 'claimed', - type: 'uint256' - }, - { - internalType: 'uint48', - name: 'stakeTime', - type: 'uint48' - }, - { - internalType: 'uint8', - name: 'planId', - type: 'uint8' - }, - { - internalType: 'bool', - name: 'unstaked', - type: 'bool' - } - ], - internalType: 'struct IStaking.Stake[]', - name: '', - type: 'tuple[]' - } - ], - stateMutability: 'view', - type: 'function' - } + 'function getUserStakes(address user) view returns (tuple(uint256 amount, uint256 claimed, uint48 stakeTime, uint8 planId, bool unstaked)[])' ]; const secondsInAMonth = 30.44 * 24 * 60 * 60; From 4dc42553ff0e672dd4669ff2f24af3aa92a1c0c1 Mon Sep 17 00:00:00 2001 From: Chaitanya Date: Mon, 14 Oct 2024 15:40:08 +0530 Subject: [PATCH 8/8] Update src/strategies/index.ts --- src/strategies/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3b159688a..0de78ef13 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -925,10 +925,10 @@ const strategies = { pom, superboring, 'erable-governance-v1': erableGovernanceV1, + 'world-liberty-financial-erc20-balance-of-votes': worldLibertyFinancial, 'snx-multichain': snxMultichain, 'staking-amount-duration-linear': stakingAmountDurationLinear, - 'staking-amount-duration-exponential': stakingAmountDurationExponential, - 'world-liberty-financial-erc20-balance-of-votes': worldLibertyFinancial + 'staking-amount-duration-exponential': stakingAmountDurationExponential }; Object.keys(strategies).forEach(function (strategyName) {