generated from Borodutch/frontend-starter
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add fetchOlderTickets function and OlderTickets component
- Loading branch information
1 parent
185bafc
commit d4e0133
Showing
7 changed files
with
243 additions
and
2 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import { atom } from 'jotai' | ||
|
||
export default atom<Promise<bigint> | null>(null) |
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
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,73 @@ | ||
import { Spam__factory } from '@borodutch/spam-contract' | ||
import { useAccount } from 'wagmi' | ||
import { useAtomValue, useSetAtom } from 'jotai' | ||
import { useEffect } from 'preact/hooks' | ||
import { useEthersSigner } from 'hooks/useEthers' | ||
import OlderTicket from 'models/OlderTicket' | ||
import SuspenseWithError from 'components/SuspenseWithError' | ||
import TicketClaimButton from 'components/TicketClaimButton' | ||
import env from 'helpers/env' | ||
import getDateString from 'helpers/getDateString' | ||
import lastClaimedTimestampAtom from 'atoms/lastClaimedTimestamp' | ||
|
||
function OlderTicketsSuspended({ tickets }: { tickets: OlderTicket[] }) { | ||
const lastClaimedTimestamp = useAtomValue(lastClaimedTimestampAtom) | ||
return ( | ||
<> | ||
<p> | ||
{lastClaimedTimestamp | ||
? `The last time you've claimed spam was at ${getDateString( | ||
lastClaimedTimestamp | ||
)}.` | ||
: "You haven't claimed $SPAM yet!"} | ||
</p> | ||
<div class="overflow-x-auto"> | ||
<table class="table table-zebra"> | ||
<thead> | ||
<tr> | ||
<th>From</th> | ||
<th>To</th> | ||
<th>Amount</th> | ||
</tr> | ||
</thead> | ||
<tbody> | ||
{tickets.map((ticket) => ( | ||
<tr id={ticket.signature}> | ||
<td>{getDateString(ticket.fromDate)}</td> | ||
<td>{getDateString(ticket.toDate)}</td> | ||
<td>{ticket.total}</td> | ||
<td> | ||
<TicketClaimButton ticket={ticket} /> | ||
</td> | ||
</tr> | ||
))} | ||
</tbody> | ||
</table> | ||
</div> | ||
</> | ||
) | ||
} | ||
|
||
export default function ({ tickets }: { tickets: OlderTicket[] }) { | ||
const { address } = useAccount() | ||
const signer = useEthersSigner() | ||
|
||
if (!address || !signer) { | ||
return <p>Doesn't look like there is an address connected!</p> | ||
} | ||
const setLastClaimedTimestamp = useSetAtom(lastClaimedTimestampAtom) | ||
useEffect(() => { | ||
if (!address) { | ||
setLastClaimedTimestamp(null) | ||
return | ||
} | ||
const bigintAddress = BigInt(address) | ||
const contract = Spam__factory.connect(env.VITE_CONTRACT, signer) | ||
setLastClaimedTimestamp(contract.lastClaimTimestamps(bigintAddress, 0n)) | ||
}, [address, setLastClaimedTimestamp, signer]) | ||
return ( | ||
<SuspenseWithError errorText="Failed to load last claim date"> | ||
<OlderTicketsSuspended tickets={tickets} /> | ||
</SuspenseWithError> | ||
) | ||
} |
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,90 @@ | ||
import { Spam__factory } from '@borodutch/spam-contract' | ||
import { ethers } from 'ethers' | ||
import { useAccount } from 'wagmi' | ||
import { useAtomValue, useSetAtom } from 'jotai' | ||
import { useEthersSigner } from 'hooks/useEthers' | ||
import { useState } from 'preact/hooks' | ||
import OlderTicket from 'models/OlderTicket' | ||
import env from 'helpers/env' | ||
import lastClaimedTimestampAtom from 'atoms/lastClaimedTimestamp' | ||
|
||
function evenPad(value: string) { | ||
return value.length % 2 === 0 ? value : `0${value}` | ||
} | ||
|
||
function turnIntoBytes(value: bigint) { | ||
return ethers.getBytes( | ||
ethers.zeroPadValue(`0x${evenPad(value.toString(16))}`, 32) | ||
) | ||
} | ||
|
||
export default function ({ | ||
ticket, | ||
}: { | ||
ticket: OlderTicket | ||
refreshClaimTimestamp: () => void | ||
}) { | ||
const [loading, setLoading] = useState(false) | ||
const { address } = useAccount() | ||
const signer = useEthersSigner() | ||
const setLastClaimedTimestamp = useSetAtom(lastClaimedTimestampAtom) | ||
|
||
async function claimSpam() { | ||
setLoading(true) | ||
try { | ||
if (!ticket) { | ||
throw new Error('No ticket found') | ||
} | ||
if (!address) { | ||
throw new Error('No address found') | ||
} | ||
const contract = Spam__factory.connect(env.VITE_CONTRACT, signer) | ||
const { r, yParityAndS } = ethers.Signature.from(ticket.signature) | ||
const spammerBytes = turnIntoBytes(BigInt(address)) | ||
const ticketTypeBytes = turnIntoBytes(0n) | ||
const spamAmountBytes = turnIntoBytes( | ||
ethers.parseEther(`${ticket.total}`) | ||
) | ||
const fromTimestampBytes = turnIntoBytes( | ||
BigInt(new Date(ticket.fromDate).getTime()) | ||
) | ||
const toTimestampBytes = turnIntoBytes( | ||
BigInt(new Date(ticket.toDate).getTime()) | ||
) | ||
const message = [ | ||
...spammerBytes, | ||
...ticketTypeBytes, | ||
...spamAmountBytes, | ||
...fromTimestampBytes, | ||
...toTimestampBytes, | ||
] | ||
const tx = await contract.claimSpam( | ||
new Uint8Array(message), | ||
r, | ||
yParityAndS | ||
) | ||
await tx.wait() | ||
const bigintAddress = BigInt(address) | ||
setLastClaimedTimestamp(contract.lastClaimTimestamps(bigintAddress, 0n)) | ||
} catch (error) { | ||
console.error(error) | ||
} finally { | ||
setLoading(false) | ||
} | ||
} | ||
|
||
const lastClaimedTimestamp = useAtomValue(lastClaimedTimestampAtom) | ||
const disabled = | ||
!!lastClaimedTimestamp && | ||
new Date(Number(lastClaimedTimestamp)).getTime() > | ||
new Date(ticket.fromDate).getTime() | ||
return ( | ||
<button | ||
class="btn btn-primary btn-xs" | ||
disabled={disabled || loading} | ||
onClick={claimSpam} | ||
> | ||
{loading && '🤔 '}Claim! | ||
</button> | ||
) | ||
} |
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
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,9 @@ | ||
export default function (date: Date | string | bigint) { | ||
if (typeof date === 'bigint') { | ||
date = new Date(Number(date)) | ||
} | ||
if (typeof date === 'string') { | ||
date = new Date(date) | ||
} | ||
return date.toLocaleString() | ||
} |
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,13 @@ | ||
interface OlderTicket { | ||
address: string | ||
signature: string | ||
ticketType: number | ||
fromDate: string | ||
toDate: string | ||
baseAmount: number | ||
additionalForLikes: number | ||
additionalForRecasts: number | ||
total: number | ||
createdAt: string | ||
} | ||
export default OlderTicket |