Skip to content

feature(SDK): add DualGovernance module #229

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
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

phonktown
Copy link

@phonktown phonktown commented May 20, 2025

Description

This PR includes:

  • DualGovernance module for SDK
  • DualGovernance warning status playground

The latter is to fetch current Governance status in terms of 3 main states [Normal, Warning, Blocked]

The method getGovernanceWarningStatus is a helper for applications to decide whether any actions should be performed in UI based on the Governance state.

Return type of this helper is defined in types.ts

export type GetGovernanceWarningStatusReturnType = {
  state: 'Blocked' | 'Warning' | 'Normal' | 'Unknown'
  currentVetoSupportPercent: number | null;
};

Most of the methods are public for future usage and integrations.

Note

Docs will be added later to cover all the logic the DG module is based on, including test scenarios.

Checklist:

  • Checked the changes locally.
  • Created/updated unit tests.
  • Created/updated README.md.

@phonktown phonktown force-pushed the feature/dual-governance-module branch from 6bbeb40 to c2a3a9d Compare May 21, 2025 09:39
@phonktown phonktown marked this pull request as ready for review May 21, 2025 09:53
@phonktown phonktown requested a review from a team as a code owner May 21, 2025 09:53
@phonktown phonktown force-pushed the feature/dual-governance-module branch 2 times, most recently from 4177504 to 2138e77 Compare May 21, 2025 15:12
@phonktown phonktown requested a review from swissarmytowel May 21, 2025 15:13
@phonktown phonktown force-pushed the feature/dual-governance-module branch from 2138e77 to f7a3c25 Compare May 21, 2025 15:17
swissarmytowel
swissarmytowel previously approved these changes May 21, 2025
katamarinaki
katamarinaki previously approved these changes May 21, 2025
@@ -92,6 +92,14 @@ export enum LIDO_CONTRACT_NAMES {
wsteth = 'wsteth',
}

export const EMERGENCY_PROTECTED_TIMELOCK_ADDRESSES: {
Copy link
Contributor

@DiRaiks DiRaiks May 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will these addresses be added to Locator?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not ATM.

const stETHContract = await dualGovernance.getContractStETH();
expectContract(stETHContract);

const stETHAddress = await dualGovernance.getStETHAddress();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems that this test is not very useful. It checks the address from the module against the address from the module.
Wouldn't it be better to check the address from the module against the address from the locator?

expect(result).toBeDefined();

// Expect above doesn't solve 'possibly undefined' linter warning, so we still have a condition as below
if (result !== undefined) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in which case will it be undefined?

export class LidoSDKDualGovernance extends LidoSDKModule {
// ---- Contract Addresses ----

@Cache(30 * 60 * 1000, ['core.chain.id'])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like here we need a cache for getContractEmergencyProtectedTimelock too

// ---- Contract Addresses ----

@Cache(30 * 60 * 1000, ['core.chain.id'])
public async getGovernanceAddress(): Promise<Address | undefined> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lets use getContractAddress from core module

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Working with Dual Governance we follow a specific approach regarding getting the contract addresses.

The only constant address in this feature is EmergencyProtectedTimelock.

The Governance address is dynamic. So we never access it directly, as well as all the addresses we get from the Governance.

Hence, in the module, as well as in the tests and UI, we only keep EmergencyProtectedTimelock as the source of truth and get the rest contracts through it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is important here is that all contract addresses are present in the Core module.

}

@Cache(30 * 60 * 1000, ['core.chain.id'])
public async getVetoSignallingEscrowAddress(): Promise<Address | undefined> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getContractAddress

}

@Cache(30 * 60 * 1000, ['core.chain.id'])
public async getStETHAddress(): Promise<Address | undefined> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

already has in the core module

}

@Cache(30 * 60 * 1000, ['core.chain.id'])
public async getDualGovernanceConfigProviderAddress(): Promise<
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getContractAddress

GetContractReturnType<typeof emergencyProtectedTimelockAbi, PublicClient>
> {
const address =
EMERGENCY_PROTECTED_TIMELOCK_ADDRESSES[this.core.chain.id as CHAINS];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move to getContractAddress

});
}

@Cache(30 * 60 * 1000, ['core.chain.id'])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pls check cache for all methods

}
}

public async getTotalStEthInEscrow(): Promise<bigint | undefined> {
Copy link
Contributor

@DiRaiks DiRaiks May 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@logger('Views:')
@errorhandler()

And you dont need additional try/catch here

}
}

public async getDualGovernanceConfig(): Promise<
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@logger('Views:')
@errorhandler()

}
}

public async getTotalStETHSupply(): Promise<bigint | undefined> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@logger('Views:')
@errorhandler()

}
}

public async calculateCurrentVetoSignallingThresholdProgress(): Promise<
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@logger('Views:')
@errorhandler()

}
| undefined
> {
const totalStETHSupply = await this.getTotalStETHSupply();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const [] = Promise.all

}
}

public async getGovernanceWarningStatus({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@logger('Views:')
@errorhandler()

Copy link
Contributor

@DiRaiks DiRaiks left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the new DG module and tests!
Will need another review iteration after fixing the comments

@phonktown phonktown dismissed stale reviews from katamarinaki and swissarmytowel via 027346b May 31, 2025 10:29
@phonktown phonktown requested a review from DiRaiks May 31, 2025 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants