-
-
Notifications
You must be signed in to change notification settings - Fork 242
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/master' into web-vitals
- Loading branch information
Showing
36 changed files
with
1,347 additions
and
460 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
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 |
---|---|---|
|
@@ -11,7 +11,7 @@ If you want to learn more about (unlimited) token approvals, I wrote an article | |
## Running locally | ||
|
||
``` | ||
git clone [email protected]:rkalis/revoke.cash.git | ||
git clone [email protected]:RevokeCash/revoke.cash.git | ||
cd revoke.cash | ||
yarn | ||
yarn dev | ||
|
@@ -51,11 +51,11 @@ Adding a new network is relatively straightforward as you only need to change th | |
|
||
#### Prerequisites | ||
|
||
To add a new network, one of the following needs to be available: | ||
To add a new network, **one** of the following needs to be available: | ||
|
||
- A (public or private) RPC endpoint that supports `eth_getLogs` requests for the entire history of the network. | ||
- Support in [CovalentHQ](https://www.covalenthq.com/) for the network. | ||
- A block explorer with an exposed API that is compatible with Etherscan's API (such as Blockscout). | ||
- Or: Support in [CovalentHQ](https://www.covalenthq.com/) for the network. | ||
- Or: A block explorer with an exposed API that is compatible with Etherscan's API (such as Blockscout). | ||
|
||
Also make sure that your network is listed in [ethereum-lists/chains](https://github.com/ethereum-lists/chains) (and that it has subsequently been included in [@revoke.cash/chains](https://github.com/RevokeCash/chains)). Besides the earlier requirements, we also require a publicly available RPC endpoint with rate limits that are not too restrictive. It is also helpful if your network is listed (with TVL and volume stats) on DeFiLlama, but this is not required. | ||
|
||
|
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,206 @@ | ||
'use client'; | ||
|
||
import ContentPageLayout from 'app/layouts/ContentPageLayout'; | ||
import Button from 'components/common/Button'; | ||
import Input from 'components/common/Input'; | ||
import { displayTransactionSubmittedToast } from 'components/common/TransactionSubmittedToast'; | ||
import Select from 'components/common/select/Select'; | ||
import { ERC20_ABI, ERC721_ABI } from 'lib/abis'; | ||
import { writeContractUnlessExcessiveGas } from 'lib/utils'; | ||
import { AllowanceType } from 'lib/utils/allowances'; | ||
import { parseErrorMessage } from 'lib/utils/errors'; | ||
import { permit2Approve } from 'lib/utils/permit2'; | ||
import { useState } from 'react'; | ||
import { toast } from 'react-toastify'; | ||
import { isAddress } from 'viem'; | ||
import { useAccount, usePublicClient } from 'wagmi'; | ||
import { useWalletClient } from 'wagmi'; | ||
|
||
const ApprovePage = () => { | ||
const { data: walletClient } = useWalletClient(); | ||
const { address: account } = useAccount(); | ||
const publicClient = usePublicClient()!; | ||
const [allowanceType, setAllowanceType] = useState<AllowanceType>(AllowanceType.ERC20); | ||
const [tokenAddress, setTokenAddress] = useState<string>(''); | ||
const [spenderAddress, setSpenderAddress] = useState<string>(''); | ||
const [permit2Address, setPermit2Address] = useState<string>(''); | ||
const [amount, setAmount] = useState<string>(''); | ||
const [tokenId, setTokenId] = useState<string>(''); | ||
const [expiration, setExpiration] = useState<string>(''); | ||
const options = Object.values(AllowanceType).map((type) => ({ value: type, label: type })); | ||
|
||
const handleApprove = async () => { | ||
try { | ||
if (!tokenAddress || !spenderAddress) { | ||
throw new Error('Token address and spender address are required'); | ||
} | ||
|
||
if (allowanceType === AllowanceType.ERC721_SINGLE && !tokenId) { | ||
throw new Error('Token ID is required'); | ||
} | ||
|
||
if (allowanceType === AllowanceType.PERMIT2 && (!permit2Address || !expiration || !isAddress(permit2Address))) { | ||
throw new Error('Permit2 address and expiration are required'); | ||
} | ||
|
||
if (!isAddress(tokenAddress) || !isAddress(spenderAddress)) { | ||
throw new Error('Invalid address'); | ||
} | ||
|
||
switch (allowanceType) { | ||
case AllowanceType.ERC20: { | ||
if (!amount) { | ||
throw new Error('Amount is required'); | ||
} | ||
|
||
const tx = await writeContractUnlessExcessiveGas(publicClient, walletClient!, { | ||
address: tokenAddress, | ||
account: account!, | ||
chain: walletClient!.chain!, | ||
abi: ERC20_ABI, | ||
functionName: 'approve', | ||
args: [spenderAddress, BigInt(amount)], | ||
}); | ||
|
||
displayTransactionSubmittedToast(walletClient!.chain!.id, tx); | ||
break; | ||
} | ||
case AllowanceType.PERMIT2: { | ||
if (!amount || !expiration || !permit2Address || !isAddress(permit2Address)) { | ||
throw new Error('Amount, expiration, and permit2 address are required'); | ||
} | ||
|
||
const tokenContract = { | ||
address: tokenAddress, | ||
publicClient, | ||
abi: ERC20_ABI, | ||
}; | ||
|
||
const tx = await permit2Approve( | ||
permit2Address, | ||
walletClient!, | ||
tokenContract, | ||
spenderAddress, | ||
BigInt(amount), | ||
Number(expiration), | ||
); | ||
|
||
displayTransactionSubmittedToast(walletClient!.chain!.id, tx); | ||
break; | ||
} | ||
case AllowanceType.ERC721_SINGLE: { | ||
if (!tokenId) { | ||
throw new Error('Token ID is required'); | ||
} | ||
|
||
const tx = await writeContractUnlessExcessiveGas(publicClient, walletClient!, { | ||
address: tokenAddress, | ||
account: account!, | ||
chain: walletClient!.chain!, | ||
abi: ERC721_ABI, | ||
functionName: 'approve', | ||
args: [spenderAddress, BigInt(tokenId)], | ||
}); | ||
|
||
displayTransactionSubmittedToast(walletClient!.chain!.id, tx); | ||
break; | ||
} | ||
case AllowanceType.ERC721_ALL: { | ||
const tx = await writeContractUnlessExcessiveGas(publicClient, walletClient!, { | ||
address: tokenAddress, | ||
account: account!, | ||
chain: walletClient!.chain!, | ||
abi: ERC721_ABI, | ||
functionName: 'setApprovalForAll', | ||
args: [spenderAddress, true], | ||
}); | ||
|
||
displayTransactionSubmittedToast(walletClient!.chain!.id, tx); | ||
break; | ||
} | ||
} | ||
} catch (e) { | ||
toast.error(e instanceof Error ? parseErrorMessage(e) : 'An error occurred'); | ||
} | ||
}; | ||
|
||
return ( | ||
<ContentPageLayout> | ||
<div className="flex flex-col gap-4 max-w-3xl mx-auto"> | ||
<h1>Approve Arbitrary Contracts</h1> | ||
<p>For testing purposes only.</p> | ||
<div className="flex flex-col gap-4 border border-gray-200 rounded-md p-4"> | ||
<div className="flex flex-col gap-1"> | ||
<span>Approval Type</span> | ||
<Select | ||
instanceId="approval-type-select" | ||
aria-label="Select Approval Type" | ||
options={options} | ||
value={options.find((option) => option.value === allowanceType)} | ||
onChange={(value) => setAllowanceType(value?.value as AllowanceType)} | ||
isMulti={false} | ||
isSearchable={false} | ||
/> | ||
</div> | ||
<div className="flex flex-col gap-1"> | ||
<span>Token Address</span> | ||
<Input | ||
size="md" | ||
placeholder="Token Address" | ||
value={tokenAddress} | ||
onChange={(e) => setTokenAddress(e.target.value)} | ||
/> | ||
</div> | ||
<div className="flex flex-col gap-1"> | ||
<span>Spender Address</span> | ||
<Input | ||
size="md" | ||
placeholder="Spender Address" | ||
value={spenderAddress} | ||
onChange={(e) => setSpenderAddress(e.target.value)} | ||
/> | ||
</div> | ||
{allowanceType === AllowanceType.PERMIT2 && ( | ||
<div className="flex flex-col gap-1"> | ||
<span>Permit2 Address</span> | ||
<Input | ||
size="md" | ||
placeholder="Permit2 Address" | ||
value={permit2Address} | ||
onChange={(e) => setPermit2Address(e.target.value)} | ||
/> | ||
</div> | ||
)} | ||
{(allowanceType === AllowanceType.ERC20 || allowanceType === AllowanceType.PERMIT2) && ( | ||
<div className="flex flex-col gap-1"> | ||
<span>Amount</span> | ||
<Input size="md" placeholder="Amount" value={amount} onChange={(e) => setAmount(e.target.value)} /> | ||
</div> | ||
)} | ||
{allowanceType === AllowanceType.ERC721_SINGLE && ( | ||
<div className="flex flex-col gap-1"> | ||
<span>Token ID</span> | ||
<Input size="md" placeholder="Token ID" value={tokenId} onChange={(e) => setTokenId(e.target.value)} /> | ||
</div> | ||
)} | ||
{allowanceType === AllowanceType.PERMIT2 && ( | ||
<div className="flex flex-col gap-1"> | ||
<span>Expiration</span> | ||
<Input | ||
size="md" | ||
placeholder="Expiration" | ||
value={expiration} | ||
onChange={(e) => setExpiration(e.target.value)} | ||
/> | ||
</div> | ||
)} | ||
</div> | ||
<Button size="md" style="secondary" onClick={handleApprove}> | ||
Approve | ||
</Button> | ||
</div> | ||
</ContentPageLayout> | ||
); | ||
}; | ||
|
||
export default ApprovePage; |
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 |
---|---|---|
@@ -1,4 +1,5 @@ | ||
User-agent: * | ||
Allow: / | ||
Disallow: /private/ | ||
|
||
Sitemap: https://revoke.cash/sitemap.xml |
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
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 @@ | ||
Close to $2.5m was stolen from DeFi platform Moby Trade and its users. The attacker was able to gain access to the protocol's admin keys, which they used to execute malicious upgrades on the protocol's contracts - allowing them to drain the wallets of any users that had active token approvals for the protocol. Close to $1.5m was recovered by the protocol's team and SEAL911, resulting in a loss of $1m for the users. |
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
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
Oops, something went wrong.