diff --git a/infra/rooch-portal-v2/src/app/invitation/[address]/page.tsx b/infra/rooch-portal-v2/src/app/invitation/[address]/page.tsx
index f9d227c635..816468ce0d 100644
--- a/infra/rooch-portal-v2/src/app/invitation/[address]/page.tsx
+++ b/infra/rooch-portal-v2/src/app/invitation/[address]/page.tsx
@@ -1,6 +1,6 @@
-import { InvitationsView } from 'src/sections/invitations/index';
+import { InvitationsView } from 'src/sections/invitations/view';
-export const metadata = { title: `Invitation` };
+export const metadata = { title: `Search Invitation` };
export default function Page({ params }: { params: { address: string } }) {
return ;
diff --git a/infra/rooch-portal-v2/src/app/invitation/page..tsx b/infra/rooch-portal-v2/src/app/invitation/page..tsx
deleted file mode 100644
index a95260cfd4..0000000000
--- a/infra/rooch-portal-v2/src/app/invitation/page..tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-
-import { InvitationsView } from 'src/sections/invitations/index';
-
-export const metadata = { title: `Invitation` };
-
-export default function Page() {
- return ;
-}
diff --git a/infra/rooch-portal-v2/src/app/invitation/page.tsx b/infra/rooch-portal-v2/src/app/invitation/page.tsx
new file mode 100644
index 0000000000..c956278188
--- /dev/null
+++ b/infra/rooch-portal-v2/src/app/invitation/page.tsx
@@ -0,0 +1,11 @@
+
+import WalletGuard from 'src/components/guard/WalletGuard';
+import InvitationOverviewView from 'src/sections/invitations/overview';
+
+export const metadata = { title: `Invitation` };
+
+export default function Page() {
+ return (
+
+ );
+}
diff --git a/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx b/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx
index 72a15de5da..72a01ce931 100644
--- a/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx
+++ b/infra/rooch-portal-v2/src/layouts/config-nav-dashboard.tsx
@@ -36,13 +36,11 @@ export const navData = [
title: 'Faucet',
path: paths.dashboard.faucet,
icon: ,
- // noAddressRequired: true,
},
{
title: 'Invitation',
path: paths.dashboard.invitation,
icon: ,
- // noAddressRequired: true,
},
{
title: 'Settings',
diff --git a/infra/rooch-portal-v2/src/sections/faucet/inviter.tsx b/infra/rooch-portal-v2/src/sections/faucet/inviter.tsx
index 394b7bfb31..6a01821faf 100644
--- a/infra/rooch-portal-v2/src/sections/faucet/inviter.tsx
+++ b/infra/rooch-portal-v2/src/sections/faucet/inviter.tsx
@@ -1,12 +1,14 @@
'use client';
+import type { Bytes} from '@roochnetwork/rooch-sdk';
+
import { useState, useEffect } from 'react';
-import { Args, stringToBytes, toHEX, Bytes } from '@roochnetwork/rooch-sdk';
+import { Args, toHEX, stringToBytes } from '@roochnetwork/rooch-sdk';
import {
- useCurrentAddress,
useRoochClient,
- useRoochClientQuery,
useCurrentWallet,
+ useCurrentAddress,
+ useRoochClientQuery,
} from '@roochnetwork/rooch-sdk-kit';
import { LoadingButton } from '@mui/lab';
@@ -17,12 +19,12 @@ import { useRouter } from 'src/routes/hooks';
import { useNetworkVariable } from 'src/hooks/use-networks';
import { formatCoin } from 'src/utils/format-number';
+import { INVITER_ADDRESS_KEY } from 'src/utils/inviter';
import { DashboardContent } from 'src/layouts/dashboard';
import { toast } from 'src/components/snackbar';
-import { INVITER_ADDRESS_KEY } from 'src/utils/inviter';
import { paths } from '../../routes/paths';
const FAUCET_NOT_OPEN = 'Faucet Not Open';
@@ -167,7 +169,6 @@ export function InviterFaucetView({ inviterAddress }: { inviterAddress: string }
if (!response.ok) {
const data = await response.json();
- console.log(data);
if (response.status === 500 && data.error.includes('UTXO value is zero')) {
const msg = 'Claim failed, Not found UTXO';
setErrorMsg(msg);
diff --git a/infra/rooch-portal-v2/src/sections/faucet/view.tsx b/infra/rooch-portal-v2/src/sections/faucet/view.tsx
index 81e9627b0b..46c058136a 100644
--- a/infra/rooch-portal-v2/src/sections/faucet/view.tsx
+++ b/infra/rooch-portal-v2/src/sections/faucet/view.tsx
@@ -2,7 +2,7 @@
import { useState, useEffect } from 'react';
import { Args, isValidBitcoinAddress } from '@roochnetwork/rooch-sdk';
-import { useRoochClient, useRoochClientQuery } from '@roochnetwork/rooch-sdk-kit';
+import { useCurrentNetwork, useRoochClient, useRoochClientQuery } from '@roochnetwork/rooch-sdk-kit';
import { LoadingButton } from '@mui/lab';
import { Box, Card, Chip, Stack, CardHeader, CardContent } from '@mui/material';
@@ -19,8 +19,9 @@ import { DashboardContent } from 'src/layouts/dashboard';
import { toast } from 'src/components/snackbar';
+import { CopyToClipboard } from 'react-copy-to-clipboard'
import { paths } from '../../routes/paths'
-import { INVITER_ADDRESS_KEY } from "../../utils/inviter";
+import { INVITER_ADDRESS_KEY } from "../../utils/inviter"
const FAUCET_NOT_OPEN= 'Faucet Not Open'
const INVALID_UTXO = 'Invalid UTXO'
@@ -47,6 +48,7 @@ export function FaucetView({ address }: { address: string }) {
const faucetObject = useNetworkVariable('faucetObject');
const [claimGas, setClaimGas] = useState(0);
const router = useRouter();
+ const network = useCurrentNetwork()
useAddressChanged({ address, path: 'faucet' });
@@ -170,7 +172,16 @@ export function FaucetView({ address }: { address: string }) {
return (
-
+
+
+
+ {
+ toast.success('Copy to you clipboard')
+ }} text={`https://${network === 'mainnet' ? '':'test-'}portal.rooch.network/inviter/${viewAddress}`}>
+
+
+
+
diff --git a/infra/rooch-portal-v2/src/sections/invitations/overview.tsx b/infra/rooch-portal-v2/src/sections/invitations/overview.tsx
new file mode 100644
index 0000000000..66ba14c47c
--- /dev/null
+++ b/infra/rooch-portal-v2/src/sections/invitations/overview.tsx
@@ -0,0 +1,20 @@
+'use client';
+
+import { useEffect } from 'react';
+import { useCurrentAddress } from '@roochnetwork/rooch-sdk-kit';
+
+import { useRouter } from 'src/routes/hooks';
+
+export default function InvitationOverviewView() {
+ const address = useCurrentAddress();
+ const router = useRouter();
+ useEffect(() => {
+ if (address) {
+ router.push(`/invitation/${address.toStr()}`);
+ }
+ }, [address, router]);
+ if (!address) {
+ return null;
+ }
+ return null;
+}
diff --git a/infra/rooch-portal-v2/src/sections/invitations/index.tsx b/infra/rooch-portal-v2/src/sections/invitations/view.tsx
similarity index 100%
rename from infra/rooch-portal-v2/src/sections/invitations/index.tsx
rename to infra/rooch-portal-v2/src/sections/invitations/view.tsx
diff --git a/infra/rooch-portal-v2/src/sections/settings/view.tsx b/infra/rooch-portal-v2/src/sections/settings/view.tsx
index 00e5414da0..c8c868c1a2 100644
--- a/infra/rooch-portal-v2/src/sections/settings/view.tsx
+++ b/infra/rooch-portal-v2/src/sections/settings/view.tsx
@@ -33,14 +33,15 @@ export function SettingsView() {
const session = useCurrentSession()
const client = useRoochClient()
+ const wallet = useCurrentWallet()
const network = useCurrentNetwork()
const faucetUrl = useNetworkVariable('faucetUrl')
const twitterOracleAddress = useNetworkVariable('twitterOracleAddress')
const [inviterCA, inviterModule, inviterConf] = useNetworkVariable('inviterCA');
- const wallet = useCurrentWallet()
const [tweetStatus, setTweetStatus] = useState('')
const [twitterId, setTwitterId] = useState()
const [verifying, setVerifying] = useState(false)
+ const [fetchTwitterIdStatus, setFetchTwitterIdStatus] = useState(true)
const {
data: sessionKeys,
@@ -78,9 +79,56 @@ export function SettingsView() {
}, [address, client, twitterOracleAddress])
useEffect(() => {
- fetchTwitterId()
+ fetchTwitterId().finally(() => setFetchTwitterIdStatus(false))
}, [fetchTwitterId])
+ const loopFetchTwitterId = async (count = 0) => {
+ const id = await fetchTwitterId()
+
+ if (id || count === 3) {
+ return id
+ }
+
+ return loopFetchTwitterId(count +1)
+ }
+
+ const checkTwitterObj = async (id: string) => {
+ const result = await client.queryObjectStates({
+ filter: {
+ object_id: id
+ }
+ })
+
+ if (result.data.length === 0) {
+ await sleep(10000)
+ return checkTwitterObj(id)
+ }
+
+ // TODO: twitter post btc address !== current wallet address.
+ // if (result.data[0].owner_bitcoin_address !== address?.toStr()) {
+ // throw (new Error('The twitter post btc address does not match the wallet address'))
+ // }
+
+ return ''
+ }
+ const fetchTwitterPost = async (pureTweetId: string) => {
+ const res = await axios.post(
+ `${faucetUrl}/fetch-tweet`,
+ {
+ tweet_id: pureTweetId,
+ },
+ {
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ },
+ )
+
+ if (res.data.ok) {
+ await checkTwitterObj(res.data.ok)
+ }
+ }
+
const disconnectTwitter = async () => {
if (!session) {
return
@@ -157,26 +205,10 @@ export function SettingsView() {
return
}
setVerifying(true)
- const pureTweetId = match[1]
try {
const pureTweetId = match[1]
- const res = await axios.post(
- `${faucetUrl}/fetch-tweet`,
- {
- tweet_id: pureTweetId,
- },
- {
- headers: {
- 'Content-Type': 'application/json',
- },
- },
- )
-
- if (!res.data.ok) {
- toast.error('fetch twitter failed')
- return
- }
+ await fetchTwitterPost(pureTweetId)
// step 2, check inviter
const inviterAddr = window.localStorage.getItem(INVITER_ADDRESS_KEY)
@@ -196,12 +228,14 @@ export function SettingsView() {
} else {
await bindTwitter(pureTweetId)
}
+ } else {
+ await bindTwitter(pureTweetId)
+ }
- await sleep(3000)
- const checkRes = await fetchTwitterId()
- if (checkRes) {
- toast.success('Binding success')
- }
+ await sleep(3000)
+ const checkRes = await loopFetchTwitterId()
+ if (checkRes) {
+ toast.success('Binding success')
}
} catch(error) {
if ('response' in error) {
@@ -218,7 +252,7 @@ export function SettingsView() {
}
}
- const networkText = network === 'mainnet' ? 'Pre-mainnet' : 'Testnet'
+ const networkText = network === 'mainnet' ? 'PreMainnet' : 'Testnet'
const XText = `BTC:${address?.toStr()}
Rooch ${networkText} is live! Bind your Twitter to earn RGas, and visit https://${network === 'mainnet' ? '':'test-'}grow.rooch.network to earn rewards with your BTC.
@@ -256,7 +290,7 @@ https://${network === 'mainnet' ? '':'test-'}portal.rooch.network/inviter/${addr
subheader="Bind a Twitter account to a Bitcoin address via publishing a tweet"
/>
- {twitterId ? (
+ {fetchTwitterIdStatus ? <>>: twitterId ? (