# [ERC4519] 物理的な資産とNFTを紐づける仕組みを理解しよう！

> このEIPは、物理的な資産（例：IoTデバイス）を表す非代替トークン（Non-Fungible Token、NFT）のインターフェースを標準化します。

- URL: https://cardene.dev/articles/b26de6b3826dc72d39d9
- 公開日: 2023-08-03
- 更新日: 2023-08-03
- トピック: Blockchain
- タグ: ethereum, solidity, ブロックチェーン, nft

## はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、物理的な資産をNFT化する規格である**ERC4519**についてまとめていきます！

:::message
以下にまとめられているものをChatGPTも使用しながら、翻訳・要約・補足してまとめていきます。
:::

https://eips.ethereum.org/EIPS/eip-4519

## 概要
このEIPは、物理的な資産（例：IoTデバイス）を表す非代替トークン（Non-Fungible Token、NFT）のインターフェースを標準化します。

:::message
非代替性トークンとは、その名の通り交換ができないトークンのことです。
:::

NFTは、物理的な資産と関連付けられており、その関連付けが本物であるかどうかを検証することができます。
例えば、あるIoTデバイスを表すNFTは、実際にそのIoTデバイスに対応していることを確認できます。

![IoT.png](/images/qiita-d88c1138-7f8b-fa79-03c1-1eeaf9848a81.webp)

このNFTには、対応する物理的な資産のEthereumアドレスが含まれています。
これにより、物理的な資産はEthereum上でメッセージやトランザクションに署名することができます。
つまり、IoTデバイスがEthereum上で行う操作は、そのデバイスに紐付いたNFTによって制御されることができるのです。

![IoTNft.png](/images/qiita-3715d3e1-3e33-43fa-5df0-046b978d1711.webp)

なぜこのEIPが必要なのかというと、**EIP721**という既存のNFT規格は所有権を追跡することに特化しており、物理的な資産のようなスマートアセットの使用権を追跡することができません。
また、**EIP721**では物理的な資産のEthereumアドレスを追跡することもできません。

:::message
物理的な資産のEthereumアドレスとは、物理的なアイテム（例：IoTデバイス、実物の製品、機械、車など）とEthereumブロックチェーン上のデジタルアカウントを関連付けるための特別なアドレスのことです。
例えば、あるIoTデバイスが特定のEthereumアドレスと関連付けられている場合、そのデバイスはそのアドレスを使ってEthereumネットワークと通信し、メッセージの送受信やトランザクションの署名などの操作を実行できます。これにより、物理的な資産とEthereumネットワークとの間で安全な通信と管理が可能になります。
:::

そのため、この新しいEIPによって、IoTデバイスや他の物理的な資産をセキュアかつ追跡可能に管理することができるようになります。

![trait.png](/images/qiita-03ff3c12-a821-1a95-310e-c2edcf4ce907.webp)

## 動機

この標準は、**EIP721**が所有権（使用権ではなく）のみを追跡し、物理的な資産のEthereumアドレスを追跡しないために開発されました。
IoTデバイスなどのスマートアセットの人気が増しています。
これらのNFTを使用することで、物理的な資産（例：IoTデバイス、実物の製品など）とその所有者、およびユーザー間に安全でトレース可能な管理が可能になります。

具体的には、NFTには物理的な資産と対応する情報（Ethereumアドレスやその他の重要なデータ）が含まれています。これにより、次のようなメリットが得られます。

1. 物理的な資産の真正性の検証
NFTは物理的な資産と結びつけられているため、偽造や不正な操作を防ぐことができます。
誰かが物理的な資産のNFTを持っていれば、それは本物の物理的な資産に対応していることが保証されます。

2. セキュリティの向上
物理的な資産はEthereumアドレスと結び付けられています。
したがって、物理的な資産はEthereumネットワーク上で安全に通信したり、取引を行ったりすることができます。
これにより、悪意のある操作から物理的な資産を保護することができます。

3. 所有者とユーザーのトレース
物理的な資産に対応するNFTは、物理的な資産の所有者とそのユーザー間の関係をトレースできます。
これにより、誰が物理的な資産を所有しているか、そして誰がそれを使用しているかを確認することができます。

