AKARI Tech Blog

燈株式会社のエンジニア・開発メンバーによる技術ブログです

Solidity実装で学ぶ、ブロックチェーンによる経費精算プロセスの自動化と透明化

皆さんこんにちは!

今週のAKARI Tech Blogは、AI SaaS 事業本部にてDigital Billder経費精算の開発を担当しております、小松が担当します。

はじめに

私たちが取り組んでいる「Digital Billder経費精算」では、経費精算業務の申請・承認・精算プロセスがまだまだ手動中心です。その結果、申請フローの非効率や不正リスクといった課題が考えられます。

そこで私は、「条件が満たされれば自動的に実行され、かつ改ざんができない記録が残る」というスマートコントラクトの特性が、経費精算のあるべき姿に近いのではと考えました。

今回は、そのスマートコントラクトを活用することで経費精算プロセスの自動化・透明化のアイデアと、そのサンプル実装を紹介します。

※Digital Billder自体にスマートコントラクトを活用した機能はありません。本記事はアイデアを基にした実験のご紹介にとどまります。

課題

既存の経費精算の課題として、以下のような点が考えられます。

  • 手動による申請・承認・精算の非効率
  • 不正リスク(虚偽申請や水増し)
  • 承認フローのブラックボックス
  • 精算履歴の改ざんリスク、証跡の不透明さ

これらの問題を解決するためには、「条件が満たされたら自動で実行され、記録は改ざんできない仕組み」が必要です。スマートコントラクトはまさにその特性を備えています。

スマートコントラクトの基礎

ブロックチェーン上にプログラム化された「もし〜なら〜する」契約をスマートコントラクトと呼びます。主な特徴は以下のとおりです。

  1. 透明性:処理内容は誰でも検証可能
  2. 改ざん耐性:一度記録された契約は変更不可
  3. 自動化:条件を満たせば手動操作なしで実行

スマートコントラクトは、ユーザーのトランザクションによって「呼び出される」ことで動作します。これは、通常のWebアプリケーションで関数を呼び出すのと似ていますが、実行されるのはブロックチェーン上の仮想マシン(例:EVM)であり、実行結果は全ノードに共有・検証されます。

たとえば、以下のような処理を考えてみましょう:

「領収書が提出され、上長が承認を出したら、自動的に支払いを実行する」

この一連の処理は、以下のようにスマートコントラクト内で定義されます:

  • ユーザーが submitExpense() 関数を呼び出して経費申請を登録
  • 承認者が approveExpense() 関数を呼び出して承認フラグを立てる
  • settle() 関数を呼び出すと、スマートコントラクトは内部状態(申請済みかつ承認済みか、かつ未払いか)を検証し、条件を満たしていれば自動的に送金処理を実行

つまり、「条件が整っている限り、ユーザーが関数を呼ぶだけで正確に処理が進む」ようにロジックが保証されており、その動作はすべてブロックチェーンに記録されるため、改ざんや不正ができません。

また、スマートコントラクトの動作は中央の管理者やサーバーに依存せず、ネットワーク全体で同一の計算が再現されるため、中立性・信頼性・耐障害性にも優れています。

イデア紹介:経費精算 × スマートコントラクト

ご紹介したスマートコントラクトの特性を踏まえ、経費精算業務に適用することでどのような課題解決が可能になるかを具体的にイメージしてみました。

以下は、実際に想定し得るユースケースの一例です。

1. 自動精算スマートコントラクト

  • 流れ:領収書提出 → 上長承認 → 自動支払
  • 効果:承認履歴の改ざん不可、手作業削減、不正抑止

2. 部署ごとの予算上限と自動アラート

  • 流れ:申請ごとに残予算をリアルタイム減算
  • 効果:予算オーバーの事前防止、透明な支出管理

3. 複数承認ステップの自動化

  • 流れ:部門長 ⇒ 経理 ⇒ 本部、と段階的承認をスマコンで管理
  • 効果:誰がいつ承認したかが完全記録、ミス防止

このような考えられるユースケースの中から、本記事では自動精算スマートコントラクトについて試してみたいと思います。

実装イメージ

今回、Remix IDEを用いてブラウザ上で動かす Solidity コントラクトの例を一部抜粋します。

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @title ExpenseSettlement
 * @dev 経費精算を管理するスマートコントラクト
 * 従業員が経費を申請し、管理者が承認後に支払いを行う仕組みを提供
 */
