diff --git a/airdrops/app/campaigns/[campaign]/page.tsx b/airdrops/app/campaigns/[campaign]/page.tsx index fbac828783e..b39283350a4 100644 --- a/airdrops/app/campaigns/[campaign]/page.tsx +++ b/airdrops/app/campaigns/[campaign]/page.tsx @@ -22,15 +22,15 @@ export async function generateMetadata({ } return { - title: `${campaign.title} | Airdrops`, + title: `${campaign.name} | Airdrops`, description: campaign.description, openGraph: { - title: `${campaign.title} | Airdrops`, + title: `${campaign.name} | Airdrops`, description: campaign.description, }, twitter: { card: 'summary', - title: `${campaign.title} | Airdrops`, + title: `${campaign.name} | Airdrops`, description: campaign.description, }, } diff --git a/airdrops/components/CampaignCard.tsx b/airdrops/components/CampaignCard.tsx index 5f9a2d47b5c..bcb643f6823 100644 --- a/airdrops/components/CampaignCard.tsx +++ b/airdrops/components/CampaignCard.tsx @@ -8,15 +8,15 @@ interface CampaignCardProps { } const CampaignCardInternal = ({ - airdrop: { title, description, eligible }, + airdrop: { name, description, eligible, contractAddress, url }, authenticated, }: CampaignCardProps) => { return (
-

{title}

+

{name}

{description}

- {authenticated && ( + {authenticated && contractAddress && ( <>
)} + {url && ( + + More info + + )}
) diff --git a/airdrops/components/CampaignDetailContent.tsx b/airdrops/components/CampaignDetailContent.tsx index 94303de7c43..c2e79755659 100644 --- a/airdrops/components/CampaignDetailContent.tsx +++ b/airdrops/components/CampaignDetailContent.tsx @@ -1,4 +1,5 @@ 'use client' +import { StandardMerkleTree } from '@openzeppelin/merkle-tree' import { ethers } from 'ethers' import { usePrivy, useWallets } from '@privy-io/react-auth' import { Container } from './layout/Container' @@ -9,6 +10,9 @@ import { BsArrowLeft as ArrowBackIcon } from 'react-icons/bs' import { ConnectButton } from './auth/ConnectButton' import { isEligible } from '../src/utils/eligibility' import { AirdropData } from './Campaigns' +import ReactMarkdown from 'react-markdown' +import { terms } from '../src/utils/terms' +import { UPAirdrops } from '@unlock-protocol/contracts' interface CampaignDetailContentProps { airdrop: AirdropData @@ -16,6 +20,25 @@ interface CampaignDetailContentProps { const timestamp = new Date().getTime() +const getContract = async (address: string, network: number) => { + const provider = new ethers.JsonRpcProvider( + `https://rpc.unlock-protocol.com/${network}` + ) + return new ethers.Contract(address, UPAirdrops.abi, provider) +} + +const getProof = async (address: string, airdrop: AirdropData) => { + const request = await fetch(airdrop.recipientsFile) + const tree = StandardMerkleTree.load(await request.json()) + for (const [i, leaf] of tree.entries()) { + if (leaf[0].toLowerCase() === address.toLowerCase()) { + const proof = tree.getProof(i) + return { leaf, proof } + } + } + return { leaf: null, proof: null } +} + export default function CampaignDetailContent({ airdrop, }: CampaignDetailContentProps) { @@ -25,11 +48,10 @@ export default function CampaignDetailContent({ useEffect(() => { const run = async () => { - const amount = await isEligible( - wallets[0].address, - airdrop.recipientsFile - ) - airdrop.eligible = amount || 0 + if (wallets[0]) { + const amount = await isEligible(wallets[0].address, airdrop) + airdrop.eligible = amount || 0 + } } run() }, [authenticated, wallets, airdrop]) @@ -40,13 +62,17 @@ export default function CampaignDetailContent({ const ethersProvider = new ethers.BrowserProvider(provider) const signer = await ethersProvider.getSigner() - await wallets[0].switchChain(8453) + await wallets[0].switchChain(airdrop.chainId) + const contract = await getContract( + airdrop.contractAddress, + airdrop.chainId + ) const domain = { - name: 'Airdrops', // await airdrops.EIP712Name(), - version: '1', // await airdrops.EIP712Version(), - chainId: 8453, - verifyingContract: '0x4200000000000000000000000000000000000011', // replace me + name: await contract.EIP712Name(), + version: await contract.EIP712Version(), + chainId: airdrop.chainId, + verifyingContract: airdrop.contractAddress, } const types = { @@ -59,7 +85,7 @@ export default function CampaignDetailContent({ const value = { signer: signer.address, - campaignName: airdrop.title, + campaignName: airdrop.name, timestamp, } @@ -70,6 +96,34 @@ export default function CampaignDetailContent({ } } + const onClaim = async () => { + const provider = await wallets[0].getEthereumProvider() + const ethersProvider = new ethers.BrowserProvider(provider) + const signer = await ethersProvider.getSigner() + + const airdropContract = await getContract( + airdrop.contractAddress, + airdrop.chainId + ) + + // Get the proof! + const { proof } = await getProof(wallets[0].address, airdrop) + console.log(proof) + + const tx = await airdropContract + .connect(signer) + // @ts-expect-error Property 'claim' does not exist on type 'BaseContract'.ts(2339) + .claim( + airdrop.name, + timestamp, + wallets[0].address, + airdrop.eligible, + proof, + termsOfServiceSignature + ) + await tx.wait() + } + return ( diff --git a/airdrops/components/Campaigns.tsx b/airdrops/components/Campaigns.tsx index 4ba0b53752b..d2204af04ae 100644 --- a/airdrops/components/Campaigns.tsx +++ b/airdrops/components/Campaigns.tsx @@ -11,13 +11,18 @@ import { CampaignCard } from './CampaignCard' export interface AirdropData { id: string - title: string + name: string description: string contractAddress?: string - tokenAmount: string - tokenSymbol: string - recipientsFile: string + token?: { + address: string + symbol: string + decimals: number + } + recipientsFile?: string eligible?: number + url?: string + chainId?: number } const CampaignsContent = () => { @@ -53,10 +58,7 @@ const CampaignsContent = () => { await Promise.all( (airdrops as AirdropData[]).map(async (drop) => { - const amount = await isEligible( - user.wallet.address, - drop.recipientsFile - ) + const amount = await isEligible(user.wallet.address, drop) drop.eligible = amount || 0 }) ) diff --git a/airdrops/package.json b/airdrops/package.json index f51a7341c96..e0d068159a8 100644 --- a/airdrops/package.json +++ b/airdrops/package.json @@ -8,10 +8,12 @@ }, "dependencies": { "@headlessui/react": "2.1.9", + "@openzeppelin/merkle-tree": "1.0.8", "@privy-io/react-auth": "2.2.1", "@sentry/nextjs": "8.54.0", "@tanstack/react-query": "5.59.19", "@tw-classed/react": "1.7.0", + "@unlock-protocol/contracts": "workspace:*", "@unlock-protocol/core": "workspace:./packages/core", "@unlock-protocol/crypto-icon": "workspace:./packages/crypto-icon", "@unlock-protocol/eslint-config": "workspace:./packages/eslint-config", @@ -26,6 +28,7 @@ "ethers": "6.13.5", "next": "14.2.21", "react-hot-toast": "2.4.1", + "react-markdown": "10.0.0", "tailwind-merge": "3.0.1", "typescript": "5.6.3" }, diff --git a/airdrops/src/airdrops.json b/airdrops/src/airdrops.json index 807c78d8f5d..317058814d9 100644 --- a/airdrops/src/airdrops.json +++ b/airdrops/src/airdrops.json @@ -1,19 +1,26 @@ [ { "id": "1", - "title": "UP Token Swap", + "name": "UP Token Swap", "description": "The Unlock DAO migration to Base is complete, and the UP token swap reward airdrop, totaling 1.061 million UP tokens, is now live for all eligible participants.", - "tokenAmount": "1061000", - "tokenSymbol": "UP", - "recipientsFile": "https://example.com/airdrop1-recipients.json" + "url": "https://unlock-protocol.com/blog/up-token-swap-reward-airdrop-now-live-" }, { "id": "2", - "title": "Airdrop #2", - "description": "More to come", - "contractAddress": "0x1234567890123456789012345678901234567890", - "tokenAmount": "10000", - "tokenSymbol": "UP", - "recipientsFile": "https://example.com/airdrop2-recipients.json" + "name": "Blastoff Airdrop", + "description": "The Unlock Protocol Foundation is launching a next airdrop to Unlock Protocol community members, distributing over 7 million $UP tokens on Base to over 10,000 members of the community!", + "contractAddress": "0x3b26D06Ea8252a73742d2125D1ACEb594ECEE5c6", + "recipientsFile": "https://merkle-trees.unlock-protocol.com/0xe238effc14b43022c9ce132e22f0baa73cdd8696f4b435150a4c9341c83abfbf.json", + "token": { + "address": "0x3b26D06Ea8252a73742d2125D1ACEb594ECEE5c6", + "symbol": "UP", + "decimals": 18 + }, + "chainId": 8453 + }, + { + "id": "3", + "name": "Trading Volume", + "description": "More details to be announced soon!" } ] diff --git a/airdrops/src/utils/eligibility.ts b/airdrops/src/utils/eligibility.ts index 54a60bfd70f..486a3c40b10 100644 --- a/airdrops/src/utils/eligibility.ts +++ b/airdrops/src/utils/eligibility.ts @@ -1,21 +1,25 @@ +import { ethers } from 'ethers' +import { AirdropData } from '../../components/Campaigns' + /** * Checks if an address is eligible for an airdrop and returns the token amount * This is a temporary implementation that randomly determines eligibility * To be replaced with actual implementation that checks against the recipients file */ export const isEligible = async ( - _address: string, - _recipientsFile: string + address: string, + airdrop: AirdropData ): Promise => { - // Temporary implementation: randomly determine eligibility - // const random = Math.random() - - // // 40% chance of being eligible - // if (random < 0.4) { - // // Random amount between 100 and 1000 tokens - // const amount = Math.floor(Math.random() * 900) + 100 - // return amount - // } - - return 1337 + if (!airdrop.recipientsFile || !address) { + return 0 + } + const request = await fetch(airdrop.recipientsFile) + const recipients = await request.json() + const recipient = recipients.values.find((recipient: any) => { + return recipient.value[0] === address + }) + if (!recipient) { + return 0 + } + return Number(ethers.formatUnits(recipient.value[1], airdrop.token.decimals)) } diff --git a/airdrops/src/utils/terms.ts b/airdrops/src/utils/terms.ts new file mode 100644 index 00000000000..717143c6da6 --- /dev/null +++ b/airdrops/src/utils/terms.ts @@ -0,0 +1,167 @@ +export const terms = ` +## Airdrop Terms and Conditions + +Effective Date: February 2025 + +Last Updated: February 2025 + +These Airdrop Terms and Conditions (“**Terms**”) govern your participation in the airdrop program (the “**Airdrop**”) offered by Unlock Protocol Foundation (“**we**,” “**us**,” or “**our**”). The purpose of the Airdrop is to distribute Unlock Protocol (UP) (“**Tokens**”) to eligible participants as part of our broader ecosystem growth and governance initiative. By claiming, receiving, or using any Tokens distributed through the Airdrop, you acknowledge that you have read, understood, and agreed to be bound by these Terms. If you do not agree with any part of these Terms, you must not participate in the Airdrop. + +For the purposes of these Terms, references to our “Website” refer to [https://airdrops.unlock-protocol.com/](https://airdrops.unlock-protocol.com/) + +1. **Eligibility** + +To participate in the Airdrop, you must: + +1. Be at least 18 years old and legally capable of entering into a binding contract. + + 2. Not be a resident or entity located in any jurisdiction subject to comprehensive sanctions or embargoes, including but not limited to North Korea, Iran, Syria, Cuba, and the Crimea, Donetsk, and Luhansk regions of Ukraine. + + 3. Not appear on any sanctions list maintained by the U.S. Office of Foreign Assets Control (OFAC), the UK Office of Financial Sanctions Implementation (OFSI), the European Union, the United Nations Security Council, or any other relevant sanctioning body. + + 4. Have your wallet address screened against relevant sanctions lists before receiving Tokens. We reserve the right to deny participation if your wallet is flagged for any sanctions violations. + + 5. Comply with all applicable laws and regulations governing your participation in the Airdrop. + +2) **Nature of Tokens** + + 1. The Tokens distributed through the Airdrop are not an investment and do not represent equity, shares, or any ownership interest in Unlock Protocol Foundation or its affiliates. + + 2. The Tokens do not provide holders with any rights to dividends, profits, or other financial returns. + + 3. We make no representations or warranties regarding the future value or liquidity of the Tokens. + +3) **Old and New Airdrop Provisions** + + 1. The Airdrop consists of both a new distribution and a prior distribution of Tokens completed on November 1st 2024\. + + 2. If you previously received Tokens under the prior airdrop, you must acknowledge and accept these Terms as applicable to the prior airdrop before claiming further distributions. + + 3. The new Airdrop is governed by these Terms, and participation requires explicit acceptance. + + 4. If you were eligible but did not claim Tokens in the prior Airdrop, you must confirm acceptance of these updated Terms before claiming any unclaimed distributions. + + 5. The Foundation reserves the right to revoke eligibility for any participant found to have violated these Terms in connection with either the prior or current Airdrop. + + 6. To mitigate risks, participants who were eligible for previous distributions may be required to check an additional confirmation box to acknowledge the past distribution terms. + + 7. If an airdrop recipient disagrees with the basis of the prior airdrop, they may return the Tokens, and failure to do so will be considered acceptance of these Terms. + + 8. The Foundation reserves the right to block users from future distributions if they are found to have circumvented terms or engaged in prohibited actions. + + 9. Wallet addresses from both the prior and current Airdrop will be screened for sanctions compliance, and any flagged wallets may be disqualified from participation and may be required to return the Tokens. + +4) **Claiming the Airdrop** + + 1. To claim the Airdrop, you may be required to interact with the user interface on our Website and explicitly accept these Terms. + + 2. You may need to connect a compatible blockchain wallet to receive the Tokens. + + 3. Participants acknowledge that transactions on blockchain networks are irreversible, and lost or misdirected Tokens cannot be recovered. + + 4. Claiming through any method other than the designated front-end interface may forfeit eligibility. + + 5. The Foundation may implement measures to store proof of agreement, ensuring compliance in the event of regulatory scrutiny. + +5) **Restrictions on Use** + +You agree not to: + +1. Use the Tokens for illegal purposes, including but not limited to money laundering, terrorism financing, or fraudulent activities. + + 2. Circumvent geographic, legal, or other restrictions, such as by using VPNs or similar tools. + + 3. Engage in activities that could damage, disable, or impair the integrity of the Airdrop process. + +6) **No Guarantees & Limitation of Liability** + + 1. We do not guarantee the availability, functionality, or uninterrupted operation of the Airdrop or associated smart contracts. + + 2. The Airdrop is provided on an “as-is” and “as available” basis without warranties of any kind. + + 3. To the fullest extent permitted by law, we disclaim all liability for any direct, indirect, or consequential losses arising from participation in the Airdrop, including but not limited to: + + 1. Loss of access to your wallet or Tokens. + + 2. Technical failures or vulnerabilities in blockchain networks. + + 3. Regulatory changes impacting the Tokens or Airdrop. + +7) **Compliance & Fraud Prevention** + + 1. We reserve the right to require identity verification from participants if deemed necessary. + + 2. If we determine that you have engaged in fraudulent activities or violated these Terms, we reserve the right to revoke your eligibility and recover any Tokens distributed. + + 3. If any participant is later found to be in violation of applicable sanctions laws, we may take necessary actions, including freezing or reclaiming the Tokens where legally permissible. + + 4. To maintain compliance, the Foundation may audit distributions and request documentation from participants to verify adherence to these Terms. + + 5. Wallet addresses will be screened prior to distribution, and any flagged addresses may be disqualified. + +8) **Acknowledgment of Risks** + + 1. By participating in the Airdrop, you acknowledge and accept the following risks: + + 1. Blockchain-based transactions are permanent and irreversible. + + 2. The Tokens may have no value and may not be redeemable for any assets or services. + + 3. Regulatory developments could impact the legality and usability of the Tokens in your jurisdiction. + +9) **Amendments & Termination** + + 1. We reserve the right to modify or terminate the Airdrop and these Terms at any time without prior notice. + + 2. Changes will be effective upon posting the updated Terms on our Website. + + 3. Your continued participation in the Airdrop constitutes acceptance of any modifications. + +10) **Governing Law & Dispute Resolution** + + 1. These Terms shall be governed by and construed in accordance with the laws of the Cayman Islands. + + 2. Any disputes arising out of or in connection with these Terms shall be subject to binding arbitration in the Cayman Islands under the London Court of International Arbitration Rules. + +11) **Contact Information** + +If you have any questions regarding these Terms, please contact us at: + +Email: [hello@unlock-protocol.com](mailto:hello@unlock-protocol.com) + +Website: https://airdrops.unlock-protocol.com/ + +12. **User Acknowledgement** + +By participating in the Airdrop, including both prior and current distributions, and using the associated Website, you expressly confirm and agree to the following: + +1. **Knowledge and Understanding** + +You affirm that you possess sufficient knowledge and understanding to interact with blockchain-based systems, digital assets, and related technologies in a responsible manner, including but not limited to the mechanics of token distribution, wallet security, and transaction finality on the blockchain. + +2. **Assumption of Risk** + +You acknowledge and assume full responsibility for understanding and managing the risks outlined in these Terms, including but not limited to potential token volatility, smart contract vulnerabilities, regulatory developments, and the irreversible nature of blockchain transactions. + +3. **Third-Party Services** + +You understand that the Airdrop, including both prior and current distributions, may involve third-party platforms, such as blockchain explorers, wallet providers, and smart contract interfaces, which are outside of the control of the Unlock Protocol Foundation. Your use of these services is solely at your own risk and subject to their respective terms and conditions. + +4. **Acceptance of Terms** + +By claiming or receiving Tokens through the prior or current Airdrop, you confirm that you have read, understood, and accepted these Terms, including all limitations of liability, disclaimers, compliance requirements, and responsibilities outlined herein. + +5. **No Expectation of Profits or Returns** + +You acknowledge that the Tokens received through the prior or current Airdrop do not constitute an investment, carry no inherent financial return, and provide no right to dividends, revenue sharing, or governance beyond their stated functional purpose. + +6. **Sanctions and Compliance** + +You acknowledge that your wallet address will be screened against applicable sanctions lists and that participation in the Airdrop, including prior and current distributions, is prohibited for individuals or entities subject to sanctions restrictions. The Unlock Protocol Foundation reserves the right to deny or revoke participation if any compliance risks are identified. + +7. **Retroactive Acceptance for Prior Airdrop** + +If you previously received Tokens through a prior Airdrop, you expressly acknowledge that these Terms apply retroactively to that distribution. If you do not agree, you must return any Tokens received through the prior Airdrop. Failure to do so constitutes acceptance of these Terms. + +By participating in the Airdrop, you confirm that you have read, understood, and agreed to these Terms. +` diff --git a/yarn.lock b/yarn.lock index 05655652bdd..f721df853c8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6097,7 +6097,7 @@ __metadata: languageName: node linkType: hard -"@ethereumjs/tx@npm:^4.1.2": +"@ethereumjs/tx@npm:^4.1.2, @ethereumjs/tx@npm:^4.2.0": version: 4.2.0 resolution: "@ethereumjs/tx@npm:4.2.0" dependencies: @@ -8453,6 +8453,16 @@ __metadata: languageName: node linkType: hard +"@metamask/abi-utils@npm:^2.0.4": + version: 2.0.4 + resolution: "@metamask/abi-utils@npm:2.0.4" + dependencies: + "@metamask/superstruct": "npm:^3.1.0" + "@metamask/utils": "npm:^9.0.0" + checksum: 10/3d32d42c6e98fc4719b2b53597e573764b80936c7cc31d884c87729c4c4f74a30e93096db87aaa7cbcec9d3bb7d22b1adfc98a8bcb4c7c2f17bfbddaa4367d34 + languageName: node + linkType: hard + "@metamask/eth-sig-util@npm:^4.0.0": version: 4.0.1 resolution: "@metamask/eth-sig-util@npm:4.0.1" @@ -8481,6 +8491,13 @@ __metadata: languageName: node linkType: hard +"@metamask/superstruct@npm:^3.1.0": + version: 3.1.0 + resolution: "@metamask/superstruct@npm:3.1.0" + checksum: 10/5066fe228d5f11da387606d7f9545de2b473ab5a9e0f1bb8aea2f52d3e2c9d25e427151acde61f4a2de80a07a9871fe9505ad06abca6a61b7c3b54ed5c403b01 + languageName: node + linkType: hard + "@metamask/utils@npm:^3.4.1": version: 3.6.0 resolution: "@metamask/utils@npm:3.6.0" @@ -8506,6 +8523,23 @@ __metadata: languageName: node linkType: hard +"@metamask/utils@npm:^9.0.0": + version: 9.3.0 + resolution: "@metamask/utils@npm:9.3.0" + dependencies: + "@ethereumjs/tx": "npm:^4.2.0" + "@metamask/superstruct": "npm:^3.1.0" + "@noble/hashes": "npm:^1.3.1" + "@scure/base": "npm:^1.1.3" + "@types/debug": "npm:^4.1.7" + debug: "npm:^4.3.4" + pony-cause: "npm:^2.1.10" + semver: "npm:^7.5.4" + uuid: "npm:^9.0.1" + checksum: 10/ed6648cd973bbf3b4eb0e862903b795a99d27784c820e19f62f0bc0ddf353e98c2858d7e9aaebc0249a586391b344e35b9249d13c08e3ea0c74b23dc1c6b1558 + languageName: node + linkType: hard + "@motionone/animation@npm:^10.15.1, @motionone/animation@npm:^10.18.0": version: 10.18.0 resolution: "@motionone/animation@npm:10.18.0" @@ -9894,7 +9928,7 @@ __metadata: languageName: node linkType: hard -"@noble/hashes@npm:1.7.1, @noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:~1.7.1": +"@noble/hashes@npm:1.7.1, @noble/hashes@npm:^1.1.2, @noble/hashes@npm:^1.3.1, @noble/hashes@npm:^1.4.0, @noble/hashes@npm:^1.5.0, @noble/hashes@npm:~1.7.1": version: 1.7.1 resolution: "@noble/hashes@npm:1.7.1" checksum: 10/ca3120da0c3e7881d6a481e9667465cc9ebbee1329124fb0de442e56d63fef9870f8cc96f264ebdb18096e0e36cebc0e6e979a872d545deb0a6fed9353f17e05 @@ -12478,6 +12512,16 @@ __metadata: languageName: node linkType: hard +"@openzeppelin/merkle-tree@npm:1.0.8": + version: 1.0.8 + resolution: "@openzeppelin/merkle-tree@npm:1.0.8" + dependencies: + "@metamask/abi-utils": "npm:^2.0.4" + ethereum-cryptography: "npm:^3.0.0" + checksum: 10/dc53789b852e164a87f181a9141c3e26160bba2431c685dff0ca07409e7d051f49ae65308e9422d0a75db747a7646dff3dc756fb66f3fcd4818108dcd0c9b74f + languageName: node + linkType: hard + "@openzeppelin/upgrades-core@npm:1.39.0": version: 1.39.0 resolution: "@openzeppelin/upgrades-core@npm:1.39.0" @@ -13970,7 +14014,7 @@ __metadata: languageName: node linkType: hard -"@scure/base@npm:^1.1.1, @scure/base@npm:~1.2.2, @scure/base@npm:~1.2.4": +"@scure/base@npm:^1.1.1, @scure/base@npm:^1.1.3, @scure/base@npm:~1.2.2, @scure/base@npm:~1.2.4": version: 1.2.4 resolution: "@scure/base@npm:1.2.4" checksum: 10/4b61679209af40143b49ce7b7570e1d9157c19df311ea6f57cd212d764b0b82222dbe3707334f08bec181caf1f047aca31aa91193c678d6548312cb3f9c82ab1 @@ -18572,11 +18616,13 @@ __metadata: resolution: "@unlock-protocol/airdrops@workspace:airdrops" dependencies: "@headlessui/react": "npm:2.1.9" + "@openzeppelin/merkle-tree": "npm:1.0.8" "@privy-io/react-auth": "npm:2.2.1" "@sentry/nextjs": "npm:8.54.0" "@tanstack/react-query": "npm:5.59.19" "@tw-classed/react": "npm:1.7.0" "@types/react": "npm:18.3.18" + "@unlock-protocol/contracts": "workspace:*" "@unlock-protocol/core": "workspace:./packages/core" "@unlock-protocol/crypto-icon": "workspace:./packages/crypto-icon" "@unlock-protocol/eslint-config": "workspace:./packages/eslint-config" @@ -18596,6 +18642,7 @@ __metadata: next: "npm:14.2.21" postcss: "npm:8.4.49" react-hot-toast: "npm:2.4.1" + react-markdown: "npm:10.0.0" tailwind-merge: "npm:3.0.1" tailwindcss: "npm:3.4.17" typescript: "npm:5.6.3" @@ -18606,7 +18653,7 @@ __metadata: languageName: unknown linkType: soft -"@unlock-protocol/contracts@workspace:./packages/contracts, @unlock-protocol/contracts@workspace:^, @unlock-protocol/contracts@workspace:packages/contracts": +"@unlock-protocol/contracts@workspace:*, @unlock-protocol/contracts@workspace:./packages/contracts, @unlock-protocol/contracts@workspace:^, @unlock-protocol/contracts@workspace:packages/contracts": version: 0.0.0-use.local resolution: "@unlock-protocol/contracts@workspace:packages/contracts" dependencies: @@ -29131,6 +29178,19 @@ __metadata: languageName: node linkType: hard +"ethereum-cryptography@npm:^3.0.0": + version: 3.1.0 + resolution: "ethereum-cryptography@npm:3.1.0" + dependencies: + "@noble/ciphers": "npm:1.2.1" + "@noble/curves": "npm:1.8.1" + "@noble/hashes": "npm:1.7.1" + "@scure/bip32": "npm:1.6.2" + "@scure/bip39": "npm:1.5.4" + checksum: 10/97345df6afb4b42da51cdbbbc6c2c3861bfb3f7b63ee64c62b878d1110fe28b7e0ca95f6c17f78bad22f07ba4f519f3d901432d26842cd64255cb5cc7224b49d + languageName: node + linkType: hard + "ethereumjs-abi@npm:^0.6.8": version: 0.6.8 resolution: "ethereumjs-abi@npm:0.6.8" @@ -42275,6 +42335,13 @@ __metadata: languageName: node linkType: hard +"pony-cause@npm:^2.1.10": + version: 2.1.11 + resolution: "pony-cause@npm:2.1.11" + checksum: 10/ed7d0bb6e3e69f753080bf736b71f40e6ae4c13ec0c8c473ff73345345c088819966fdd68a62ad7482d464bf41176cf9421f5f63715d1a4532005eedc099db55 + languageName: node + linkType: hard + "posix-character-classes@npm:^0.1.0": version: 0.1.1 resolution: "posix-character-classes@npm:0.1.1" @@ -44529,6 +44596,28 @@ __metadata: languageName: node linkType: hard +"react-markdown@npm:10.0.0": + version: 10.0.0 + resolution: "react-markdown@npm:10.0.0" + dependencies: + "@types/hast": "npm:^3.0.0" + "@types/mdast": "npm:^4.0.0" + devlop: "npm:^1.0.0" + hast-util-to-jsx-runtime: "npm:^2.0.0" + html-url-attributes: "npm:^3.0.0" + mdast-util-to-hast: "npm:^13.0.0" + remark-parse: "npm:^11.0.0" + remark-rehype: "npm:^11.0.0" + unified: "npm:^11.0.0" + unist-util-visit: "npm:^5.0.0" + vfile: "npm:^6.0.0" + peerDependencies: + "@types/react": ">=18" + react: ">=18" + checksum: 10/513d9119587b561ac1195e3b2fa30b2bd9149b4dea658c189e2417fda600fbf9d5067967f098ea8e2d525b5fc7db00e3e4176ba2662a6eb503bc09d9b8bd5b5a + languageName: node + linkType: hard + "react-markdown@npm:9.0.3": version: 9.0.3 resolution: "react-markdown@npm:9.0.3"