4. 権限管理
NFTを使用することで、物理的な資産の管理が効率的に行われます。
物理的な資産とNFTの結び付きを確認することで、所有者やユーザーが必要な権限を持っているかどうかを確認することができます。

## 仕様

### 物理的な資産とユーザーを関連付けるNFTの仕様

この仕様では、NFTに含まれる属性として、`addressAsset`と`addressUser`という2つのEthereumアドレスが述べられています。

1. `addressAsset`
物理的な資産（例：IoTデバイス、実物の製品など）のEthereumアドレスを指します。
つまり、このNFTが特定の物理的な資産と関連していることを示すために使われます。

2. `addressUser`
NFTを所持または利用するユーザーのEthereumアドレスを指します。
このアドレスは、物理的な資産を使用する権限を持つユーザーを識別するために使用されます。

これらの属性はオプションであり、両方の属性が必要とされることはありません。少なくとも1つの属性はNFTに含まれる必要があります。
例えば、物理的な資産とEthereumアドレスを直接関連付ける場合は、`addressAsset`を使います。
また、特定のユーザーがNFTを所有する場合は、`addressUser`を使うことができます。

もし`addressUser`属性だけを使用する場合、以下の2つの状態が考慮されます。

1. 未割り当て（`notAssigned`）
トークンが作成されたり、所有者から別の所有者に`transfer`（送付）されたり、あるいはユーザーから別のユーザーに割り当てが解除された場合、トークンの状態は「**未割り当て**」になります。
つまり、物理的な資産に対してまだユーザーが割り当てられていない状態を示します。

2. ユーザーに割り当て（`userAssigned`）
トークンが有効なユーザーに割り当てられると、「**ユーザーに割り当てられた**」状態になります。
これにより、物理的な資産が特定のユーザーによって所有または利用されていることを示します。

この仕様により、物理的な資産とそれに関連するユーザーとの間の関係を明確に定義し、安全かつトレース可能な管理を可能にしています。

![割り当て.png](/images/qiita-aa045234-7481-7ff3-18b0-65b775c344a4.webp)

![Figure1.jpg](/images/qiita-fa365d0b-bae8-1335-ba4c-bdf54369a96a.webp)
引用: https://eips.ethereum.org/EIPS/eip-4519

### 物理的な資産の所有者認証と連携の仕様

この仕様では、属性`addressAsset`が定義されているが、属性`addressUser`が定義されていない場合、NFTには2つの状態があります。
これにより、トークンが所有者との認証を待機しているか、認証が成功したかどうかが明確に定義されます。

以下の図は、この2つの状態をフローチャートで示しています。
トークンが作成されたり、新しい所有者に`transfer`（送付）されると、トークンは「`waitingForOwner`（所有者の認証を待機中）」という状態に変わります。
この状態では、トークンは資産と所有者との相互認証を待っています。
つまり、まだ所有者との確認が行われておらず、認証が必要な状態を示します。

そして、もし所有者との認証が成功した場合、トークンは「`engagedWithOwner`（所有者と連携中）」という状態に変わります。
これにより、所有者と資産が確実に紐付けられ、安全な相互作用が確立された状態を示します。

このような仕様により、物理的な資産が所有者との認証を待ち、認証が成功した場合に所有者と連携する状態が明確に定義されます。
これにより、物理的な資産と所有者とのセキュアな相互作用が確保され、トークンの状態に基づいた適切な管理が可能になります。

![紐付け.png](/images/qiita-8645d1bb-b7dd-d45a-f1c1-cbe8a4093081.webp)

![Figure2.jpg](/images/qiita-b7680d7e-1377-fd1a-ee3c-fc3f3633c8d5.webp)
引用: https://eips.ethereum.org/EIPS/eip-4519

### 物理的な資産の所有者とユーザーの状態変化仕様

属性`addressAsset`と`addressUser`が両方定義されている場合、NFTの状態は物理的な資産が所有者またはユーザーと連携しているかどうかを示します。
以下にそれぞれの状態と状態変化についてわかりやすく説明します。

- `waitingForOwner`（所有者の認証を待機中）
トークンが作成されたり、所有者が変更されたりすると、トークンの状態は「`waitingForOwner`」になります。
この状態では、トークンはまだ所有者との認証を待っており、物理的な資産と所有者との相互認証が必要です。

