Skip to content
On this page

L1-4: Custom Stream(高度なストリーミング支払い)

1. 課題

ETH Streamingをベースに、より高度なストリーミング支払いシステムを構築します。複数受信者、マルチストリーム管理、ストリームキャンセルなどの機能をサポートします。

2. 背景

基本的なETH Streamingは単一のETHストリームのみをサポートします。実際のアプリケーションでは以下が必要です:

  • 複数の並行ストリームの管理
  • ERC20トークンストリームのサポート(ETHだけでなく)
  • ストリームのライフサイクル管理(作成、キャンセル、資金回収)

3. 解決策

アーキテクチャ設計

solidity
struct Stream {
    address token;              // ERC20トークンアドレス(address(0) = ETH)
    uint256 cap;                // 1サイクルあたりの最大引き出し可能量
    uint256 unlockTime;         // フルアンロックサイクルの期間
    uint256 timeOfLastWithdrawal;
    uint256 remainingBalance;   // このストリームの残り総予算
}

マルチストリーム管理

  • streamIdで各ストリームを識別
  • streamId → recipient → Streamの二層マッピング
  • 各ストリームは独立して予算とアンロック状態を追跡

ストリームライフサイクル

  1. createStream(token, totalBudget) — 作成と資金提供
  2. addRecipient(streamId, recipient, cap, unlockTime) — 受信者を追加
  3. withdraw(streamId, amount) — 受信者が引き出し
  4. cancelStream(streamId) — オーナーがストリームをキャンセル

4. 遭遇した落とし穴

4.1 remainingBalanceとcapの混同

capはアンロックサイクルごとの最大引き出し可能量(時間経過で回復)であり、remainingBalanceはその受信者の総予算上限(回復しません)です。

4.2 キャンセル後も引き出しがブロックされない

ストリームキャンセル後にactiveStreamsフラグをクリアしないと、受信者が引き続き引き出しできる可能性があります。

5. 落とし穴の原因

5.1

capは時間ベースのアンロックモデル(L1-3と同様)に従って動作しますが、remainingBalanceは固定の予算上限です。この2つは別々に処理する必要があり、withdrawでは最初にunlocked(時間次元)をチェックし、次にremainingBalance(予算次元)をチェックします。

5.2

ストリームキャンセルが内部状態を変更した後、withdrawの入口でactiveStreams[streamId]をチェックする必要があります。

6. 落とし穴の解決方法

solidity
if (amount > unlocked) revert InsufficientUnlockedBalance();
if (amount > stream.remainingBalance) revert InsufficientStreamBalance();

7. 技術的ポイント

ポイント説明
マルチストリームアーキテクチャstreamId + 二層マッピング
予算 vs レートremainingBalance(総量)vs cap(レート)
ストリームライフサイクルcreate → fund → addRecipient → withdraw → cancel
拡張性各ストリームに独立したunlockTimeを設定可能

Built with AiAda