Skip to content

Commit

Permalink
feat: implement Redelegation of staking and pending withdrawals
Browse files Browse the repository at this point in the history
  • Loading branch information
kunstmusik committed Dec 19, 2024
1 parent 9aa8951 commit ba69db9
Show file tree
Hide file tree
Showing 13 changed files with 1,110 additions and 157 deletions.
112 changes: 62 additions & 50 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,119 +7,131 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Redelegate Stake: Users can now redelegate stake and pending withdrawals between gateways. Includes moving to/from operator stake and delegated stake.
Fee is applied if the user has redelegated within the last 7 days, at a rate of 10% per redelegation. If no redelegations have occurred in the last 7 days, the fee is 0%.

### Changed

- Leave Network: text updated to 90-days for vaulted funds
- Staking: Staking and Withdrawal are now separate modals that are initiated from unique popup menu options

### Fixed

- Gateway Details: Restored "Leave" (when viewing own gateway) and "Stake" (when viewing other gateways) buttons

## [1.6.0] - 2024-12-10

### Added
### Added

* Gateway Details
* Added Operator Stake card showing operator stake and EAY, as well as manage stake button for updating operator stake.
* Added collapsible Pending Withdrawals card for viewing current withdrawals as well as managing
them (canceling a withdrawal or initiating an expedited withdrawal). Visible only to the gateway operator.
* Added collapsible Active Delegates card showing the list of active delegates for the gateway.
- Gateway Details
- Added Operator Stake card showing operator stake and EAY, as well as manage stake button for updating operator stake.
- Added collapsible Pending Withdrawals card for viewing current withdrawals as well as managing
them (canceling a withdrawal or initiating an expedited withdrawal). Visible only to the gateway operator.
- Added collapsible Active Delegates card showing the list of active delegates for the gateway.

## [1.5.0] - 2024-12-04

### Added
### Added

* Profile button shows user's ArNS Primary Name (if available) or wallet address when logged in
* Download buttons added to Reports page and individual Report page
* Observers: Added epoch selector to view prescribed observers for previous epochs
* Gateway Details Page
* Reported On By card: text links to gateway for observer, report button links to report
* Reported On card: Report button shows in header that links to that report's page
- Profile button shows user's ArNS Primary Name (if available) or wallet address when logged in
- Download buttons added to Reports page and individual Report page
- Observers: Added epoch selector to view prescribed observers for previous epochs
- Gateway Details Page
- Reported On By card: text links to gateway for observer, report button links to report
- Reported On card: Report button shows in header that links to that report's page

### Updated

* Staking and Withdrawal modals updated to show Review page for user to confirm operation before processing
* Withdrawal Modal: Added option for Standard and Expedited Withdrawal
* Modal dialog styles refreshed
* Reward Share Ratio capped to 95% when joining network and updating gateway settings
- Staking and Withdrawal modals updated to show Review page for user to confirm operation before processing
- Withdrawal Modal: Added option for Standard and Expedited Withdrawal
- Modal dialog styles refreshed
- Reward Share Ratio capped to 95% when joining network and updating gateway settings

## [1.4.3] - 2024-11-27

### Updated

* Settings updated for staking:
* Staking withdrawals are now 90 days
* Gateway Operator Stake minimum is now 10,000 IO
* Minimum Delegated Staking amount for gateway configuration is now 10 IO
- Settings updated for staking:
- Staking withdrawals are now 90 days
- Gateway Operator Stake minimum is now 10,000 IO
- Minimum Delegated Staking amount for gateway configuration is now 10 IO

## [1.4.2] - 2024-11-20

### Updated

* Show error message toast if the application is unable to retrieve the current epoch
- Show error message toast if the application is unable to retrieve the current epoch

## [1.4.1] - 2024-11-18

### Updated

* Optimized loading of user stakes and pending withdrawals.
- Optimized loading of user stakes and pending withdrawals.

### Fixed

* Gateways count in site header should only count active gateways.
- Gateways count in site header should only count active gateways.

## [1.4.0] - 2024-11-14

### Added

* View Pending Withdrawals on Staking page and support cancelling pending withdrawals as well as performing expedited withdrawals
* View Changelog in app by clicking version number in sidebar
- View Pending Withdrawals on Staking page and support cancelling pending withdrawals as well as performing expedited withdrawals
- View Changelog in app by clicking version number in sidebar

### Updated

* Staking page top cards now show balance, amount staking + pending withdrawals, and rewards earned last 14 epochs and last epoch
- Staking page top cards now show balance, amount staking + pending withdrawals, and rewards earned last 14 epochs and last epoch

### Changed