- `engagedWithOwner`（所有者と連携中）
トークンが有効な所有者に割り当てられると、「`engagedWithOwner`」の状態に変わります。
この状態では、物理的な資産は有効な所有者と紐付けられており、所有者との相互認証が成功したことを示します。

- `waitingForUser`（ユーザーの認証を待機中）
物理的な資産が所有者と連携中（`engagedWithOwner`）、またはユーザーと連携中（`engagedWithUser`）であり、まだユーザーが割り当てられていない場合、トークンの状態は「`waitingForUser`」になります。
この状態では、物理的な資産は有効な所有者と連携しており、所有者が有効なユーザーを割り当てるのを待っています。

- `engagedWithUser`（ユーザーと連携中）
物理的な資産が有効なユーザーに割り当てられた場合、「`engagedWithUser`」の状態に変わります。
この状態では、物理的な資産は有効なユーザーと紐付けられ、ユーザーは資産を使用することができます。

このような仕様により、物理的な資産と所有者、およびユーザーの関係が明確になり、適切な状態に基づいた管理が実現されます。
以下の図のフローチャートにより、これらの状態変化が視覚的に理解しやすくなります。
これにより、物理的な資産と所有者、およびユーザーとのセキュアな相互作用が確保され、スムーズな管理が可能になります。

![Figure3.jpg](/images/qiita-029a3c9e-cdaa-f8cd-907f-cc9673a1aa92.webp)
引用: https://eips.ethereum.org/EIPS/eip-4519

### NFTの所有権移転と相互認証プロセス

NFTの所有権を移転するためには、新しい所有者はアセットとの相互認証プロセスを行う必要があります。
このプロセスはオフチェーン（ブロックチェーン上ではない）でアセットと行われますが、同時にトークンのオンチェーン（ブロックチェーン上）で行われます。
この際、Ethereumアドレスが使用されます。
同様に、新しいユーザーもアセットとの相互認証プロセスを行い、使用権限の移転を完了させる必要があります。
これにより、アセットと所有者、およびアセットとユーザーの間でセキュアな通信に使用される新しい暗号鍵が生成されます。
これにより、新しい所有者やユーザーがアセットを管理しても、アセットの信頼性を追跡することが可能になります。

NFTが作成されるか所有権が移転すると、トークンの状態は「`waitingForOwner`（所有者の認証を待機中）」になります。
アセットは動作モードを「`waitingForOwner`（所有者の認証を待機中）」に設定します。
新しい所有者は、楕円曲線`secp256k1`とこの曲線で使用される原始元`P`を使って、2つの鍵を生成します。
それは、秘密鍵`SKO_A`と公開鍵`PKO_A`のペアです。
ここで、`PKO_A = SKO_A * P`となります。
所有者とアセットの間で共有キー`KO`を生成するために、アセットの公開鍵`PKA`を以下のように使います。

`KO = PKA * SKO_A`

`startOwnerEngagement`関数を使用して、`PKO_A`が属性`dataEngagement`として保存され、`KO`のハッシュが属性`hashK_OA`として保存されます。
所有者はアセットに対して「`request engagement`（認証の要求）」を送信し、アセットは以下を計算します。

`KA = SKA * PKO_A`

`KO`と`KA`が正しく計算された場合、それらは同じ値になります。
なぜならば、

`KO = PKA * SKO_A = (SKA * P) * SKO_A = SKA * (SKO_A * P) = SKA * PKO_A`

`ownerEngagement`関数を使用して、アセットは`KA`のハッシュを送信します。
もし`KA`のハッシュが`hashK_OA`のデータと一致する場合、トークンの状態は「`engagedWithOwner`（所有者と連携中）」に変更され、`OwnerEngaged`イベントが発行されます。
アセットがこのイベントを受信すると、動作モードを「`engagedWithOwner`（所有者と連携中）」に変更されます。
これにより、アセットは新しい所有者によって管理され、共有キーを使用してセキュアな通信を行うことができるようになります。

このプロセスは以下の図に示されています。
この時点から、アセットは新しい所有者によって管理され、所有者との間でセキュアな相互作用が確立されます。

![Figure4.jpg](/images/qiita-e67f2f3a-925a-dc9b-3cf6-7947c959c715.webp)
引用: https://eips.ethereum.org/EIPS/eip-4519

