Skip to content
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

feat: add correct wrapped subname tags + expiry date #298

Merged
merged 16 commits into from
Feb 16, 2023
Merged
2 changes: 1 addition & 1 deletion deploy/.utils/nonceManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const nonceManager =

for (let i = 0; i < namesWithAccount.length; i += 1) {
const data = namesWithAccount[i]
usedNonces += await func(newNonceMap[account])(data, i)
usedNonces += await func(newNonceMap[account])(data, usedNonces)
}
newNonceMap[account] += usedNonces
}
Expand Down
6 changes: 6 additions & 0 deletions deploy/00_register_legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,12 @@ const names: Name[] = [
namedAddr: 'owner',
namedController: 'deployer',
},
{
label: 'other-registrant-2',
namedOwner: 'deployer',
namedAddr: 'deployer',
namedController: 'owner',
},
{
label: 'migrated-resolver-to-be-updated',
namedOwner: 'owner',
Expand Down
80 changes: 65 additions & 15 deletions deploy/00_register_wrapped.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { DeployFunction } from 'hardhat-deploy/types'
import { HardhatRuntimeEnvironment } from 'hardhat/types'

import { PublicResolver__factory } from '@ensdomains/ensjs/generated/factories/PublicResolver__factory'
import { CombinedFuseInput, encodeFuses } from '@ensdomains/ensjs/utils/fuses'
import { namehash } from '@ensdomains/ensjs/utils/normalise'
import { RecordOptions } from '@ensdomains/ensjs/utils/recordHelpers'
import {
Expand All @@ -21,19 +22,13 @@ type Name = {
namedOwner: string
reverseRecord?: boolean
records?: RecordOptions
fuses?: {
cannotUnwrap: true
cannotBurnFuses?: boolean
cannotTransfer?: boolean
cannotSetResolver?: boolean
cannotSetTtl?: boolean
cannotCreateSubdomain?: boolean
parentCannotControl?: boolean
}
fuses?: CombinedFuseInput['child']
customDuration?: number
subnames?: {
label: string
namedOwner: string
fuses?: number
expiry?: number
}[]
}

Expand All @@ -55,6 +50,58 @@ const names: Name[] = [
{ label: 'xyz', namedOwner: 'deployer' },
],
},
{
name: 'wrapped-expired-subnames.eth',
namedOwner: 'owner',
fuses: {
named: ['CANNOT_UNWRAP'],
},
subnames: [
{
label: 'day-expired',
namedOwner: 'owner',
// set expiry to 24 hours ago
expiry: Math.floor(Date.now() / 1000) - 86400,
fuses: encodeFuses({ parent: { named: ['PARENT_CANNOT_CONTROL'] } }),
},
{
label: 'hour-expired',
namedOwner: 'owner',
// set expiry to 24 hours ago
expiry: Math.floor(Date.now() / 1000) - 3600,
fuses: encodeFuses({ parent: { named: ['PARENT_CANNOT_CONTROL'] } }),
},
{
label: 'two-minute-expired',
namedOwner: 'owner',
expiry: Math.floor(Date.now() / 1000) - 120,
fuses: encodeFuses({ parent: { named: ['PARENT_CANNOT_CONTROL'] } }),
},
{
label: 'two-minute-expiring',
namedOwner: 'owner',
expiry: Math.floor(Date.now() / 1000) + 120,
fuses: encodeFuses({ parent: { named: ['PARENT_CANNOT_CONTROL'] } }),
},
{
label: 'hour-expiring',
namedOwner: 'owner',
// set expiry to 24 hours ago
expiry: Math.floor(Date.now() / 1000) + 3600,
fuses: encodeFuses({ parent: { named: ['PARENT_CANNOT_CONTROL'] } }),
},
{
label: 'no-pcc',
namedOwner: 'owner',
expiry: Math.floor(Date.now() / 1000) - 86400,
},
{
label: 'not-expired',
namedOwner: 'owner',
fuses: encodeFuses({ parent: { named: ['PARENT_CANNOT_CONTROL'] } }),
},
],
},
]