* Updated header style of cards
* Observations: Updated to use arweave.net for reference domain when generating observation report
* Observe: Default to using prescribed names
- Updated header style of cards
- Observations: Updated to use arweave.net for reference domain when generating observation report
- Observe: Default to using prescribed names

## [1.3.0] - 2024-10-21

### Added

* New Dashboard home page that visualizes data for the state of the gateway network
- New Dashboard home page that visualizes data for the state of the gateway network

## [1.2.0] - 2024-10-17

### Added

* “Reported On” and “Reported On By” cards on Gateway Details page for viewing observation status by epoch for a gateway
* “Software” card on gateway details page that shows gateway software version and available bundlers (if gateway has listed them)
- “Reported On” and “Reported On By” cards on Gateway Details page for viewing observation status by epoch for a gateway
- “Software” card on gateway details page that shows gateway software version and available bundlers (if gateway has listed them)

### Changed

* Updated Gateway Details page for leaving gateways to hide non-relevant cards and show leave date

- Updated Gateway Details page for leaving gateways to hide non-relevant cards and show leave date

## [1.1.0] - 2024-10-08

### Added

* Gateways > Reports: Add “AR.IOEpoch #” Column
* Gateways>Reports>Individual Reports
* Add Epoch #
* Remove Epoch start height
* Implemented Leave Network Flow:
* Adds button to Gateway Detail page to leave network when gateway shown is the user’s own gateway
* Hitting Leave shows a modal with information. User has to type “LEAVE NETWORK” before Leave Network button is enabled.
* Hitting Leave Network button initiates signature request and then a success message.
* Site is refreshed after leaving.
* Release version shown on sidebar

- Gateways > Reports: Add “AR.IOEpoch #” Column
- Gateways>Reports>Individual Reports
- Add Epoch #
- Remove Epoch start height
- Implemented Leave Network Flow:
- Adds button to Gateway Detail page to leave network when gateway shown is the user’s own gateway
- Hitting Leave shows a modal with information. User has to type “LEAVE NETWORK” before Leave Network button is enabled.
- Hitting Leave Network button initiates signature request and then a success message.
- Site is refreshed after leaving.
- Release version shown on sidebar

### Changed

* Gateway Details: rename “Reward Ratios” to “Performance Ratios”
* Gateway Details: Fixes text bubble cut off when copying wallet address
- Gateway Details: rename “Reward Ratios” to “Performance Ratios”
- Gateway Details: Fixes text bubble cut off when copying wallet address

### Fixed

* Gateway Details: Remove Edit and Stake Buttons from gateways that are leaving
- Gateway Details: Remove Edit and Stake Buttons from gateways that are leaving

## [1.0.0]

* Initial versions of application; version was bumped to 1.1.0 for first public versioned release.
- Initial versions of application; version was bumped to 1.1.0 for first public versioned release.
210 changes: 210 additions & 0 deletions src/components/GatewaySelector.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
import { AoGatewayWithAddress, mARIOToken } from '@ar.io/sdk/web';
import { EAY_TOOLTIP_FORMULA, EAY_TOOLTIP_TEXT } from '@src/constants';
import useGateways from '@src/hooks/useGateways';
import useProtocolBalance from '@src/hooks/useProtocolBalance';
import { useGlobalState } from '@src/store';
import { formatAddress, formatPercentage, formatWithCommas } from '@src/utils';
import { calculateGatewayRewards } from '@src/utils/rewards';
import { ColumnDef, createColumnHelper } from '@tanstack/react-table';
import { MathJax } from 'better-react-mathjax';
import { InfoIcon, SearchIcon } from 'lucide-react';
import { useEffect, useState } from 'react';
import Button, { ButtonType } from './Button';
import BaseModal from './modals/BaseModal';
import TableView from './TableView';
import Tooltip from './Tooltip';

export type GatewaySelectorProps = {
selectedGateway?: AoGatewayWithAddress;
setSelectedGateway: (gateway: AoGatewayWithAddress) => void;
gateways?: AoGatewayWithAddress[];
};

interface TableData {
label: string;
gateway: AoGatewayWithAddress;
rewardShareRatio: number;
totalStake: number;
eay: number;
}

const columnHelper = createColumnHelper<TableData>();

