Skip to content
This repository was archived by the owner on Aug 22, 2025. It is now read-only.

Commit 6dee9e7

Browse files
authored
Merge branch 'master' into feat-erc20-balance-starknet-strategy
2 parents 0efdfd0 + 906a08d commit 6dee9e7

54 files changed

Lines changed: 2179 additions & 129 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/build.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ name: Build CI
33
on: [push, pull_request]
44

55
jobs:
6-
build_lint:
6+
build:
77
runs-on: ubuntu-latest
88

99
strategy:
@@ -16,7 +16,7 @@ jobs:
1616
uses: actions/setup-node@v1
1717
with:
1818
node-version: ${{ matrix.node-version }}
19-
- name: yarn install, build and lint
19+
- name: yarn install and build
2020
run: |
2121
yarn install --frozen-lockfile
2222
yarn build

.github/workflows/lint.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: Lint
22

3-
on: [push]
3+
on: [push, pull_request]
44

55
jobs:
66
lint:

.github/workflows/test.yml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: Tests CI
2+
3+
on: [push]
4+
5+
jobs:
6+
tests:
7+
runs-on: ubuntu-latest
8+
9+
strategy:
10+
matrix:
11+
node-version: ['16', '20']
12+
13+
steps:
14+
- uses: actions/checkout@v3
15+
- name: Use Node.js ${{ matrix.node-version }}
16+
uses: actions/setup-node@v3
17+
with:
18+
node-version: ${{ matrix.node-version }}
19+
- name: yarn install, build and run tests
20+
run: |
21+
yarn install --frozen-lockfile
22+
yarn build
23+
yarn test --coverage
24+
- name: Upload coverage reports to Codecov
25+
uses: codecov/codecov-action@v3
26+
with:
27+
token: ${{ secrets.CODECOV_TOKEN }}

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
.DS_Store
22
node_modules
33
dist
4+
coverage
45