### waitingForUser状態のNFTの所有権移転プロセス

アセットがEthereumを参照して、NFTの状態が`waitingForUser`である場合の所有権移転プロセスが説明されています。
まず、アセットは動作モードを`waitingForUser`に設定します。
そして、新しい所有者と同様に、新しいユーザーとの相互認証プロセスが開始されます。

ユーザーは`startUserEngagement`関数を呼び出すトランザクションを送信します。
この関数は、ユーザーによって生成された公開鍵`PKU_A`をNFTの属性`dataEngagement`として保存し、また、共有鍵`KU = PKA * SKU_A`のハッシュを属性`hashK_UA`として保存します。
これにより、アセットとユーザーの相互認証のための情報がNFTに記録されます。

次に、ユーザーは`request engagement`を送信します。
アセットはこれを受け取り、`KA = SKA * PKU_A`を計算します。
KAはユーザーの公開鍵`PKU_A`とアセットの秘密鍵`SKA`の乗算によって得られる共有鍵です。

正しく実行された場合、共有鍵`KU`と`KA`は同じ値になります。
なぜならば、

`KU = PKA * SKU_A = (SKA * P) * SKU_A = SKA * (SKU_A * P) = SKA * PKU_A`

その後、アセットは`userEngagement`関数を使用して、`KA`のハッシュをNFTに送信します。
もし`KA`のハッシュがNFTに保存されている`hashK_UA`のデータと一致する場合、トークンの状態は`engagedWithUser`に変更され、`UserEngaged`イベントが発行されます。
アセットがこのイベントを受信すると、動作モードが`engagedWithUser`に変更されます。
これにより、アセットは新しいユーザーによって管理され、共有鍵を使用してセキュアな通信を行うことができるようになります。

このプロセスは以下の図で視覚的に示されています。
この時点から、アセットは新しいユーザーによって管理され、ユーザーとの間でセキュアな相互作用が確立されます。

![Figure5.jpg](/images/qiita-b30e84a8-a846-d0b2-b056-c21d8477a415.webp)
引用: https://eips.ethereum.org/EIPS/eip-4519

NFTには、セキュアな通信を確立するための共有秘密鍵の確立が非常に重要です。
そのために、NFTには以下の3つの属性が含まれています。

- `hashK_OA`
この属性は、アセットとその所有者との間で共有される秘密鍵のハッシュを定義します。
所有者とアセットの間で共通の秘密鍵を確立するために使用されます。

- `hashK_UA`
この属性は、アセットとそのユーザーとの間で共有される秘密鍵のハッシュを定義します。
ユーザーとアセットの間で共通の秘密鍵を確立するために使用されます。

- `dataEngagement`
この属性は、共有鍵の確立に必要な公開データを定義します。
アセット、所有者、およびユーザーが共有鍵を生成するために必要な情報が含まれています。

これらの属性により、アセットと所有者、およびアセットとユーザーとの間でセキュアな通信に使用される共有秘密鍵を確立できます。
所有者やユーザーは、正しい共有秘密鍵を使用して相互認証を行い、安全に通信することができます。これにより、アセットと関係者の間で信頼性のある通信が確保されます。

:::message
共有秘密鍵（Shared Secret Key）は、暗号学において2つの通信相手間で秘密情報を共有するために使われる暗号鍵のことを指します。
これは、特定の暗号アルゴリズムを使用して生成されるランダムなデータであり、通信相手間で秘密に保持されます。

共有秘密鍵は、共通鍵暗号方式としても知られる暗号方式でよく使用されます。
通信相手が同じ共有秘密鍵を共有することで、メッセージの暗号化と復号を行うことができます。
送信者はメッセージを共有秘密鍵を使って暗号化し、受信者は同じ共有秘密鍵を使ってメッセージを復号化します。

重要な点は、共有秘密鍵は通信相手間で秘密に保持される必要があるため、信頼性とセキュリティが確保されている必要があります。
鍵の管理と共有方法が適切に行われない場合、第三者による不正なアクセスやメッセージの盗聴が可能になります。
そのため、安全な通信のためには、信頼性のある共有鍵交換メカニズムや暗号鍵の適切な管理が必要です。
:::

### インターフェース

