Skip to content

Commit

Permalink
Merge pull request #413 from valory-xyz/feat/add_staking_contracts
Browse files Browse the repository at this point in the history
Add Pearl Beta 3, 4, 5 staking contracts
  • Loading branch information
truemiller authored Nov 1, 2024
2 parents e8db80a + f0e54d1 commit 1d35484
Show file tree
Hide file tree
Showing 12 changed files with 126 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export enum CantMigrateReason {
InsufficientOlasToMigrate = 'Insufficient OLAS to switch',
MigrationNotSupported = 'Switching to this program is not currently supported',
NoAvailableRewards = 'This program has no rewards available',
NoAvailableStakingSlots = 'The program has no more avaiable slots',
NoAvailableStakingSlots = 'The program has no more available slots',
NotStakedForMinimumDuration = 'Pearl has not been staked for the required minimum duration',
PearlCurrentlyRunning = 'Unable to switch while Pearl is running',
LoadingServices = 'Loading services...',
Expand Down Expand Up @@ -208,7 +208,7 @@ export const useMigrate = (stakingProgramId: StakingProgramId) => {

const stakingContractInfo = stakingContractInfoRecord?.[stakingProgramId];

if (stakingContractInfo?.availableRewards === 0) {
if ((stakingContractInfo?.availableRewards ?? 0) <= 0) {
return {
canMigrate: false,
reason: CantMigrateReason.NoAvailableRewards,
Expand Down
9 changes: 7 additions & 2 deletions frontend/constants/contractAddresses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,14 @@ export const SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES: Record<
Record<StakingProgramId, Address>
> = {
[Chain.GNOSIS]: {
[StakingProgramId.Beta2]: '0x1c2F82413666d2a3fD8bC337b0268e62dDF67434',
[StakingProgramId.Beta]: '0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d',
[StakingProgramId.Alpha]: '0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A',

[StakingProgramId.Beta]: '0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d',
[StakingProgramId.Beta2]: '0x1c2F82413666d2a3fD8bC337b0268e62dDF67434',
[StakingProgramId.Beta3]: '0xBd59Ff0522aA773cB6074ce83cD1e4a05A457bc1',
[StakingProgramId.Beta4]: '0x3052451e1eAee78e62E169AfdF6288F8791F2918',
[StakingProgramId.Beta5]: '0x4Abe376Fda28c2F43b84884E5f822eA775DeA9F4',

[StakingProgramId.BetaMechMarketplace]:
'0xDaF34eC46298b53a3d24CBCb431E84eBd23927dA',
},
Expand Down
42 changes: 31 additions & 11 deletions frontend/constants/stakingProgramMeta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,55 @@ export type StakingProgramMeta = {
deprecated: boolean;
};

const allStakingProgramIds = Object.values(StakingProgramId);
const deprecatedStakingProgramIds = [StakingProgramId.Alpha];
const activeStakingProgramIds = allStakingProgramIds.filter(
(id) => !deprecatedStakingProgramIds.includes(id),
);

const activeStakingProgramsWithout = (stakingProgramId: StakingProgramId) =>
activeStakingProgramIds.filter((id) => id !== stakingProgramId);

export const STAKING_PROGRAM_META: Record<
StakingProgramId,
StakingProgramMeta
> = {
[StakingProgramId.Alpha]: {
name: 'Pearl Alpha',
canMigrateTo: [
StakingProgramId.Beta,
StakingProgramId.Beta2,
StakingProgramId.BetaMechMarketplace,
],
canMigrateTo: activeStakingProgramsWithout(StakingProgramId.Alpha),
deprecated: true,
},
[StakingProgramId.Beta]: {
name: 'Pearl Beta',
canMigrateTo: [
StakingProgramId.Beta2,
StakingProgramId.BetaMechMarketplace,
],
canMigrateTo: activeStakingProgramsWithout(StakingProgramId.Beta),
deprecated: false,
},
[StakingProgramId.Beta2]: {
name: 'Pearl Beta 2',
canMigrateTo: [StakingProgramId.Beta, StakingProgramId.BetaMechMarketplace],
canMigrateTo: activeStakingProgramsWithout(StakingProgramId.Beta2),
deprecated: false,
},
[StakingProgramId.Beta3]: {
name: 'Pearl Beta 3',
canMigrateTo: activeStakingProgramsWithout(StakingProgramId.Beta3),
deprecated: false,
},
[StakingProgramId.Beta4]: {
name: 'Pearl Beta 4',
canMigrateTo: activeStakingProgramsWithout(StakingProgramId.Beta4),
deprecated: false,
},
[StakingProgramId.Beta5]: {
name: 'Pearl Beta 5',
canMigrateTo: activeStakingProgramsWithout(StakingProgramId.Beta5),
deprecated: false,
},

[StakingProgramId.BetaMechMarketplace]: {
name: 'Pearl Beta Mech Marketplace',
canMigrateTo: [StakingProgramId.Beta, StakingProgramId.Beta2],
canMigrateTo: activeStakingProgramsWithout(
StakingProgramId.BetaMechMarketplace,
),
deprecated: false,
},
};
41 changes: 20 additions & 21 deletions frontend/context/StakingContractInfoProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,29 +84,28 @@ export const StakingContractInfoProvider = ({

/** Updates general staking contract information, not user or service specific */
const updateStakingContractInfoRecord = async () => {
const alpha = AutonolasService.getStakingContractInfoByStakingProgram(
StakingProgramId.Alpha,
);
const beta = AutonolasService.getStakingContractInfoByStakingProgram(
StakingProgramId.Beta,
);
const beta2 = AutonolasService.getStakingContractInfoByStakingProgram(
StakingProgramId.Beta2,
);
const betaMechMarketplace =
AutonolasService.getStakingContractInfoByStakingProgram(
StakingProgramId.BetaMechMarketplace,
);
const stakingPrograms = Object.values(StakingProgramId);

try {
const [alphaInfo, betaInfo, beta2Info, betaMechMarketplaceInfo] =
await Promise.all([alpha, beta, beta2, betaMechMarketplace]);
setStakingContractInfoRecord({
[StakingProgramId.Alpha]: alphaInfo,
[StakingProgramId.Beta]: betaInfo,
[StakingProgramId.Beta2]: beta2Info,
[StakingProgramId.BetaMechMarketplace]: betaMechMarketplaceInfo,
});
const stakingInfoPromises = stakingPrograms.map((programId) =>
AutonolasService.getStakingContractInfoByStakingProgram(programId),
);

const stakingInfos = await Promise.allSettled(stakingInfoPromises);

const stakingContractInfoRecord = stakingPrograms.reduce(
(record, programId, index) => {
if (stakingInfos[index].status === 'rejected') {
console.error(stakingInfos[index].reason);
return record;
}
record[programId] = stakingInfos[index].value;
return record;
},
{} as Record<string, Partial<StakingContractInfo>>,
);

setStakingContractInfoRecord(stakingContractInfoRecord);
setIsStakingContractInfoLoaded(true);
} catch (e) {
console.error(e);
Expand Down
6 changes: 4 additions & 2 deletions frontend/context/StakingProgramProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ import { StakingProgramId } from '@/enums/StakingProgram';
import { useServices } from '@/hooks/useServices';
import { AutonolasService } from '@/service/Autonolas';

export const DEFAULT_STAKING_PROGRAM_ID = StakingProgramId.Beta;

export const StakingProgramContext = createContext<{
activeStakingProgramId?: StakingProgramId | null;
defaultStakingProgramId: StakingProgramId;
updateActiveStakingProgramId: () => Promise<void>;
}>({
activeStakingProgramId: undefined,
defaultStakingProgramId: StakingProgramId.Beta,
defaultStakingProgramId: DEFAULT_STAKING_PROGRAM_ID,
updateActiveStakingProgramId: async () => {},
});

Expand Down Expand Up @@ -50,7 +52,7 @@ export const StakingProgramProvider = ({ children }: PropsWithChildren) => {
value={{
activeStakingProgramId,
updateActiveStakingProgramId,
defaultStakingProgramId: StakingProgramId.Beta,
defaultStakingProgramId: DEFAULT_STAKING_PROGRAM_ID,
}}
>
{children}
Expand Down
3 changes: 3 additions & 0 deletions frontend/enums/StakingProgram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@ export enum StakingProgramId {
Alpha = 'pearl_alpha',
Beta = 'pearl_beta',
Beta2 = 'pearl_beta_2',
Beta3 = 'pearl_beta_3',
Beta4 = 'pearl_beta_4',
Beta5 = 'pearl_beta_5',
BetaMechMarketplace = 'pearl_beta_mech_marketplace',
}
4 changes: 2 additions & 2 deletions frontend/hooks/useStakingContractInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ export const useStakingContractInfo = () => {
const {
serviceStakingState,
serviceStakingStartTime,
//availableRewards, // TODO: uncomment when availableRewards is available
serviceIds,
maxNumServices,
minimumStakingDuration,
availableRewards,
} = activeStakingContractInfo;

const isRewardsAvailable = true; // availableRewards > 0;
const isRewardsAvailable = availableRewards ?? 0 > 0;

const hasEnoughServiceSlots =
!isNil(serviceIds) &&
Expand Down
66 changes: 37 additions & 29 deletions frontend/service/Autonolas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,32 +35,18 @@ const ServiceStakingTokenAbi = SERVICE_STAKING_TOKEN_MECH_USAGE_ABI.filter(
const serviceStakingTokenMechUsageContracts: Record<
StakingProgramId,
MulticallContract
> = {
[StakingProgramId.Alpha]: new MulticallContract(
SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS][
StakingProgramId.Alpha
],
ServiceStakingTokenAbi,
),
[StakingProgramId.Beta]: new MulticallContract(
SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS][
StakingProgramId.Beta
],
ServiceStakingTokenAbi,
),
[StakingProgramId.Beta2]: new MulticallContract(
SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS][
StakingProgramId.Beta2
],
ServiceStakingTokenAbi,
),
[StakingProgramId.BetaMechMarketplace]: new MulticallContract(
SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS][
StakingProgramId.BetaMechMarketplace
],
ServiceStakingTokenAbi,
),
};
> = Object.values(StakingProgramId).reduce(
(contracts, programId) => {
contracts[programId] = new MulticallContract(
SERVICE_STAKING_TOKEN_MECH_USAGE_CONTRACT_ADDRESSES[Chain.GNOSIS][
programId
],
ServiceStakingTokenAbi,
);
return contracts;
},
{} as Record<StakingProgramId, MulticallContract>,
);

const serviceRegistryTokenUtilityContract = new MulticallContract(
SERVICE_REGISTRY_TOKEN_UTILITY_CONTRACT_ADDRESS[Chain.GNOSIS],
Expand Down Expand Up @@ -306,19 +292,26 @@ const getStakingContractInfoByStakingProgram = async (
const availableRewards = parseFloat(
ethers.utils.formatUnits(availableRewardsInBN, 18),
);

const serviceIds = getServiceIdsInBN.map((id: BigNumber) => id.toNumber());
const maxNumServices = maxNumServicesInBN.toNumber();

// APY
const rewardsPerYear = rewardsPerSecond.mul(ONE_YEAR);
const apy =
Number(rewardsPerYear.mul(100).div(minStakingDeposit)) /
(1 + numAgentInstances.toNumber());

let apy = 0;

if (rewardsPerSecond.gt(0) && minStakingDeposit.gt(0)) {
apy =
Number(rewardsPerYear.mul(100).div(minStakingDeposit)) /
(1 + numAgentInstances.toNumber());
}

// Amount of OLAS required for Stake
const stakeRequiredInWei = minStakingDeposit.add(
minStakingDeposit.mul(numAgentInstances),
);

const olasStakeRequired = Number(formatEther(stakeRequiredInWei));

// Rewards per work period
Expand Down Expand Up @@ -402,6 +395,9 @@ const getCurrentStakingProgramByServiceId = async (
isAlphaStaked,
isBetaStaked,
isBeta2Staked,
isBeta3Staked,
isBeta4Staked,
isBeta5Staked,
isBetaMechMarketplaceStaked,
] = await gnosisMulticallProvider.all(Object.values(contractCalls));

Expand All @@ -417,6 +413,18 @@ const getCurrentStakingProgramByServiceId = async (
return StakingProgramId.Beta2;
}

if (isBeta3Staked) {
return StakingProgramId.Beta3;
}

if (isBeta4Staked) {
return StakingProgramId.Beta4;
}

if (isBeta5Staked) {
return StakingProgramId.Beta5;
}

if (isBetaMechMarketplaceStaked) {
return StakingProgramId.BetaMechMarketplace;
}
Expand Down
15 changes: 14 additions & 1 deletion frontend/utils/service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { ServiceTemplate } from '@/client';
import { DEFAULT_STAKING_PROGRAM_ID } from '@/context/StakingProgramProvider';
import { StakingProgramId } from '@/enums/StakingProgram';

/** TODO: update from hardcoded, workaround for quick release */
export const getMinimumStakedAmountRequired = (
serviceTemplate?: ServiceTemplate, //TODO: remove, as unused
stakingProgramId: StakingProgramId = StakingProgramId.Beta,
stakingProgramId: StakingProgramId = DEFAULT_STAKING_PROGRAM_ID,
): number | undefined => {
if (stakingProgramId === StakingProgramId.Alpha) {
return 20;
Expand All @@ -18,6 +19,18 @@ export const getMinimumStakedAmountRequired = (
return 100;
}

if (stakingProgramId === StakingProgramId.Beta3) {
return 100;
}

if (stakingProgramId === StakingProgramId.Beta4) {
return 100;
}

if (stakingProgramId === StakingProgramId.Beta5) {
return 10;
}

if (stakingProgramId === StakingProgramId.BetaMechMarketplace) {
return 40;
}
Expand Down
3 changes: 3 additions & 0 deletions operate/ledger/profiles.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
"pearl_alpha": "0xEE9F19b5DF06c7E8Bfc7B28745dcf944C504198A",
"pearl_beta": "0xeF44Fb0842DDeF59D37f85D61A1eF492bbA6135d",
"pearl_beta_2": "0x1c2F82413666d2a3fD8bC337b0268e62dDF67434",
"pearl_beta_3": "0xBd59Ff0522aA773cB6074ce83cD1e4a05A457bc1",
"pearl_beta_4": "0x3052451e1eAee78e62E169AfdF6288F8791F2918",
"pearl_beta_5": "0x4Abe376Fda28c2F43b84884E5f822eA775DeA9F4",
"pearl_beta_mech_marketplace": "0xDaF34eC46298b53a3d24CBCb431E84eBd23927dA",
}
}
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,11 +57,11 @@
"install:frontend": "cd frontend && yarn",
"lint:frontend": "cd frontend && yarn lint",
"start": "yarn electron .",
"dev": "dotenv -e .env -- yarn start",
"dev": "dotenv -e .env -- electron .",
"start:frontend": "cd frontend && yarn start",
"test:frontend": "cd frontend && yarn test",
"download-binaries": "sh download_binaries.sh",
"build:pearl": "sh build_pearl.sh"
},
"version": "0.1.0-rc182"
"version": "0.1.0-rc183"
}
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "olas-operate-middleware"
version = "0.1.0-rc182"
version = "0.1.0-rc183"
description = ""
authors = ["David Vilela <[email protected]>", "Viraj Patel <[email protected]>"]
readme = "README.md"
Expand Down

0 comments on commit 1d35484

Please sign in to comment.