const GatewaySelectorModal = ({
gateways,
onClose,
onGatewaySelected,
}: {
gateways: AoGatewayWithAddress[];
onClose: () => void;
onGatewaySelected: (gateway: AoGatewayWithAddress) => void;
}) => {
const ticker = useGlobalState((state) => state.ticker);
const [tableData, setTableData] = useState<TableData[]>([]);

const { data: prototocolBalance } = useProtocolBalance();
const { data: totalGateways } = useGateways();

const [searchText, setSearchText] = useState<string>();

useEffect(() => {
if (prototocolBalance && totalGateways && gateways) {
const tableData: TableData[] = gateways.map((gateway) => {
return {
gateway,
label: gateway.settings.label,
rewardShareRatio: gateway.settings.delegateRewardShareRatio,
totalStake: gateway.totalDelegatedStake,
eay: calculateGatewayRewards(
new mARIOToken(prototocolBalance).toARIO(),
Object.values(totalGateways).filter((g) => g.status == 'joined')
.length,
gateway,
).EAY,
};
});
if (searchText && searchText.length > 0) {
const filteredData = tableData.filter((data) => {
return (
data.label.toLowerCase().includes(searchText.toLowerCase()) ||
data.gateway.settings.fqdn
.toLowerCase()
.includes(searchText.toLowerCase()) ||
data.gateway.gatewayAddress
.toLowerCase()
.includes(searchText.toLowerCase())
);
});
setTableData(filteredData);
} else {
setTableData(tableData);
}
}
}, [totalGateways, gateways, prototocolBalance, searchText]);

// Define columns for the table
const columns: ColumnDef<TableData, any>[] = [
columnHelper.accessor('label', {
id: 'label',
header: 'Gateway',
sortDescFirst: true,
cell: ({ row }) => (
<div className="flex flex-col text-left">
<div className="text-sm text-high">{row.original.label}</div>
<div className="text-xs">
{formatAddress(row.original.gateway.gatewayAddress)}
</div>
</div>
),
}),
columnHelper.accessor('rewardShareRatio', {
id: 'rewardShareRatioe',
header: 'Reward Share',
sortDescFirst: true,
cell: ({ row }) => formatPercentage(row.original.rewardShareRatio / 100),
}),
columnHelper.accessor('totalStake', {
id: 'totalStake',
header: 'Total Stake',
sortDescFirst: true,
cell: ({ row }) =>
`${formatWithCommas(row.original.totalStake)} ${ticker}`,
}),
columnHelper.accessor('eay', {
id: 'eay',
header: () => (
<div className="flex gap-1">
EAY
<Tooltip
message={
<div>
<p>{EAY_TOOLTIP_TEXT}</p>
<MathJax className="mt-4">{EAY_TOOLTIP_FORMULA}</MathJax>
</div>
}
>
<InfoIcon className="h-4" />
</Tooltip>
</div>
),
sortDescFirst: true,
cell: ({ row }) => (
<div>
{row.original.eay < 0
? 'N/A'
: `${formatWithCommas(row.original.eay * 100)}%`}
</div>
),
}),
];

return (
<BaseModal onClose={onClose} showCloseButton={false} closeOnClickOutside>
<div className="w-[48rem] overflow-hidden rounded-xl border border-grey-500 text-left">
<div className="flex items-center rounded-t-xl border border-grey-500 px-6 py-2">
<SearchIcon className="size-4 text-mid" />
<input
type="text"
placeholder="Enter label, domain, or address"
className="grow bg-transparent px-3 py-2 text-sm text-high placeholder:text-low focus:outline-none"
value={searchText ?? ''}
onChange={(e) => setSearchText(e.target.value)}
/>
</div>
<TableView
columns={columns}
data={tableData}
onRowClick={(row) => {
onGatewaySelected(row.gateway);
onClose();
}}
defaultSortingState={{ id: 'label', desc: false }}
isLoading={false}
noDataFoundText="No gateways found."
shortTable={true}
/>
</div>
</BaseModal>
);
};

const GatewaySelector = ({
selectedGateway,
setSelectedGateway,
gateways,
}: GatewaySelectorProps) => {
const [showGatewaySelectorTable, setShowGatewaySelectorTable] =
useState(false);

return (
<div className="flex items-center rounded border border-grey-500 p-2 pl-6 text-left text-sm text-mid">
<div className="grow">
{!gateways
? 'Loading Gateways...'
: selectedGateway
? formatAddress(selectedGateway.gatewayAddress)
: ''}
</div>

<div className={gateways ? undefined : 'pointer-events-none opacity-30'}>
<Button
buttonType={ButtonType.SECONDARY}
className="max-h-7 text-mid"
active={true}
title="Choose Gateway"
text="Choose Gateway"
onClick={() => setShowGatewaySelectorTable(true)}
/>
</div>
{showGatewaySelectorTable && gateways && (
<GatewaySelectorModal
gateways={gateways}
onClose={() => setShowGatewaySelectorTable(false)}
onGatewaySelected={setSelectedGateway}
/>
)}
</div>
);
};

export default GatewaySelector;
Loading

0 comments on commit ba69db9

Please sign in to comment.