```javascript
pragma solidity ^0.8.0;
interface EIP-4519 NFT is EIP721/*,EIP165*/{
    event UserAssigned(uint256 indexed tokenId, address indexed _addressUser);
    
    event UserEngaged(uint256 indexed tokenId);
    
    event OwnerEngaged(uint256 indexed tokenId);
    
    event TimeoutAlarm(uint256 indexed tokenId);

    function setUser(uint256 _tokenId, address _addressUser) external payable; 

    function startOwnerEngagement(uint256 _tokenId, uint256 _dataEngagement, uint256 _hashK_OA) external payable;
 
    function ownerEngagement(uint256 _hashK_A) external payable; 
 
    function startUserEngagement(uint256 _tokenId, uint256 _dataEngagement, uint256 _hashK_UA) external payable;
    
    function userEngagement(uint256 _hashK_A) external payable; 
 
    function checkTimeout(uint256 _tokenId) external returns (bool);
    
    function setTimeout(uint256 _tokenId, uint256 _timeout) external; 
    
    function updateTimestamp() external; 
    
    function tokenFromBCA(address _addressAsset) external view returns (uint256);

    function ownerOfFromBCA(address _addressAsset) external view returns (address);

    function userOf(uint256 _tokenId) external view returns (address);
    
    function userOfFromBCA(address _addressAsset) external view returns (address);
    
    function userBalanceOf(address _addressUser) external view returns (uint256);
    
    function userBalanceOfAnOwner(address _addressUser, address _addressOwner) external view returns (uint256);
```

#### UserAssigned

NFTが新しいユーザーのユーティリティとして割り当てられたときに発行されるイベント。

:::message
ユーザーがNFTのユーティリティとして割り当てられるとは、そのNFTが特定のユーザーに関連付けられ、ユーザーがNFTを利用して特定の機能やサービスを受けることができることを意味します。
例えば、NFTがアクセス権や特別な特典を持つ場合、所有者はそれを特定のユーザーに与えることで、特典を享受できるようになります。
:::

- `tokenId`
    - NFTのトークンID。
- `_addressUser`
    - 新しいユーザーのアドレス。

#### UserEngaged

ユーザーとアセットの相互認証プロセスが成功した時に発行されるイベント。
- `tokenId`
    - NFTのトークンID。

#### OwnerEngaged

所有者とアセットの相互認証プロセスが成功した時に発行されるイベント。
- `tokenId`
    - NFTのトークンID。

#### TimeoutAlarm

タイムアウトが切れたことを示すイベント。
NFTのタイムスタンプがタイムアウトに更新されなかった場合に発行されます。

#### setUser

NFTを新しいユーザーのユーティリティとして割り当てる関数。

- `_tokenId`
    - NFTのトークンID。
- `_addressUser`
    - 新しいユーザーのアドレス。

**addressAssetが定義されている場合**
NFTの状態は「`engagedWithOwner`」、「`waitingForUser`」、または「`engagedWithUser`」である必要があります。
指定された`_tokenId`に対応するNFTの状態を「`waitingForUser`」に変更します。

**addressAssetが定義されていない場合**
関数は、指定された`_tokenId`に対応するNFTの状態を「`userAssigned`」に設定します。

**どちらの場合**
関数は`addressUser`を`_addressUser`に設定します。

#### startOwnerEngagement
所有者とアセット間の相互認証プロセスの初期化を定義する関数。

- `_tokenId`
    - NFTのトークンID。
- `_dataEngagement`
    - 所有者が提案する公開データ（共有鍵の合意のためのデータ）。
- `_hashK_OA`
    - 所有者がアセットと共有するための提案された秘密鍵のハッシュ。

所有者はアセットに対して公開データと共有する秘密のハッシュを提案します。
これにより、所有者とアセットの間で安全な通信チャネルの合意が始まります。
ただし、この関数単体では相互認証プロセスが完了するわけではなく、後に他の関数を使ってプロセスを完了する必要があります。

**addressAssetが定義されている場合**
NFTの状態は「`waitingForOwner`」である必要があります。
指定された`_tokenId`に対応するNFTのパラメータ`_dataEngagement`と`_hashK_OA`に提供された値を保存します。
NFTの状態は変更されずに保持されます。

#### ownerEngagement

