Day 23【Tokens' Owner】FUN SIDE PROJECT

fun_projects.jpg

【前言】
终於到了验证的最後一步啦,感觉时间过得很快,一眨眼就到了这里,网站也变得非常完整。感谢大家的陪伴,让我们继续迈向终点吧!

【定义 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-domLink 可以附带 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 tagstyle 利用 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 IDOwnership

图片 25.png

【验证成功 & 验证失败】
我发现 call opnesea.js 的 getAssetBalance() 会有一些延迟才会得到真正的 ownership,所以我们必须要有一个 Loading Message。这边就不多加叙述了,因为前面做过很多次方法都差不多!

如果今天是验证失败的话我们就要导回到 DINO Login 的地方,但因为 DINO Login 的使用者地址是直接抓 window.ethereum 取得的,所以就不用像上面一样使用 react-router-domLink 搭配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 专属的互动区!

图片 26.png

【小结】
到这边网页的部分就正式结束啦!真的好累天啊,学到了超多新东西,也遇到了无数的困难,总归还是还行地完成了这个不小的企划。有很多心得想要讲的只是那些话就留给结语吧!接下来几天我会分享除了我专责的网页任务内容外,其他在上链工程的部分!

https://s3-us-west-2.amazonaws.com/secure.notion-static.com/a111b4f1-23b1-4bdf-868f-c71520cc7714/5d3hkb.jpg

【参考资料】
opensea-js
bignumber
React Router: Declarative Routing for React
React CSS


<<:  Day 30 整合宝石:【Lab】建构三层式云端架构 (EC2+VPC+S3+RDS+IAM) (下)

>>:  DAY 23- HTTPS、TLS/ SSL

Day 26:Google Map 范本学习(1)

本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...

D10/ 我要怎麽把文字变美美的 - Text & AnnotatedString

今天大概会聊到的范围 AnnotatedString Text 在 Compose 中显示文字时,...

#16. Quiz App(原生JS版)

#16. Quiz App 所谓Quiz App就是提供给用户答题的小应用,包含数个选择题,选完一个...

Day 17: 人工智慧在音乐领域的应用 (AI作曲-基因演算法一)

我们在Day 7的时候曾经介绍过基於达尔文物竞天择适者生存的演化式计算,那麽今天开始我们就来详细的介...

第27天~CRUD

C-新增 R-查询 U-更改 D-删除 流程: 建置 设定 show 4.一定会有key:value...