-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
454 additions
and
0 deletions.
There are no files selected for viewing
This file contains 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
132 changes: 132 additions & 0 deletions
132
packages/ethernaut-optigov/src/internal/agora/Delegates.js
This file contains 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,132 @@ | ||
const debug = require('ethernaut-common/src/ui/debug') | ||
|
||
class Delegates { | ||
constructor(agora) { | ||
this.agora = agora | ||
} | ||
|
||
// Get a list of delegates with pagination | ||
async getDelegates({ limit = 10, offset = 0, sort } = {}) { | ||
try { | ||
const axiosInstance = this.agora.createAxiosInstance() | ||
const response = await axiosInstance.get('/delegates', { | ||
params: { limit, offset, sort }, | ||
}) | ||
|
||
debug.log(`Delegates: ${response.data.data}`, 'ethernaut-optigov') | ||
return response.data.data.map((delegate) => ({ | ||
address: delegate.address, | ||
votingPower: delegate.votingPower?.total, | ||
twitter: delegate.statement?.payload?.twitter, | ||
discord: delegate.statement?.payload?.discord, | ||
delegateStatement: | ||
delegate.statement?.payload?.delegateStatement?.substring(0, 100), | ||
})) | ||
} catch (error) { | ||
this.agora.handleError(error) | ||
} | ||
} | ||
|
||
// Get a specific delegate by address or ENS name | ||
async getDelegateById(addressOrEnsName) { | ||
try { | ||
const axiosInstance = this.agora.createAxiosInstance() | ||
const response = await axiosInstance.get(`/delegates/${addressOrEnsName}`) | ||
|
||
debug.log(`Delegate: ${response.data}`, 'ethernaut-optigov') | ||
const data = response.data | ||
return { | ||
address: data.address, | ||
votingPower: { | ||
advanced: data.votingPower.advanced, | ||
direct: data.votingPower.direct, | ||
total: data.votingPower.total, | ||
}, | ||
votingPowerRelativeToVotableSupply: | ||
data.votingPowerRelativeToVotableSupply, | ||
votingPowerRelativeToQuorum: data.votingPowerRelativeToQuorum, | ||
proposalsCreated: data.proposalsCreated, | ||
proposalsVotedOn: data.proposalsVotedOn, | ||
votedFor: data.votedFor, | ||
votedAgainst: data.votedAgainst, | ||
votedAbstain: data.votedAbstain, | ||
votingParticipation: data.votingParticipation, | ||
lastTenProps: data.lastTenProps, | ||
numOfDelegators: data.numOfDelegators, | ||
} | ||
} catch (error) { | ||
this.agora.handleError(error) | ||
} | ||
} | ||
|
||
// Get a paginated list of votes for a specific delegate | ||
async getDelegateVotes({ | ||
addressOrEnsName, | ||
limit = 10, | ||
offset = 0, | ||
sort, | ||
} = {}) { | ||
try { | ||
const axiosInstance = this.agora.createAxiosInstance() | ||
const response = await axiosInstance.get( | ||
`/delegates/${addressOrEnsName}/votes`, | ||
{ | ||
params: { limit, offset, sort }, | ||
}, | ||
) | ||
|
||
debug.log( | ||
`Votes for Delegate ${addressOrEnsName}: ${response.data.data}`, | ||
'ethernaut-optigov', | ||
) | ||
return response.data.data.map((vote) => ({ | ||
transactionHash: vote.transactionHash, | ||
proposalId: vote.proposalId, | ||
address: vote.address, | ||
support: vote.support, | ||
reason: vote.reason, | ||
weight: vote.weight, | ||
proposalValue: vote.proposalValue, | ||
proposalTitle: vote.proposalTitle, | ||
proposalType: vote.proposalType, | ||
timestamp: vote.timestamp, | ||
})) | ||
} catch (error) { | ||
this.agora.handleError(error) | ||
} | ||
} | ||
|
||
// Get a paginated list of delegators for a specific delegate | ||
async getDelegateDelegators({ | ||
addressOrEnsName, | ||
limit = 10, | ||
offset = 0, | ||
sort, | ||
} = {}) { | ||
try { | ||
const axiosInstance = this.agora.createAxiosInstance() | ||
const response = await axiosInstance.get( | ||
`/delegates/${addressOrEnsName}/delegators`, | ||
{ | ||
params: { limit, offset, sort }, | ||
}, | ||
) | ||
|
||
debug.log( | ||
`Delegators for Delegate ${addressOrEnsName}: ${response.data.data}`, | ||
'ethernaut-optigov', | ||
) | ||
return response.data.data.map((delegator) => ({ | ||
from: delegator.from, | ||
allowance: delegator.allowance, | ||
timestamp: delegator.timestamp, | ||
type: delegator.type, | ||
amount: delegator.amount, | ||
})) | ||
} catch (error) { | ||
this.agora.handleError(error) | ||
} | ||
} | ||
} | ||
|
||
module.exports = Delegates |
This file contains 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,143 @@ | ||
const types = require('ethernaut-common/src/validation/types') | ||
const output = require('ethernaut-common/src/ui/output') | ||
const Delegates = require('../internal/agora/Delegates') | ||
const Agora = require('../internal/agora/Agora') | ||
|
||
const RELATED_DATA = { | ||
votes: 'votes', | ||
delegators: 'delegators', | ||
none: 'none', | ||
} | ||
|
||
require('../scopes/optigov') | ||
.task( | ||
'delegates', | ||
'Prints a list of delegates on Agora, or a specific delegate, with optional votes or delegator related data', | ||
) | ||
.addOptionalParam( | ||
'limit', | ||
'The maximum number of delegates to fetch. Defaults to 10.', | ||
10, | ||
types.int, | ||
) | ||
.addOptionalParam( | ||
'offset', | ||
'The number of delegates to skip before starting to fetch. Defaults to 0.', | ||
0, | ||
types.int, | ||
) | ||
.addOptionalParam( | ||
'address', | ||
'The address or ENS name of a specific delegate to query.', | ||
undefined, | ||
types.string, | ||
) | ||
.addOptionalParam( | ||
'relatedData', | ||
'If specified, fetch additional related data such as votes or delegators for the given address or ENS name.', | ||
RELATED_DATA.none, | ||
types.string, | ||
) | ||
.setAction(async ({ limit, offset, address, relatedData }) => { | ||
try { | ||
const agora = new Agora() | ||
const delegates = new Delegates(agora) | ||
|
||
if (address) { | ||
if (relatedData === RELATED_DATA.votes) { | ||
// Get votes | ||
const delegateVotes = await delegates.getDelegateVotes({ | ||
addressOrEnsName: address, | ||
limit, | ||
offset, | ||
}) | ||
return output.resultBox( | ||
printVotes(delegateVotes), | ||
`Votes for Delegate ${address}`, | ||
) | ||
} else if (relatedData === RELATED_DATA.delegators) { | ||
// Get delegators | ||
const delegateDelegators = await delegates.getDelegateDelegators({ | ||
addressOrEnsName: address, | ||
limit, | ||
offset, | ||
}) | ||
return output.resultBox( | ||
printDelegators(delegateDelegators), | ||
`Delegators for Delegate ${address}`, | ||
) | ||
} else { | ||
// Get the specific delegate | ||
const delegate = await delegates.getDelegateById(address) | ||
return output.resultBox( | ||
printDelegate(delegate), | ||
`Delegate ${address}`, | ||
) | ||
} | ||
} | ||
|
||
// If no specific address or ENS is given, fetch the list of delegates | ||
const delegateList = await delegates.getDelegates({ limit, offset }) | ||
|
||
return output.resultBox(printDelegates(delegateList), 'Delegates') | ||
} catch (err) { | ||
return output.errorBox(err) | ||
} | ||
}) | ||
|
||
function printDelegates(delegates) { | ||
const strs = [] | ||
|
||
for (const delegate of delegates) { | ||
strs.push( | ||
`Address: ${delegate.address} | ||
Voting Power: ${delegate.votingPower} | ||
Twitter: ${delegate.twitter} | ||
Discord: ${delegate.discord} | ||
Statement: ${delegate.delegateStatement}`, | ||
) | ||
} | ||
|
||
return strs.join('\n\n') | ||
} | ||
|
||
function printDelegate(delegate) { | ||
return `Address: ${delegate.address} | ||
Voting Power (Advanced): ${delegate.votingPower.advanced} | ||
Voting Power (Direct): ${delegate.votingPower.direct} | ||
Voting Power (Total): ${delegate.votingPower.total} | ||
Voting Power Relative to Votable Supply: ${delegate.votingPowerRelativeToVotableSupply} | ||
Voting Power Relative to Quorum: ${delegate.votingPowerRelativeToQuorum} | ||
Proposals Created: ${delegate.proposalsCreated} | ||
Proposals Voted On: ${delegate.proposalsVotedOn} | ||
Voted For: ${delegate.votedFor} | ||
Voted Against: ${delegate.votedAgainst} | ||
Voted Abstain: ${delegate.votedAbstain} | ||
Voting Participation: ${delegate.votingParticipation} | ||
Last Ten Proposals: ${delegate.lastTenProps} | ||
Number of Delegators: ${delegate.numOfDelegators}` | ||
} | ||
|
||
function printVotes(votes) { | ||
const strs = [] | ||
|
||
for (const vote of votes) { | ||
strs.push( | ||
` - Support: ${vote.support}, Weight: ${vote.weight}, Proposal: ${vote.proposalTitle} (ID: ${vote.proposalId}), Timestamp: ${vote.timestamp}`, | ||
) | ||
} | ||
|
||
return strs.join('\n\n') | ||
} | ||
|
||
function printDelegators(delegators) { | ||
const strs = [] | ||
|
||
for (const delegator of delegators) { | ||
strs.push( | ||
` - From: ${delegator.from}, Allowance: ${delegator.allowance}, Type: ${delegator.type}, Amount: ${delegator.amount}, Timestamp: ${delegator.timestamp}`, | ||
) | ||
} | ||
|
||
return strs.join('\n\n') | ||
} |
Oops, something went wrong.