56
# Remove some common IDE working directories
67
.idea
78
.vscode
89
.env
9-
.history
10+
.history

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"name": "@snapshot-labs/strategies",
33
"version": "0.1.0",
44
"main": "dist/index.js",
5-
"types": "dist/index.d.ts",
65
"exports": {
76
".": "./dist/index.js"
87
},
@@ -13,10 +12,12 @@
1312
"license": "MIT",
1413
"scripts": {
1514
"build": "tsc -p .",
16-
"test": "jest -i strategy.test.ts",
15+
"test": "yarn test:unit && jest -i strategy.test.ts",
1716
"test:vp": "jest -i vp.test.ts",
1817
"test:delegation": "jest -i delegation.test.ts",
1918
"test:validation": "jest -i validation.test.ts",
19+
"test:integration": "jest -i test/integration/",
20+
"test:unit": "jest -i test/unit/",
2021
"prepublishOnly": "npm run build",
2122
"postinstall": "npm run build",
2223
"postbuild": "copyfiles -u 1 \"src/**/*.md\" dist/ && copyfiles -u 1 \"src/**/*.json\" dist/",
@@ -36,7 +37,7 @@
3637
"@ethersproject/strings": "^5.6.1",
3738
"@ethersproject/units": "^5.6.1",
3839
"@ethersproject/wallet": "^5.6.2",
39-
"@snapshot-labs/snapshot.js": "^0.12.62",
40+
"@snapshot-labs/snapshot.js": "^0.14.0",
4041
"@spruceid/didkit-wasm-node": "^0.2.1",
4142
"@uniswap/sdk-core": "^3.0.1",
4243
"@uniswap/v3-sdk": "^3.9.0",

src/constants.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { Protocol } from './types';
2+
3+
export const DEFAULT_SUPPORTED_PROTOCOLS: Protocol[] = ['evm'];
4+
export const VALID_PROTOCOLS: Protocol[] = ['evm', 'starknet'];
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
This strategy returns total voting power on Defi App, based on HOME and sHOME.
2+
3+
HOME tokens have no voting power multiplier, whereas sHOME (staked HOME) tokens have a 4x multiplier.
4+
5+
Here is an example of parameters:
6+
7+
{
8+
"lockingContract": "0xC9714F8f036087d801f38C4105194e150d3a1864",
9+
"homeToken": "0x4BfAa776991E85e5f8b1255461cbbd216cFc714f"
10+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
[
2+
{
3+
"name": "HOME & sHOME Voting - Base",
4+
"strategy": {
5+
"name": "defi-app-voting",
6+
"params": {
7+
"lockingContract": "0xC9714F8f036087d801f38C4105194e150d3a1864",
8+
"homeToken": "0x4BfAa776991E85e5f8b1255461cbbd216cFc714f"
9+
}
10+
},
11+
"network": "8453",
12+
"addresses": [
13+
"0x0dC9044fcD7760dfbdB567A364B9B098e770b192",
14+
"0x4011091Dbe57bd4521F598616fe4BB3978ea3005",
15+
"0x2eAA7327e9B5Ff46bc2B7452acE9e44A1528eb84"
16+
],
17+
"snapshot": 31422072
18+
}
19+
]
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
import { BigNumberish } from '@ethersproject/bignumber';
2+
import { formatUnits } from '@ethersproject/units';
3+
import { Multicaller } from '../../utils';
4+
5+
export const author = 'JD0x2e';
6+
export const version = '0.1.2';
7+
8+
const mfdAbi = [
9+
'function getUserLocks(address) view returns (tuple(uint256 amount, uint256 unlockTime, uint256 multiplier, uint256 duration, uint256 lockCreationTime)[])'
10+
];
11+
12+
const erc20Abi = ['function balanceOf(address) view returns (uint256)'];
13+
14+
const toJsNum = (bn: BigNumberish) => parseFloat(formatUnits(bn));
15+
16+
export async function strategy(
17+
space,
18+
network,
19+
provider,
20+
addresses,
21+
options,
22+
snapshot
23+
): Promise<Record<string, number>> {
24+
const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';
25+
26+
const MFD_CONTRACT = options.lockingContract;
27+
const HOME_TOKEN = options.homeToken;
28+
29+
const locksMulticaller = new Multicaller(network, provider, mfdAbi, {
30+
blockTag
31+
});
32+
const homeMulticaller = new Multicaller(network, provider, erc20Abi, {
33+
blockTag
34+
});
35+
36+
addresses.forEach((address) => {
37+
locksMulticaller.call(address, MFD_CONTRACT, 'getUserLocks', [address]);
38+
homeMulticaller.call(address, HOME_TOKEN, 'balanceOf', [address]);
39+
});
40+
41+
const [lockResults, homeBalances] = await Promise.all([
42+
locksMulticaller.execute(),
43+
homeMulticaller.execute()
44+
]);
45+
46+
return Object.fromEntries(
47+
addresses.map((address) => {
48+
const locks = lockResults[address] ?? [];
49+
const sHome = locks.reduce((acc, lock) => acc + toJsNum(lock.amount), 0);
50+
const home = toJsNum(homeBalances[address] ?? 0);
51+
52+
const weightedPower = sHome * 4 + home;
53+
return [address, weightedPower];
54+
})
55+
);
56+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Delegated APE
2+
3+
This strategy calculates voting power based on gas token balance with delegation support.
4+
5+
If a user has delegated their voting power to someone else, their own balance is not counted toward their voting power.
6+
7+
## Parameters
8+
9+
| Parameter | Description | Required |
10+
| --------- | ----------- | -------- |
11+
| `delegationContract` | Address of the delegation contract | Yes |
12+
| `delegationId` | Delegation ID (bytes32) to query | Yes |
13+
| `symbol` | Symbol to display | No |
14+
15+
## Example Configuration
16+
17+
```json
18+
{
19+
"delegationContract": "0xDd6B74123b2aB93aD701320D3F8D1b92B4fA5202",
20+
"delegationId": "0x0000000000000000000000000000000000000000000000000000000000000001",
21+
"symbol": "APE"
22+
}
23+
```

0 commit comments

Comments
 (0)