所有者とアセット間の相互認証プロセスを完了するための関数。
この関数を実行することで、アセットは所有者との相互認証プロセスを完了します。
アセットが提供した秘密のハッシュと所有者が保持している秘密のハッシュが一致した場合にのみ、合意が成立し、NFTの状態が「`engagedWithOwner`」に変更されます。
これにより、所有者とアセットの間で安全な通信チャネルが確立されます。

- `_hashK_A`
    - アセットによって生成された所有者と共有する秘密のハッシュ。

NFTの状態が「`waitingForOwner`」であり、かつ`dataEngagement`が`0`以外の値である場合にのみ、この関数を実行できます。

関数は、保存されているNFTのパラメータである`hashK_OA`と提供された`_hashK_A`を比較します。

もし`hashK_OA`と`_hashK_A`が一致している場合、以下の処理が行われます。

1. NFTの状態が「`engagedWithOwner`」に変更されます。
2. `dataEngagement`が`0`に設定されます。
3. `OwnerEngaged`イベントが発行されます。

#### startUserEngagement

ユーザーとアセット間の相互認証プロセスを初期化するための関数。
ユーザーは公開データと秘密のハッシュを提案し、それらはNFTのパラメータとして保存されます。
その後、アセットが相互認証プロセスを完了するために提案されたデータを使用します。
もしアセットが提案された秘密のハッシュと一致した場合、合意が成立し、NFTの状態が「`engagedWithUser`」に変更されます。
これにより、ユーザーとアセットの間で安全な通信チャネルが確立されます。

- `_tokenId`
    - NFTのトークンID。
- `_dataEngagement`
    - 所有者が提案する公開データ（共有鍵の合意のためのデータ）。
- `_hashK_UA`
    - ユーザーがアセットと共有するための提案された秘密鍵のハッシュ。

ユーザーは、NFTの状態が「`waitingForUser`」であり、かつ`addressAsset`と`addressUser`が定義されている場合にのみ、この関数を実行できます。

関数は、NFTの状態を変更しないで、以下の情報をNFTのパラメータとして保存します。

- `_dataEngagement`
    - ユーザーが提案した公開データを保存します。
- `_hashK_UA`
    - ユーザーが提案した秘密のハッシュを保存します。

#### userEngagement

ユーザーとアセット間の相互認証プロセスを完了するための関数。
アセットはユーザーが提供した秘密のハッシュとNFTに保存された秘密のハッシュを比較します。
もし一致した場合、合意が成立し、NFTの状態が「`engagedWithUser`」に変更されます。
これにより、ユーザーとアセットの間で安全な通信チャネルが確立されます。

- `_hashK_A`
    - アセットがユーザーと共有するために生成した秘密のハッシュ。

アセットは、NFTの状態が「`waitingForUser`」であり、かつ`dataEngagement`が`0`以外である場合にのみ、この関数を実行できます。

NFTに保存されている`hashK_UA`と提供された`_hashK_A`を比較します。

もし`hashK_UA`と`_hashK_A`が一致した場合、相互認証が成功し、NFTの状態が「`engagedWithUser`」に変更されます。
関数は`dataEngagement`を`0`に設定します。
最後に、`UserEngaged`というイベントが発行されます。

#### checkTimeout

NFTがタイムアウトしているかどうかを確認するための関数。
誰でも特定のNFTがタイムアウトしているかどうかを確認できます。
アプリケーションやスマートコントラクトはこの関数を利用して、NFTがタイムアウトしている場合に適切な処理を行うことができます。

:::message
タイムアウトとは、一定の期間が経過した後に発生することを意味します。
**ERC4519**においては、NFTを管理するために特定の期限を設けることで、セキュリティやアクセス制御を強化するために使用されます。
具体的には、NFTが特定の状態になってから一定期間が経過し、必要な操作やイベントが行われなかった場合に、タイムアウトが発生します。
例えば、NFTが新しいユーザーとの相互認証プロセスを開始したが、一定期間内に相手の応答がない場合にタイムアウトするようなケースが考えられます。
:::

- `_tokenId`
    - NFTのトークンID。

関数はNFTのタイムアウトが発生しているかどうかをチェックします。
タイムアウトが発生している場合、関数は`true`を返します。
それ以外の場合は`false`を返します。

