【前言】
終於到了驗證的最後一步啦,感覺時間過得很快,一眨眼就到了這裡,網站也變得非常完整。感謝大家的陪伴,讓我們繼續邁向終點吧!
【定義 Ownership】
接續著上次的內容,這邊我們可以藉由 bignumber.js 的函數 toString()
來轉成字串,並藉此定義 OwnerShip
。
console.log(balance.toNumber());
if(balance.toString() === "1"){
setOwnerShip(true);
}
console.log(OwnerShip);
};
然後我們就可以傳出 OwnerOf()
這個函數,屆時就可以利用 OwnerOf().OwnerShip
來得到到底這個 Token 是不是屬於當前登入者的!
export function OwnerOf(account, id) {
const [a, setA] = useState({
tokenAddress: "我們智能合約的地址",
tokenId: id, // Token ID
schemaName: 'ERC721'
});
const [accountAddress, setAccountAddress] = useState(account)
const [OwnerShip, setOwnerShip] = useState(false)
useEffect(() => {
const fetchData = async () => {
const balance = await seaport.getAssetBalance({
accountAddress: accountAddress,
asset: {
tokenAddress: a.tokenAddress,
tokenId: a.tokenId,
schemaName: a.schemaName
},
})
console.log(balance.toString());
if(balance.toString() === "1"){
setOwnerShip(true);
}
};
fetchData();
}, []);
return (
{ OwnerShip }
);
}
【資料傳遞】
大家還記得我們那時候取得使用者登入帳號的部分嗎!現在我們要把資料傳出來。
首先先在登入區取得當前登入者的帳戶資料,也可以透過導入 web3.js
套件之後利用 web3.eth.coinbase
的方式取得!之後我們就不需要登入者再輸入一次以太坊地址了,我們使用自動填入的功能。
此外我們在導至 VIP 頁面的時候也要順便把使用者帳戶利用 react-router-dom
中 Link
可以附帶 state
的功能傳出去,當然也可以到 VIP 頁面的時候用上述方法重新抓一次地址及使用者欲登入的 id
,或從後端直接調資料,不過我就想試試看這個方法。
export function LoginForm(props) {
const [ accounts, setAccounts ] = useState([]);
const [ inputID, setInputID ] = useState('');
...
useEffect(() => {
window.ethereum
.request({ method: 'eth_requestAccounts' })
.then((newAccounts) => setAccounts(newAccounts));
...
}, []);
return (
<BoxContainer>
...
<SubmitButton type="submit" to={{
pathname: "/VIP",
state: { ac: accounts,
id: inputID}
}}>Enter</SubmitButton>
...
</BoxContainer>
);
}
這邊有個小細節是因為我們只會發行一萬隻的角色,如果這時候使用者隨便填入一個智能合約中不存在的 id
會導致 compiler error
,所以特別在 button tag
做 style
利用 pointerEvents
的限制就可以解決問題!
export function LoginForm(props) {
const [ accounts, setAccounts ] = useState([]);
const [ inputID, setInputID ] = useState('My Dino ID');
const [ go, setGo ] = useState({ pointerEvents: "none" })
...
useEffect(() => {
var i = Number(inputID);
if( 0 <= i && i <= 9999){
setGo({pointerEvents: "auto" })
}
else{
setGo({pointerEvents: "none" })
}
}, [inputID]);
return (
<BoxContainer>
<Input type="text" placeholder="My Dino ID" value={inputID} onInput={e => setInputID(e.target.value)} />
<Input type="text" placeholder="My Ethereum Address" value={ accounts } onInput={e => setAccounts(e.target.value)} />
...
<SubmitButton type="submit" style={ go } to={{
pathname: "/VIP",
state: { ac: accounts,
id: inputID}
}}>Enter</SubmitButton>
...
</BoxContainer>
);
}
pointer-events - CSS(层叠样式表) | MDN
在這邊我們先 call UseLocation
出來,然後利用 state.ac
就可以得到我們從前一個地方來的 state
。
import { useLocation } from "react-router-dom";
...
export function VIP(props) {
...
const location = useLocation();
const [accounts, setAccounts] = useState(location.state.ac);
const id = location.state.id;
const OS = OwnerOf(accounts[0], id).OwnerShip;
...
return (
<Wrapper>
...
</Wrapper>
);
}
這邊可以確實接收到資料,其中依序 print 出的是: 0
表示 accounts
以及 Token
有 0 組契合;登入者的地址;欲查詢 Ownership 的 Token ID
;Ownership
。
【驗證成功 & 驗證失敗】
我發現 call opnesea.js 的 getAssetBalance()
會有一些延遲才會得到真正的 ownership,所以我們必須要有一個 Loading Message。這邊就不多加敘述了,因為前面做過很多次方法都差不多!
如果今天是驗證失敗的話我們就要導回到 DINO Login 的地方,但因為 DINO Login 的使用者地址是直接抓 window.ethereum
取得的,所以就不用像上面一樣使用 react-router-dom
中 Link
搭配UseLocation
的方式找到地址。
export function VIP(props) {
...
return (
<Wrapper>
{ isPending && <LoaderTEXT /> }
{ !isPending && !OS && <Link1 to="/login">Verified Failed! Click to direct back DINO Login.</Link1> }
{/* failed */}
{ !isPending && OS && isVering && <VerifiedSuc>Verified Successfully!</VerifiedSuc> }
{ !isPending && OS && !isVering && <div></div> }
{/* successfully */}
</Wrapper>
);
}
驗證失敗的話會回傳一個 Link 可以讓使用者回到 DINO Login。成功的話就會進到 VIP 專屬的互動區!
【小結】
到這邊網頁的部分就正式結束啦!真的好累天啊,學到了超多新東西,也遇到了無數的困難,總歸還是還行地完成了這個不小的企劃。有很多心得想要講的只是那些話就留給結語吧!接下來幾天我會分享除了我專責的網頁任務內容外,其他在上鏈工程的部分!
【參考資料】
opensea-js
bignumber
React Router: Declarative Routing for React
React CSS