-
Notifications
You must be signed in to change notification settings - Fork 14
feat: update proposal's value #570
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
wa0x6e
wants to merge
6
commits into
master
Choose a base branch
from
feat-update-proposal-scores-value
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
0e77cd4
feat: update proposal's value
wa0x6e cac0b30
refactor: centralize fiat handling in a dedicated helper
wa0x6e a13c0a4
refactor: centralize fiat value logic in dedicated helper
wa0x6e 716f434
Update src/helpers/entityValue.ts
wa0x6e 0706ce6
refactor: improve readability and robustness
wa0x6e 730f416
Merge branch 'master' into feat-update-proposal-scores-value
wa0x6e File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
type Proposal = { | ||
scores_by_strategy: number[][]; | ||
vp_value_by_strategy: number[]; | ||
}; | ||
|
||
/** | ||
* Calculates the proposal total value based on all votes' total voting power and the proposal's value per strategy. | ||
* @returns The total value of the given proposal's votes, in the currency unit specified by the proposal's vp_value_by_strategy values | ||
*/ | ||
export function getProposalValue(proposal: Proposal): number { | ||
const { scores_by_strategy, vp_value_by_strategy } = proposal; | ||
|
||
if ( | ||
!scores_by_strategy.length || | ||
!scores_by_strategy[0]?.length || | ||
!vp_value_by_strategy.length | ||
) { | ||
return 0; | ||
} | ||
|
||
let totalValue = 0; | ||
for (let strategyIndex = 0; strategyIndex < vp_value_by_strategy.length; strategyIndex++) { | ||
const strategyTotal = scores_by_strategy.reduce((sum, voteScores) => { | ||
if (voteScores.length !== vp_value_by_strategy.length) { | ||
throw new Error( | ||
'Array size mismatch: voteScores length does not match vp_value_by_strategy length' | ||
); | ||
} | ||
const score = voteScores[strategyIndex]; | ||
if (typeof score !== 'number') { | ||
throw new Error(`Invalid score value: expected number, got ${typeof score}`); | ||
} | ||
return sum + score; | ||
}, 0); | ||
|
||
if (typeof vp_value_by_strategy[strategyIndex] !== 'number') { | ||
throw new Error( | ||
`Invalid vp_value: expected number, got ${typeof vp_value_by_strategy[strategyIndex]}` | ||
); | ||
} | ||
|
||
totalValue += strategyTotal * vp_value_by_strategy[strategyIndex]; | ||
} | ||
|
||
return totalValue; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
import { getProposalValue } from '../../../src/helpers/entityValue'; | ||
|
||
describe('getProposalValue', () => { | ||
it('should calculate correct proposal value with single strategy', () => { | ||
const proposal = { | ||
scores_by_strategy: [[100], [200]], | ||
vp_value_by_strategy: [2.5] | ||
}; | ||
|
||
const result = getProposalValue(proposal); | ||
|
||
expect(result).toBe(750); // (100 + 200) * 2.5 = 300 * 2.5 = 750 | ||
}); | ||
|
||
it('should calculate correct proposal value with multiple strategies', () => { | ||
const proposal = { | ||
scores_by_strategy: [ | ||
[100, 50], | ||
[200, 75], | ||
[300, 25] | ||
], | ||
vp_value_by_strategy: [1.5, 3.0] | ||
}; | ||
|
||
const result = getProposalValue(proposal); | ||
|
||
expect(result).toBe(1350); // (100+200+300)*1.5 + (50+75+25)*3.0 = 600*1.5 + 150*3.0 = 900 + 450 = 1350 | ||
}); | ||
|
||
it('should return 0 when scores_by_strategy is empty', () => { | ||
const proposal = { | ||
scores_by_strategy: [], | ||
vp_value_by_strategy: [2.0] | ||
}; | ||
|
||
const result = getProposalValue(proposal); | ||
|
||
expect(result).toBe(0); | ||
}); | ||
|
||
it('should return 0 when first strategy array is empty', () => { | ||
const proposal = { | ||
scores_by_strategy: [[]], | ||
vp_value_by_strategy: [2.0] | ||
}; | ||
|
||
const result = getProposalValue(proposal); | ||
|
||
expect(result).toBe(0); | ||
}); | ||
|
||
it('should return 0 when vp_value_by_strategy is empty', () => { | ||
const proposal = { | ||
scores_by_strategy: [[100], [200]], | ||
vp_value_by_strategy: [] | ||
}; | ||
|
||
const result = getProposalValue(proposal); | ||
|
||
expect(result).toBe(0); | ||
}); | ||
|
||
it('should handle zero values correctly', () => { | ||
const proposal = { | ||
scores_by_strategy: [ | ||
[0, 0], | ||
[0, 0] | ||
], | ||
vp_value_by_strategy: [2.0, 1.5] | ||
}; | ||
|
||
const result = getProposalValue(proposal); | ||
|
||
expect(result).toBe(0); | ||
}); | ||
|
||
it('should handle zero vp_value_by_strategy correctly', () => { | ||
const proposal = { | ||
scores_by_strategy: [ | ||
[100, 50], | ||
[200, 75] | ||
], | ||
vp_value_by_strategy: [0, 0] | ||
}; | ||
|
||
const result = getProposalValue(proposal); | ||
|
||
expect(result).toBe(0); | ||
}); | ||
|
||
it('should handle decimal values correctly', () => { | ||
const proposal = { | ||
scores_by_strategy: [ | ||
[10.5, 20.5], | ||
[15.5, 25.5] | ||
], | ||
vp_value_by_strategy: [0.1, 0.2] | ||
}; | ||
|
||
const result = getProposalValue(proposal); | ||
|
||
expect(result).toBe(11.8); // (10.5+15.5)*0.1 + (20.5+25.5)*0.2 = 26*0.1 + 46*0.2 = 2.6 + 9.2 = 11.8 | ||
}); | ||
|
||
it('should handle single vote scenario', () => { | ||
const proposal = { | ||
scores_by_strategy: [[100]], | ||
vp_value_by_strategy: [2.0] | ||
}; | ||
|
||
const result = getProposalValue(proposal); | ||
|
||
expect(result).toBe(200); // 100 * 2.0 = 200 | ||
}); | ||
|
||
it('should throw on array size mismatch', () => { | ||
const proposal = { | ||
scores_by_strategy: [ | ||
[100, 50], // 2 strategies | ||
[200, 75] // 2 strategies | ||
], | ||
vp_value_by_strategy: [1.5] // Only 1 strategy value | ||
}; | ||
|
||
expect(() => getProposalValue(proposal)).toThrow( | ||
'Array size mismatch: voteScores length does not match vp_value_by_strategy length' | ||
); | ||
}); | ||
|
||
it('should throw on invalid score value', () => { | ||
const proposal = { | ||
scores_by_strategy: [ | ||
[100, 'invalid'], // Invalid string value | ||
[200, 75] | ||
], | ||
vp_value_by_strategy: [1.5, 2.0] | ||
} as any; | ||
|
||
expect(() => getProposalValue(proposal)).toThrow( | ||
'Invalid score value: expected number, got string' | ||
); | ||
}); | ||
|
||
it('should throw on invalid vp_value', () => { | ||
const proposal = { | ||
scores_by_strategy: [ | ||
[100, 50], | ||
[200, 75] | ||
], | ||
vp_value_by_strategy: [1.5, 'invalid'] // Invalid string value | ||
} as any; | ||
|
||
expect(() => getProposalValue(proposal)).toThrow( | ||
'Invalid vp_value: expected number, got string' | ||
); | ||
}); | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.