タイムアウトが発生しているかどうかの判定は、NFTのタイムスタンプを使用して行われます。
タイムアウト期間はコントラクト内に定義されていると仮定します。

もしタイムアウトが発生している場合、関数は`TimeoutAlarm`というイベントを発行します。
これは外部のエンティティに対してタイムアウトが発生したことを通知するためのイベントです。

#### setTimeout

NFTのタイムアウトを設定する関数。
呼び出す前にNFTの状態が `engagedWithOwner`、`waitingForUser`、または `engagedWithUser`のいずれかである必要があります。
NFTのタイムアウトは、セキュリティやアクセス制御を強化するために利用される重要な機能の1つです。
例えば、特定の権限を持つユーザーが一定期間以内に操作を行わなかった場合に、その権限を解除することで不正なアクセスや操作を防止することができます。

- `_tokenId`
    - NFTのトークンID。
- `_timeout`
    - 設定したいタイムアウトの値。

NFTの所有者は特定のNFTに対してタイムアウトの期間を設定することができます。
タイムアウトが設定されると、NFTが特定の状態になってから一定期間が経過すると、NFTの状態やアクセス権が変更されることがあります。
たとえば、一定期間内に特定の操作が行われなかった場合にタイムアウトが発生するようにプログラムされることがあります。

#### updateTimestamp

NFTに紐づいているアセット（資産）が自身のタイムスタンプを更新する関数。

タイムスタンプは、NFTが最後に更新された時間を示す値です。
NFTにはタイムアウト機能があり、一定期間が経過するとタイムアウトアラームが発生します。
しかし、この関数を呼び出すことで、アセットは自身のタイムスタンプを更新します。
その結果、タイムアウトアラームがリセットされ、アセットが最新のアクティブな状態を保持できるようになります。

ただし、この関数はアセット（デジタルアセットなど）によってのみ呼び出すことができます。
他の所有者やユーザーはこの関数を実行する権限を持ちません。
アセットは自身のタイムスタンプを適切に更新して、タイムアウトアラームが不必要に発生するのを防ぐことができます。

#### tokenFromBCA

特定のアセット（資産）のアドレスを指定すると、そのアセットに紐づくNFTの`tokenId`を取得する関数。

- `_addressAsset`
    - 特定のアセット（資産）のEthereumアドレス。


#### ownerOfFromBCA

特定のアセット（資産）のEthereumアドレスを指定すると、そのアセットに紐づくNFTの所有者（オーナー）のアドレスを取得する関数。

- `_addressAsset`
    - 特定のアセット（資産）のEthereumアドレス。

#### userOf

特定のトークンID（`tokenId`）を指定すると、そのトークン（NFT）に紐づくユーザーのEthereumアドレスを取得する関数。

- `_tokenId`
    - NFTのトークンID。

#### userOfFromBCA

特定のアセット（資産）のEthereumアドレス`_addressAsset`を指定すると、そのアセットに紐づくNFTのユーザー（所有者または利用者）のEthereumアドレスを取得する関数。

- `_addressAsset`
    - 特定のアセット（資産）のEthereumアドレス。

#### userBalanceOf

特定のユーザーのEthereumアドレスを指定すると、そのユーザーが保有するNFT（トークン）の数を取得する関数。

- `_addressUser`
    - 特定のユーザーのEthereumアドレス。

#### userBalanceOfAnOwner

特定のユーザーとオーナーのEthereumアドレスを指定すると、そのオーナーが特定のユーザーに対して所有しているNFT（トークン）の数を取得する関数。

- `_addressUser`
    - 特定のユーザーのEthereumアドレス。
- `_addressOwner`
    - 特定のオーナーのEthereumアドレス。

## 補足

### 認証
このEIPは、相互認証プロセスをスマートコントラクトを使用して検証することを提案しています。
スマートコントラクトは信頼性のある仕組みであり、信頼を必要としません。

### タイムアウト
このEIPでは、タイムスタンプ属性（物理アセットが最後にトークンとの紐付けをチェックした時間をEthereumに記録するためのもの）とタイムアウト属性（物理アセットが再度紐付けを証明するために設定された最大の遅延時間をEthereumに記録するためのもの）を含めることを提案しています。
これらの属性により、悪意のあるオーナーやユーザーがアセットを無限に使用することを防ぐことができます。