type ProcessedNameData = RegistrationParams & {
Expand All @@ -79,12 +126,14 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
const owner = allNamedAccts[namedOwner]

const processedSubnames: ProcessedSubname[] =
subnames?.map(({ label, namedOwner: subNamedOwner }) => ({
label,
owner: allNamedAccts[subNamedOwner],
expiry: wrapperExpiry,
fuses: 0,
})) || []
subnames?.map(
({ label, namedOwner: subNamedOwner, fuses: subnameFuses, expiry: subnameExpiry }) => ({
label,
owner: allNamedAccts[subNamedOwner],
expiry: subnameExpiry || wrapperExpiry,
fuses: subnameFuses || 0,
}),
) || []

return {
resolver,
Expand All @@ -94,6 +143,7 @@ const func: DeployFunction = async function (hre: HardhatRuntimeEnvironment) {
name,
label: name.split('.')[0],
subnames: processedSubnames,
fuses: fuses || undefined,
...rest,
}
}
Expand Down
2 changes: 1 addition & 1 deletion e2e/specs/stateless/12_updateResolver.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { acceptMetamaskAccess } from '../../setup'

const newResolver = '0x70e0bA845a1A0F2DA3359C97E0285013525FFC49'
const newResolver = '0x0E801D84Fa97b50751Dbf25036d067dCf18858bF'
const oldResolver = '0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB'

describe('Update Resolver', () => {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@
"@cloudflare/workers-types": "^3.14.1",
"@deploysentinel/cypress-debugger": "^0.5.5",
"@ensdomains/buffer": "^0.1.0",
"@ensdomains/ens-test-env": "^0.3.6",
"@ensdomains/ens-test-env": "^0.3.7",
"@ethersproject/wallet": "^5.7.0",
"@next/bundle-analyzer": "^12.2.5",
"@next/swc-linux-x64-gnu": "12.1.4",
Expand Down Expand Up @@ -214,4 +214,4 @@
"@synthetixio/synpress@3.0.5": "patches/@synthetixio__synpress@3.0.5.patch"
}
}
}
}
14 changes: 7 additions & 7 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
"controller": "Controller",
"dnsOwner": "DNS Owner",
"owner": "Owner",
"notOwned": "Not Owned",
"manager": "Manager",
"all": "All Names",
"expiresInYears_one": "Expires in {{count}} year",
Expand All @@ -90,6 +91,18 @@
"expiresInMonths_other": "Expires in {{count}} months",
"expiresInDays_one": "Expires in {{count}} day",
"expiresInDays_other": "Expires in {{count}} days",
"expiresInHours_one": "Expires in {{count}} hour",
"expiresInHours_other": "Expires in {{count}} hours",
"expiresInHours_zero": "Expires in less than an hour",
"expiredInHours_one": "Expired {{count}} hour ago",
"expiredInHours_other": "Expired {{count}} hours ago",
"expiredInHours_zero": "Expired less than an hour ago",
"expiredInDays_one": "Expired {{count}} day ago",
"expiredInDays_other": "Expired {{count}} days ago",
"expiredInMonths_one": "Expired {{count}} month ago",
"expiredInMonths_other": "Expired {{count}} months ago",
"expiredInYears_one": "Expired {{count}} year ago",
"expiredInYears_other": "Expired {{count}} years ago",
"extend": "Extend",
"send": "Send",
"transfer": "Transfer",
Expand Down
26 changes: 25 additions & 1 deletion src/components/@atoms/ExpiryComponents/ExpiryComponents.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ jest.mock('@app/hooks/useBlockTimestamp', () => ({
const twoYearExpiry = new Date(Date.now() + 1000 * 60 * 60 * 24 * 366 * 2)
const yearExpiry = new Date(Date.now() + 1000 * 60 * 60 * 24 * 365)
const monthExpiry = new Date(Date.now() + 1000 * 60 * 60 * 24 * 30)
const expired = new Date(Date.now() - 1)
const lessThanHourExpired = new Date(Date.now() - 1000 * 60 * 60 * 0.5)
const hourExpired = new Date(Date.now() - 1000 * 60 * 60 * 23)
const expired = new Date(Date.now() - 1000 * 60 * 60 * 24)
const yearExpired = new Date(Date.now() - 1000 * 60 * 60 * 24 * 365)

describe('ExpiryClock', () => {
it('should be grey if expiry is more than 90 days away', () => {
Expand Down Expand Up @@ -55,4 +58,25 @@ describe('ShortExpiry', () => {
render(<ShortExpiry expiry={monthExpiry} />)
expect(screen.getByText('name.expiresInDays.29')).toBeVisible()
})
it('should inverse numbers if expired', () => {
render(<ShortExpiry expiry={expired} />)
expect(screen.getByText('name.expiredInDays.1')).toBeVisible()
})
it('should not inverse numbers if expired for less than 90 days and has grace period', () => {
render(<ShortExpiry expiry={expired} hasGracePeriod />)
expect(screen.getByText('name.expiresInDays.88')).toBeVisible()
})
it('should always show red text for inversed numbers', () => {
render(<ShortExpiry expiry={yearExpired} />)
expect(screen.getByText('name.expiredInYears.1')).toBeVisible()
expect(screen.getByText('name.expiredInYears.1')).toHaveAttribute('data-color', 'red')
})
it('should show hours if difference is less than 24 hours', () => {
render(<ShortExpiry expiry={hourExpired} />)
expect(screen.getByText('name.expiredInHours.23')).toBeVisible()
})
it('should show less than an hour if difference is less than 1 hour', () => {
render(<ShortExpiry expiry={lessThanHourExpired} />)
expect(screen.getByText('name.expiredInHours')).toBeVisible()
})
})
42 changes: 31 additions & 11 deletions src/components/@atoms/ExpiryComponents/ExpiryComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import styled, { css } from 'styled-components'
import { Typography } from '@ensdomains/thorin'

import ClockSVG from '@app/assets/Clock.svg'
import { secondsToDays } from '@app/utils/utils'
import { daysToSeconds, secondsToDays, secondsToHours } from '@app/utils/utils'

import { useBlockTimestamp } from '../../../hooks/useBlockTimestamp'

Expand Down Expand Up @@ -50,38 +50,58 @@ export const ExpiryClock = ({ expiry }: { expiry: Date }) => {
return <ClockIcon data-testid="expiry-clock-grey" $color="grey" as={ClockSVG} />
}

export const ShortExpiry = ({ expiry, textOnly = false }: { expiry: Date; textOnly?: boolean }) => {
export const ShortExpiry = ({
expiry,
textOnly = false,
hasGracePeriod,
}: {
expiry: Date
textOnly?: boolean
hasGracePeriod?: boolean
}) => {
const { t } = useTranslation()
const blockTimestamp = useBlockTimestamp()
const currentDate = new Date(blockTimestamp.data!)
const difference = secondsToDays((expiry.getTime() - currentDate.getTime()) / 1000)
let secondsDiff = (expiry.getTime() - currentDate.getTime()) / 1000
const inverse =
(!hasGracePeriod && secondsDiff < 0) || (hasGracePeriod && secondsDiff < -daysToSeconds(90))
if (inverse) secondsDiff = -secondsDiff
let difference = secondsToDays(secondsDiff)

const months = Math.floor(difference / 30)
const years = Math.floor(difference / 365)
const transPrefix = inverse ? 'name.expired' : 'name.expires'

let text = t('name.expiresInYears', { count: years })
let text = t(`${transPrefix}InYears`, { count: years })
let color: 'grey' | 'red' | 'orange' = 'grey'

if (difference < 0) {
text = t('name.expiresInDays', { count: difference + 90 })
if (difference === 0) {
difference = secondsToHours(secondsDiff)
text = t(`${transPrefix}InHours`, { count: difference })
color = 'red'
} else if (difference < 0) {
text = t(`${transPrefix}InDays`, { count: hasGracePeriod ? difference + 90 : difference })
color = 'red'
} else if (difference < 30) {
text = t('name.expiresInDays', { count: difference })
text = t(`${transPrefix}InDays`, { count: difference })
color = 'orange'
} else if (difference < 90) {
text = t('name.expiresInMonths', { count: months })
text = t(`${transPrefix}InMonths`, { count: months })
color = 'orange'
} else if (difference < 365) {
text = t('name.expiresInMonths', { count: months })
text = t(`${transPrefix}InMonths`, { count: months })
color = 'grey'
}

const processedColor = inverse ? 'red' : color

if (textOnly) return <>{text}</>
return (
<ExpiryText
data-testid="short-expiry"
data-color={color}
data-color={processedColor}
data-timestamp={expiry.getTime()}
$color={color}
$color={processedColor}
fontVariant="small"
>
{text}
Expand Down
3 changes: 2 additions & 1 deletion src/components/@atoms/NameDetailItem/NameDetailItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Avatar, mq } from '@ensdomains/thorin'
import CircleTick from '@app/assets/CircleTick.svg'
import { useAvatar } from '@app/hooks/useAvatar'
import { useZorb } from '@app/hooks/useZorb'
import { checkETH2LDFromName } from '@app/utils/utils'

import { ShortExpiry } from '../ExpiryComponents/ExpiryComponents'
import { OptionalLink } from '../OptionalLink/OptionalLink'
Expand Down Expand Up @@ -182,7 +183,7 @@ export const NameDetailItem = ({
<TitleWrapper name={truncatedName || name} disabled={disabled} />
{expiryDate && (
<SubtitleWrapper>
<ShortExpiry expiry={expiryDate} />
<ShortExpiry expiry={expiryDate} hasGracePeriod={checkETH2LDFromName(name)} />
</SubtitleWrapper>
)}
</NameItemContent>
Expand Down
Loading