contract ExpenseSettlement {
    address public owner;

    /**
     * @dev 経費申請の情報を格納する構造体
     * @param requester 申請者のアドレス
     * @param amount 申請金額(wei単位)
     * @param approved 承認状態(true: 承認済み, false: 未承認)
     * @param paid 支払い状態(true: 支払い済み, false: 未払い)
     */
    struct Expense {
        address requester;  // 申請者のアドレス
        uint256 amount;     // 申請金額
        bool approved;      // 承認フラグ
        bool paid;          // 支払い完了フラグ
    }

    Expense[] public expenses;

    constructor() {
        owner = msg.sender;  // デプロイ者を所有者として設定
    }

    /**
     * @dev 経費申請を提出する関数
     * 誰でも経費申請を行うことができる
     * @param amount 申請する金額(wei単位)
     */
    function submitExpense(uint256 amount) external {
        expenses.push(Expense(msg.sender, amount, false, false));
    }

    /**
     * @dev 経費申請を承認する関数
     * 所有者(管理者)のみが実行可能
     * @param id 承認する経費申請のID(配列のインデックス)
     */
    function approveExpense(uint256 id) external {
        require(msg.sender == owner, "Only manager");
        
        expenses[id].approved = true;
    }

    /**
     * @dev 承認された経費を精算(支払い)する関数
     * 承認済みかつ未払いの経費のみ支払い可能
     * @param id 精算する経費申請のID(配列のインデックス)
     */
    function settle(uint256 id) external {
        Expense storage exp = expenses[id];
        
        require(exp.approved, "Not approved");
        require(!exp.paid, "Already paid");
        require(address(this).balance >= exp.amount, "Insufficient funds");

        exp.paid = true;
        
        (bool success, ) = payable(exp.requester).call{value: exp.amount}("");
        require(success, "Transfer failed");
    }

    receive() external payable {}
}

動作の順番としては

  1. submitExpense:申請者が金額を送信
  2. approveExpense:管理者が承認フラグを立てる
  3. settle:承認済み経費を申請者へ送金

このコードをRemix IDEへデプロイします。操作はブラウザ上で全て完了します。

Remix IDEでの操作画面
Remix IDEでの操作画面

以下は、実際にEthereumのテストネットでsettleまでの動作を実行し、対象の経費申請を確認した結果のログになります。

call to ExpenseSettlement.expenses
call
[call]from: 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2to: ExpenseSettlement.expenses(uint256)data: 0xaf4...00000

from    0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2
to  ExpenseSettlement.expenses(uint256) 0xd9145CCE52D386f254917e481eB44e9943F39138
execution cost  9766 gas (Cost only applies when called by a contract)
input   0xaf4...00000

# エンコード済みの関数の戻り値
# ここではExpense 構造体の内容:
# 0. 申請者アドレス
# 1. 金額(1000000 wei)
# 2. 承認済み(true)
# 3. 支払済み(true)
output  0x000000000000000000000000ab8483f64d9c6d1ecf9b849ae677dd3315835cb200000000000000000000000000000000000000000000000000000000000f424000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001

decoded input   {
    "uint256 ": "0"
}
decoded output  {
    "0": "address: requester 0xAb8483F64d9C6d1EcF9b849Ae677dD3315835cb2",
    "1": "uint256: amount 1000000",
    "2": "bool: approved true",
    "3": "bool: paid true"
}
logs    []
raw logs    []

decoded outputの値から paid true であり、精算が完了したことがわかります。

このように申請 → 承認 → 支払 の一連の流れが自動化され、すべての履歴がブロックチェーン上に記録されることを確認できました。

課題と今後の展望

スマートコントラクトを経費精算に導入することで多くの課題が解決される一方で、実運用を見据えた際にクリアすべき技術的・制度的な壁も存在します。

まず、法制度への対応は避けて通れません。現状では電子的な記録だけで完結する業務プロセスにおいて、「領収書の原本性」や「税務調査への耐性」が求められます。これに対しては、法的要件が認められるとされた場合、ブロックチェーンのタイムスタンプ機能を活用できるのではないでしょうか。

また、ブロックチェーンの特性として「記録が消せない・改ざんできない」という利点がありますが、それは同時に訂正や再申請の柔軟性が制限されることも意味します。サンプル実装では着手しませんでしたが、「誤申請→取り消し→再申請」といった業務フローを支えるための訂正プロセスの設計が必要になります。不可変な台帳を前提としたUI/UX設計が鍵となるでしょう。

加えて、スマートコントラクトの実行にかかるガス代(手数料)が障壁となります。処理の高速化やコスト削減の手段を解決する手段を考える必要があります。

セキュリティ面では、秘密鍵の管理体制も重要な課題です。とくに承認者の秘密鍵が漏洩すると、業務プロセスが乗っ取られるリスクがあります。

これらの技術的・制度的な課題を一つずつ乗り越えていくことで、経費精算のあり方そのものを進化させる可能性が広がっていると感じています。

今回のような実験的な取り組みを通じて、将来的に業務プロセスの透明性や自動化をどのように実現できるか、引き続き検証と模索を重ねることでより良いサービスの提供を追求していきたいと思います。

まとめ

今回は、経費精算の自動化と透明化を目指し、スマートコントラクトを活用した仕組みをご紹介しました。手動フローの非効率や不正リスクをブロックチェーンの強みで解消し、承認から支払いまでを自動化することで、監査性とUXを両立できる可能性を感じています。

燈では、こうした実験的な技術検証にも自主的に挑戦する文化があり、日々の課題解決や業務改善につながる可能性を探っています。

今後も技術検証を進め、社内外で活用できるプラットフォームとして磨いていきます。

We’re Hiring!

燈では、フルスタックで開発するソフトウェアエンジニアを募集しています。

興味がある方は、ぜひカジュアル面談でお話しましょう!🔥

akariinc.co.jp