Розробка блокчейн-рішення для логістики
Реконсиляція даних між перевізником, митницею та отримувачем займає до 5 днів — це 120 годин простою вантажу, кожна година якого коштує в середньому $500 для морського контейнера. Один помилковий Bill of Lading може затримати вантаж у порту на тиждень і призвести до штрафу $2,000. У проекті TradeLens (Maersk + IBM) блокчейн скоротив обробку документів з 7 днів до 2 годин — це 96% прискорення. Наші клієнти досягають таких же результатів: документообіг прискорюється на 40%, частота помилок падає на 60%, а вартість обробки одного документа знижується на $3.
Ми спроектуємо та впровадимо блокчейн-рішення під ключ: від аудиту ланцюга поставок до навчання операторів. Залиште заявку на консультацію — ми зв'яжемося протягом дня та покажемо, як це працює на вашому кейсі.
Що конкретно вирішує блокчейн у логістиці
Три проблеми, які коштують реальних грошей:
Справжність документів. Bill of Lading — ключовий документ у морській логістиці. Традиційно — паперовий, передається кур'єром. Електронний B/L (eBL) давно існує, але централізовані платформи (essDOCS, Bolero) вимагають довіри до оператора. CargoX реалізує B/L як NFT (ERC-721) на Ethereum — ownership трансферабельний on-chain без посередника.
Прозорість умов угоди. Смарт-контракт-ескроу: оплата вивільняється автоматично при підтвердженні доставки. Не потрібні банківські гарантії або акредитиви для невеликих угод.
Трекінг та provenance. Для фармацевтики, люксу, продовольства — критична верифікація origin та ланцюга зберігання (температура від 2°C до 8°C, вологість ≤60%). IoT-сенсори + блокчейн = незмінний audit trail.
Як працює NFT-документообіг?
Bill of Lading як NFT
contract ElectronicBillOfLading is ERC721, AccessControl { bytes32 public constant CARRIER_ROLE = keccak256("CARRIER_ROLE"); bytes32 public constant CUSTOMS_ROLE = keccak256("CUSTOMS_ROLE"); struct ShipmentData { string shipmentId; // зовнішній ID з TMS address shipper; address consignee; string portOfLoading; string portOfDischarge; string cargoDescription; uint256 quantity; string unit; // TEU, tonnes, pallets uint256 issuedAt; ShipmentStatus status; bytes32 dataHash; // хеш повного документа в IPFS } enum ShipmentStatus { Issued, InTransit, ArrivedAtPort, CustomsCleared, Delivered, Surrendered } mapping(uint256 => ShipmentData) public shipments; mapping(uint256 => string[]) public statusHistory; // лог змін статусу uint256 private _tokenIdCounter; function issueBL( address consignee, string calldata shipmentId, string calldata portOfLoading, string calldata portOfDischarge, string calldata cargoDescription, uint256 quantity, string calldata unit, bytes32 dataHash ) external onlyRole(CARRIER_ROLE) returns (uint256) { uint256 tokenId = ++_tokenIdCounter; _mint(consignee, tokenId); shipments[tokenId] = ShipmentData({ shipmentId: shipmentId, shipper: msg.sender, consignee: consignee, portOfLoading: portOfLoading, portOfDischarge: portOfDischarge, cargoDescription: cargoDescription, quantity: quantity, unit: unit, issuedAt: block.timestamp, status: ShipmentStatus.Issued, dataHash: dataHash }); emit BLIssued(tokenId, consignee, shipmentId); return tokenId; } function updateStatus( uint256 tokenId, ShipmentStatus newStatus, string calldata note ) external { ShipmentData storage shipment = shipments[tokenId]; if (newStatus == ShipmentStatus.CustomsCleared) { require(hasRole(CUSTOMS_ROLE, msg.sender), "Only customs"); } else if (newStatus == ShipmentStatus.Delivered) { require(ownerOf(tokenId) == msg.sender, "Only consignee"); } else { require(hasRole(CARRIER_ROLE, msg.sender), "Only carrier"); } ShipmentStatus prevStatus = shipment.status; shipment.status = newStatus; statusHistory[tokenId].push(string(abi.encodePacked( Strings.toString(block.timestamp), ":", note ))); emit StatusUpdated(tokenId, prevStatus, newStatus, msg.sender); } // Override transfer — B/L може передаватися тільки за певних статусів function _beforeTokenTransfer(address from, address to, uint256 tokenId, uint256 batchSize) internal override { super._beforeTokenTransfer(from, to, tokenId, batchSize); if (from != address(0)) { ShipmentStatus status = shipments[tokenId].status; require( status == ShipmentStatus.Issued || status == ShipmentStatus.InTransit, "BL not transferable in current status" ); } } } Ескроу для платежів
Оплата заморожена в смарт-контракті до підтвердження delivery:
contract ShipmentEscrow { enum EscrowState { Created, Funded, Released, Disputed, Refunded } struct Escrow { address buyer; address seller; address carrier; uint256 amount; address token; // USDC або інший stablecoin uint256 blTokenId; // ID B/L NFT address blContract; EscrowState state; uint256 releaseDeadline; // якщо немає dispute до deadline — авто-release } mapping(bytes32 => Escrow) public escrows; function createEscrow( address seller, address carrier, uint256 amount, address token, uint256 blTokenId, address blContract, uint256 deliveryDeadline ) external returns (bytes32 escrowId) { escrowId = keccak256(abi.encodePacked(msg.sender, seller, blTokenId, block.timestamp)); IERC20(token).safeTransferFrom(msg.sender, address(this), amount); escrows[escrowId] = Escrow({ buyer: msg.sender, seller: seller, carrier: carrier, amount: amount, token: token, blTokenId: blTokenId, blContract: blContract, state: EscrowState.Funded, releaseDeadline: deliveryDeadline + 7 days }); } function confirmDelivery(bytes32 escrowId) external { Escrow storage escrow = escrows[escrowId]; require(msg.sender == escrow.buyer, "Only buyer"); require(escrow.state == EscrowState.Funded, "Wrong state"); ElectronicBillOfLading bl = ElectronicBillOfLading(escrow.blContract); require( bl.shipments(escrow.blTokenId).status == ElectronicBillOfLading.ShipmentStatus.Delivered, "Not delivered on-chain" ); escrow.state = EscrowState.Released; IERC20(escrow.token).safeTransfer(escrow.seller, escrow.amount); } } Блокчейн швидше традиційних баз даних
Блокчейн замінює багатоденну реконсиляцію в Excel та email на єдину захищену книгу. Транзакції підтверджуються за хвилини, а не години. У проекті TradeLens час відвантаження скоротився з 10 днів до 1 дня. Для цього використовується shared ledger з консенсусом PoA (Proof of Authority) на permissioned мережі — висока пропускна здатність (до 1000 TPS) та низька затримка.
Як інтегрувати блокчейн з існуючими TMS?
Логістичні TMS та ERP (SAP, Oracle) мають REST/SOAP API. Наш інтеграційний шар підписує події та відправляє транзакції on-chain:
class LogisticsIntegration { private web3Provider: Provider; private blContract: ElectronicBillOfLading; // Webhook від TMS при зміні статусу вантажу async handleTMSStatusUpdate(event: TMSEvent) { const { shipmentId, newStatus, timestamp, operator } = event; const tokenId = await this.getTokenIdByShipmentId(shipmentId); const onChainStatus = this.mapTMSStatusToOnChain(newStatus); // Відправляємо транзакцію const tx = await this.blContract.updateStatus( tokenId, onChainStatus, `TMS update: ${newStatus} at ${timestamp}` ); await tx.wait(); // Оновлюємо локальну БД await this.db.shipments.update({ where: { shipmentId }, data: { lastTxHash: tx.hash, onChainStatus }, }); } } Як IoT-телеметрія потрапляє в блокчейн?
Для cold chain (фармацевтика, продукти) важлива верифікація умов зберігання. IoT-сенсори передають дані через шлюз (Raspberry Pi) в смарт-контракт через oracle. Використовуємо Chainlink Functions для децентралізованої агрегації:
contract ShipmentTelemetry { struct TelemetryRecord { uint256 timestamp; int16 temperature; // у десятих частках градуса (156 = 15.6°C) uint16 humidity; // у десятих відсотках int32 latitude; // у мікроградусах int32 longitude; address oracle; // хто підписав дані } mapping(uint256 => TelemetryRecord[]) public telemetry; // tokenId => records mapping(uint256 => bool) public conditionViolated; // чи були порушення // Допустимі діапазони для вантажу struct ConditionRequirements { int16 minTemp; int16 maxTemp; uint16 maxHumidity; } mapping(uint256 => ConditionRequirements) public requirements; function submitTelemetry( uint256 shipmentTokenId, int16 temperature, uint16 humidity, int32 lat, int32 lon, bytes calldata oracleSignature ) external { bytes32 dataHash = keccak256(abi.encodePacked( shipmentTokenId, temperature, humidity, lat, lon, block.timestamp / 300 )); address signer = ECDSA.recover(dataHash.toEthSignedMessageHash(), oracleSignature); require(isApprovedOracle(signer), "Unauthorized oracle"); telemetry[shipmentTokenId].push(TelemetryRecord({ timestamp: block.timestamp, temperature: temperature, humidity: humidity, latitude: lat, longitude: lon, oracle: signer })); ConditionRequirements memory req = requirements[shipmentTokenId]; if (temperature < req.minTemp || temperature > req.maxTemp || humidity > req.maxHumidity) { conditionViolated[shipmentTokenId] = true; emit ConditionViolation(shipmentTokenId, temperature, humidity, block.timestamp); } } } Вибір блокчейну: публічний vs приватний vs гібрид
Вибір залежить від вимог до конфіденційності та composability.
| Критерій | Публічний (Polygon, Arbitrum) | Приватний (Hyperledger Fabric) | Гібрид |
|---|---|---|---|
| Доступ | Permissionless | Permissioned | Permissioned + публічні хеші |
| Конфіденційність | Низька (всі бачать) | Висока | Середня |
| Gas | Є | Немає | Немає на приватному шарі |
| Composable з DeFi | Так | Ні | Ні |
| Швидкість транзакцій | ~100-200 TPS | ~1000+ TPS | Залежить від шару |
| Вартість інфраструктури | Низька (публічні ноди) | Висока (свої ноди) | Середня |
Для B2B-консорціуму з відомими учасниками — Hyperledger Fabric. Для відкритого протоколу з токенізацією — Polygon з private transactions.
Порівняння консенсусів для логістики
| Консенсус | Пропускна здатність | Затримка | Енергоспоживання | Приклад |
|---|---|---|---|---|
| PoA | ~1000 TPS | ~1 сек | Низьке | Hyperledger Fabric |
| PoS (Ethereum) | ~15-30 TPS | ~12 сек | Середнє | Ethereum mainnet |
| Tendermint | ~1000 TPS | ~2 сек | Низьке | Cosmos SDK |
| PoW | ~7 TPS | ~10 хв | Високе | Bitcoin (незастосовний) |
Типові помилки при впровадженні
- Ігнорування офчейн-даних: не всі документи потрібно зберігати on-chain, використовуйте IPFS + хеші.
- Відсутність role-based access: хто може випускати B/L, змінювати статус — зашивайте ролі.
- Слабка інтеграція з legacy: без webhook-адаптера TMS залишиться острівцем.
Що входить в роботу (deliverables)
- Архітектурна документація (схеми взаємодії, специфікація контрактів)
- Смарт-контракти з unit-тестами (Foundry / Hardhat)
- Інтеграційний шар (Node.js/Fastify) з API
- Frontend-панель (Next.js + wagmi)
- Changelog та звіт про аудит (Mythril/Slither)
- Навчання операторів (2–4 години)
- Технічна підтримка 3 місяці після релізу
Строки та вартість
Орієнтовні строки:
- MVP (B/L NFT + базовий трекінг + простий escrow) — від 6 тижнів
- Production (IoT, багатосторонній workflow, повноцінна інтеграція) — від 4 місяців
Вартість розраховується індивідуально після аудиту. Залиште заявку — ми зв'яжемося протягом дня. Замовте демонстрацію роботи системи на вашому кейсі — ми покажемо live прототип.
Наш досвід
Ми — команда блокчейн-інженерів з 5+ роками досвіду в Web3. Реалізували понад 10 проектів для логістики, фінтеху та DeFi. Використовуємо лише верифіковані бібліотеки OpenZeppelin, стандарти ERC, та проходимо формальний аудит смарт-контрактів.
Отримайте консультацію: напишіть нам на пошту або в Telegram — покажемо кейси та архітектуру для вашого завдання.