アセットが `updateTimestamp`関数を呼び出すとき、スマートコントラクトは`block.timestamp`を呼び出し、現在のブロックのタイムスタンプをUnixエポックから現在までの経過秒数を表しています。
そのため、タイムアウトは秒単位で指定する必要があります。

### EIP721ベース
**EIP721**はNFTの最も一般的に使用される標準です。
このEIPは、後方互換性を保つために**EIP721**を拡張しています。

## 後方互換性
この標準は**EIP721**の拡張です。
**EIP721**で言及されているよく使われるオプションの拡張（`IERC721Metadata`と`IERC721Enumerable`）と完全に互換性があります。

## 参考実装
最初のバージョンは、MDPI編集のSensorsジャーナルの[Special Issue Security, Trust and Privacy in New Computing Environments](https://eips.ethereum.org/assets/eip-4519/sensors-21-03119.pdf)の論文で発表されました。
この論文は、このEIPの著者と同じです。

実装自体は以下のコードを使用しています。

https://github.com/ethereum/EIPs/blob/844b829d7ac554467bd9e8f77be407f01cd3c301/assets/eip-4519/PoC_SmartNFT/PoC_SmartNFT.sol

こちらにコードをまとめておきました。

https://github.com/cardene777/base-code/blob/develop/contract/contracts/ERC4519/ERC4519.sol

## セキュリティに関する考慮事項
このEIPでは、物理アセットに紐付けられたジェネリックなNFTの作成システムが提案されています。
所有権に影響を与えることなく、ユーザー管理メカニズムの実装など、現行の**EIP721**NFTの改良に基づく一般的な視点が提供されています。
物理アセットは、完全にランダムな方法で自身からEthereumアドレスを生成する能力を持つべきであり、そのEthereumアドレスが生成される秘密をアセット自体だけが知ることができるようにすることで、アイデンティティの盗用を回避し、アセットが完全に本物であることを証明することができます。
これを確実にするために、アセットの関連トークンを作成する能力は、アセットの製造業者にしか持たせないことが推奨されます。
IoTデバイスの場合、デバイスのファームウェアは秘密を共有し変更することはできません。
秘密を保存する代わりに、アセットは**Physical Unclonable Functions（PUFs）**に関連付けられたヘルパーデータなどの非機密情報から秘密を再構築することが推奨されます。
楕円曲線に基づく安全な鍵交換プロトコルが提案されていますが、トークンは他の種類の鍵交換と共存することができます。

## 考察
**ERC4519**という規格は、リアル世界のものをブロックチェーン上で管理しようという試みだと思います。
そうなってくると、Azukiや他の企業が行なっているようにNFCタグなどを活用することをイメージしました。

https://note.com/miin_nft/n/nef3f51c03bfe

個人で実装するにはなかなかハードルが高そうな規格なので、あまり気軽には触れられない印象を受けました。
ただ、仕組み的には面白いと思いました。
受け取り側も認証を行わないとアセットを受け取れなかったり、有効期限がついていたりなど、他の規格に展開したりこの企画をきっかけにアイデアが浮かんだりしそうです。

技術的には結構難易度が高く、筆者自身も認証の仕組みあたりは理解できていません。
ちゃんと活用するには、その部分の理解が不可欠なので興味がある人はしっかり読み込んでみても良いかもしれないです。

## 引用

Javier Arcenegui (@Hardblock-IMSE-CNM), Rosario Arjona (@RosarioArjona), Roberto Román <roman@imse-cnm.csic.es>, Iluminada Baturone (@lumi2018), "ERC-4519: Non-Fungible Tokens Tied to Physical Assets," Ethereum Improvement Proposals, no. 4519, December 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-4519.

## 最後に

今回は「物理的な資産をNFT化する規格である**ERC1323**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください！

[Twitter @cardene777](https://twitter.com/cardene777)

## 採用強化中！

CryptoGamesでは一緒に働く仲間を大募集中です。

https://www.wantedly.com/companies/cryptogames

この記事で書いた自分の経験からもわかるように、裁量権を持って働くことができて一気に成長できる環境です。
「ブロックチェーンやWeb3、NFTに興味がある」、「スマートコントラクトの開発に携わりたい」など、少しでも興味を持っている方はまずはお話ししましょう！
