diff --git a/docs/fdc/reference/IAddressValidity.mdx b/docs/fdc/reference/IAddressValidity.mdx index 4384b66f..747edee1 100644 --- a/docs/fdc/reference/IAddressValidity.mdx +++ b/docs/fdc/reference/IAddressValidity.mdx @@ -4,6 +4,10 @@ sidebar_position: 6 description: Assert whether a string represents a valid address. --- +import CodeBlock from "@theme/CodeBlock"; +import AddressVerifier from "!!raw-loader!/examples/developer-hub-solidity/AddressVerifier.sol"; +import Remix from "@site/src/components/remix"; + Assert whether a string represents a valid address on an external blockchain. Sourced from `IAddressValidity.sol` on [GitHub](https://github.com/flare-foundation/flare-smart-contracts-v2/blob/main/contracts/userInterfaces/fdc/IAddressValidity.sol). @@ -142,62 +146,7 @@ struct ResponseBody { ## Usage Example -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcHub.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcVerification.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/fdc/IAddressValidity.sol"; - -contract AddressVerifier { - IFdcHub private fdcHub; - IFdcVerification private fdcVerification; - - bytes32 private constant ATTESTATION_TYPE_ADDRESS_VALIDITY = 0x0500000000000000000000000000000000000000000000000000000000000000; - bytes32 private constant SOURCE_ID_BTC = 0x4254430000000000000000000000000000000000000000000000000000000000; - - constructor(address _fdcHubAddress, address _fdcVerificationAddress) { - fdcHub = IFdcHub(_fdcHubAddress); - fdcVerification = IFdcVerification(_fdcVerificationAddress); - } - - // Request address validation - function requestAddressValidation(string calldata _address) external payable { - // Create request body - IAddressValidity.RequestBody memory requestBody = IAddressValidity.RequestBody({ - addressStr: _address - }); - - // Encode the full request - bytes memory encodedRequest = abi.encode( - ATTESTATION_TYPE_ADDRESS_VALIDITY, - SOURCE_ID_BTC, - bytes32(0), // messageIntegrityCode (would need to be calculated properly) - requestBody - ); - - // Submit the request with payment - fdcHub.requestAttestation{value: msg.value}(encodedRequest); - } - - // Verify a provided proof - function verifyAddressProof(IAddressValidity.Proof calldata _proof) external view returns ( - bool isValid, - string memory standardAddress, - bytes32 standardAddressHash - ) { - // Verify the proof using FdcVerification - bool proofVerified = fdcVerification.verifyAddressValidity(_proof); - - if (proofVerified) { - // Extract data from the verified proof - isValid = _proof.data.responseBody.isValid; - standardAddress = _proof.data.responseBody.standardAddress; - standardAddressHash = _proof.data.responseBody.standardAddressHash; - } - - return (isValid, standardAddress, standardAddressHash); - } -} -``` + + {AddressVerifier} + +Open example in Remix diff --git a/docs/fdc/reference/IBalanceDecreasingTransaction.mdx b/docs/fdc/reference/IBalanceDecreasingTransaction.mdx index e8880e09..dbdd1b48 100644 --- a/docs/fdc/reference/IBalanceDecreasingTransaction.mdx +++ b/docs/fdc/reference/IBalanceDecreasingTransaction.mdx @@ -4,6 +4,10 @@ sidebar_position: 7 description: Detect a transaction that decreases an address balance. --- +import CodeBlock from "@theme/CodeBlock"; +import LockMonitor from "!!raw-loader!/examples/developer-hub-solidity/LockMonitor.sol"; +import Remix from "@site/src/components/remix"; + An interface to detect transactions that decrease the balance of a specific address or are signed by that address on external blockchains. Sourced from `IBalanceDecreasingTransaction.sol` on [GitHub](https://github.com/flare-foundation/flare-smart-contracts-v2/blob/main/contracts/userInterfaces/fdc/IBalanceDecreasingTransaction.sol). @@ -239,75 +243,7 @@ Response body containing details about the balance decreasing transaction. ## Usage Example -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcHub.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcVerification.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/fdc/IBalanceDecreasingTransaction.sol"; - -contract LockMonitor { - IFdcHub private fdcHub; - IFdcVerification private fdcVerification; - - bytes32 private constant ATTESTATION_TYPE_BALANCE_DECREASING = 0x0200000000000000000000000000000000000000000000000000000000000000; - bytes32 private constant SOURCE_ID_BTC = 0x4254430000000000000000000000000000000000000000000000000000000000; - - mapping(bytes32 => bool) public lockedAddresses; // sourceAddressHash => isLocked - - constructor(address _fdcHubAddress, address _fdcVerificationAddress) { - fdcHub = IFdcHub(_fdcHubAddress); - fdcVerification = IFdcVerification(_fdcVerificationAddress); - } - - // Register an address as locked (should not spend funds) - function registerLockedAddress(bytes32 sourceAddressHash) external { - lockedAddresses[sourceAddressHash] = true; - } - - // Request verification of a transaction that might violate lock agreement - function checkViolation(bytes32 transactionId, bytes32 sourceAddressIndicator) external payable { - // Create request body - IBalanceDecreasingTransaction.RequestBody memory requestBody = IBalanceDecreasingTransaction.RequestBody({ - transactionId: transactionId, - sourceAddressIndicator: sourceAddressIndicator - }); - - // Encode the full request - bytes memory encodedRequest = abi.encode( - ATTESTATION_TYPE_BALANCE_DECREASING, - SOURCE_ID_BTC, - bytes32(0), // messageIntegrityCode (would need to be calculated properly) - requestBody - ); - - // Submit the request with payment - fdcHub.requestAttestation{value: msg.value}(encodedRequest); - } - - // Verify a provided proof and take action if a locked address has spent funds - function verifyViolation(IBalanceDecreasingTransaction.Proof calldata _proof) - external - returns (bool isViolation) - { - // Verify the proof using FdcVerification - bool proofVerified = fdcVerification.verifyBalanceDecreasingTransaction(_proof); - - if (proofVerified) { - // Extract the sourceAddressHash - bytes32 sourceAddressHash = _proof.data.responseBody.sourceAddressHash; - int256 spentAmount = _proof.data.responseBody.spentAmount; - - // Check if this is a locked address and the amount spent is positive - if (lockedAddresses[sourceAddressHash] && spentAmount > 0) { - // Take action - e.g., liquidate collateral, notify stakeholders, etc. - lockedAddresses[sourceAddressHash] = false; // Remove from locked addresses - return true; - } - } - - return false; - } -} -``` + + {LockMonitor} + +Open example in Remix diff --git a/docs/fdc/reference/IConfirmedBlockHeightExists.mdx b/docs/fdc/reference/IConfirmedBlockHeightExists.mdx index 7c514af0..8fcf85c8 100644 --- a/docs/fdc/reference/IConfirmedBlockHeightExists.mdx +++ b/docs/fdc/reference/IConfirmedBlockHeightExists.mdx @@ -4,6 +4,10 @@ sidebar_position: 8 description: Assert that a block number is confirmed. --- +import CodeBlock from "@theme/CodeBlock"; +import BlockchainMonitor from "!!raw-loader!/examples/developer-hub-solidity/BlockchainMonitor.sol"; +import Remix from "@site/src/components/remix"; + An interface to verify that a specified block has been confirmed on an external blockchain and to calculate block production rates. Sourced from `IConfirmedBlockHeightExists.sol` on [GitHub](https://github.com/flare-foundation/flare-smart-contracts-v2/blob/main/contracts/userInterfaces/fdc/IConfirmedBlockHeightExists.sol). @@ -207,79 +211,10 @@ average_block_time = time_elapsed / blocks_produced ## Usage Example -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcHub.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcVerification.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/fdc/IConfirmedBlockHeightExists.sol"; - -contract BlockchainMonitor { - IFdcHub private fdcHub; - IFdcVerification private fdcVerification; - - bytes32 private constant ATTESTATION_TYPE_CONFIRMED_BLOCK = 0x0200000000000000000000000000000000000000000000000000000000000000; - bytes32 private constant SOURCE_ID_BTC = 0x4254430000000000000000000000000000000000000000000000000000000000; - - constructor(address _fdcHubAddress, address _fdcVerificationAddress) { - fdcHub = IFdcHub(_fdcHubAddress); - fdcVerification = IFdcVerification(_fdcVerificationAddress); - } - - // Request confirmation of a block - function requestBlockConfirmation(uint64 blockNumber, uint64 queryWindow) external payable { - // Create request body - IConfirmedBlockHeightExists.RequestBody memory requestBody = IConfirmedBlockHeightExists.RequestBody({ - blockNumber: blockNumber, - queryWindow: queryWindow - }); - - // Encode the full request - bytes memory encodedRequest = abi.encode( - ATTESTATION_TYPE_CONFIRMED_BLOCK, - SOURCE_ID_BTC, - bytes32(0), // messageIntegrityCode (would need to be calculated properly) - requestBody - ); - - // Submit the request with payment - fdcHub.requestAttestation{value: msg.value}(encodedRequest); - } - - // Verify a provided proof and calculate block rate - function verifyBlockAndCalculateRate(IConfirmedBlockHeightExists.Proof calldata _proof) - external view - returns ( - bool blockConfirmed, - uint64 avgBlockTimeSeconds - ) - { - // Verify the proof using FdcVerification - bool proofVerified = fdcVerification.verifyConfirmedBlockHeightExists(_proof); - - if (proofVerified) { - // Extract data for calculation - uint64 blockNumber = _proof.data.requestBody.blockNumber; - uint64 blockTimestamp = _proof.data.responseBody.blockTimestamp; - uint64 lowestNumber = _proof.data.responseBody.lowestQueryWindowBlockNumber; - uint64 lowestTimestamp = _proof.data.responseBody.lowestQueryWindowBlockTimestamp; - - // Calculate average block time - uint64 blocksProduced = blockNumber - lowestNumber; - uint64 timeElapsed = blockTimestamp - lowestTimestamp; - - if (blocksProduced > 0) { - avgBlockTimeSeconds = timeElapsed / blocksProduced; - } - - return (true, avgBlockTimeSeconds); - } - - return (false, 0); - } -} -``` + + {BlockchainMonitor} + +Open example in Remix ## Related Interfaces diff --git a/docs/fdc/reference/IEVMTransaction.mdx b/docs/fdc/reference/IEVMTransaction.mdx index 172f67f9..2ce046dc 100644 --- a/docs/fdc/reference/IEVMTransaction.mdx +++ b/docs/fdc/reference/IEVMTransaction.mdx @@ -4,6 +4,10 @@ sidebar_position: 9 description: Relay a transaction from an EVM chain. --- +import CodeBlock from "@theme/CodeBlock"; +import EVMTransactionVerifier from "!!raw-loader!/examples/developer-hub-solidity/EVMTransactionVerifier.sol"; +import Remix from "@site/src/components/remix"; + An interface to relay and verify transactions from EVM-compatible blockchains. Sourced from `IEVMTransaction.sol` on [GitHub](https://github.com/flare-foundation/flare-smart-contracts-v2/blob/main/contracts/userInterfaces/fdc/IEVMTransaction.sol). @@ -251,99 +255,7 @@ When working with events, it's important to remember: ## Usage Example -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcHub.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcVerification.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/fdc/IEVMTransaction.sol"; - -contract EVMTransactionVerifier { - IFdcHub private fdcHub; - IFdcVerification private fdcVerification; - - bytes32 private constant ATTESTATION_TYPE_EVM_TX = 0x0600000000000000000000000000000000000000000000000000000000000000; - bytes32 private constant SOURCE_ID_ETH = 0x4554480000000000000000000000000000000000000000000000000000000000; - - // Event signatures we're interested in - bytes32 private constant EVENT_TRANSFER = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; - - constructor(address _fdcHubAddress, address _fdcVerificationAddress) { - fdcHub = IFdcHub(_fdcHubAddress); - fdcVerification = IFdcVerification(_fdcVerificationAddress); - } - - // Request verification of an EVM transaction with specific events - function requestTransactionVerification( - bytes32 transactionHash, - uint16 requiredConfirmations, - bool includeInput, - uint32[] calldata eventIndices - ) external payable { - // Create request body - IEVMTransaction.RequestBody memory requestBody = IEVMTransaction.RequestBody({ - transactionHash: transactionHash, - requiredConfirmations: requiredConfirmations, - provideInput: includeInput, - listEvents: eventIndices.length > 0, - logIndices: eventIndices - }); - - // Encode the full request - bytes memory encodedRequest = abi.encode( - ATTESTATION_TYPE_EVM_TX, - SOURCE_ID_ETH, - bytes32(0), // messageIntegrityCode (would need to be calculated properly) - requestBody - ); - - // Submit the request with payment - fdcHub.requestAttestation{value: msg.value}(encodedRequest); - } - - // Verify a provided proof and extract ERC-20 transfer information - function verifyERC20Transfer(IEVMTransaction.Proof calldata _proof) - external view - returns ( - bool success, - address tokenContract, - address from, - address to, - uint256 amount - ) - { - // Verify the proof using FdcVerification - bool proofVerified = fdcVerification.verifyEVMTransaction(_proof); - - if (proofVerified && _proof.data.responseBody.status == 1) { - // Look for Transfer events in the transaction - IEVMTransaction.Event[] memory events = _proof.data.responseBody.events; - - for (uint i = 0; i < events.length; i++) { - IEVMTransaction.Event memory evt = events[i]; - - // Check if this is a Transfer event (topic[0] is the event signature) - if (evt.topics.length >= 3 && evt.topics[0] == EVENT_TRANSFER) { - tokenContract = evt.emitterAddress; - - // ERC-20 Transfer(address indexed from, address indexed to, uint256 amount) - // topics[1] is the first indexed parameter (from address) - // topics[2] is the second indexed parameter (to address) - // The addresses are padded to 32 bytes, so we need to extract them - from = address(uint160(uint256(evt.topics[1]))); - to = address(uint160(uint256(evt.topics[2]))); - - // The amount is in the data field for non-indexed parameters - // It's a single uint256 value (32 bytes) - amount = abi.decode(evt.data, (uint256)); - - return (true, tokenContract, from, to, amount); - } - } - } - - return (false, address(0), address(0), address(0), 0); - } -} -``` + + {EVMTransactionVerifier.toString()} + +Open example in Remix diff --git a/docs/fdc/reference/IFdcHub.md b/docs/fdc/reference/IFdcHub.md index a4b48e25..38e2c7b1 100644 --- a/docs/fdc/reference/IFdcHub.md +++ b/docs/fdc/reference/IFdcHub.md @@ -4,6 +4,10 @@ sidebar_position: 2 description: Primary interface for interacting with FDC. --- +import CodeBlock from "@theme/CodeBlock"; +import AddressSolidity from "!!raw-loader!/examples/developer-hub-solidity/AddressSolidity.sol"; +import Remix from "@site/src/components/remix"; + Primary interface for interacting with the Flare Data Connector (FDC). Sourced from `IFdcHub.sol` on [GitHub](https://github.com/flare-foundation/flare-smart-contracts-v2/blob/main/contracts/userInterfaces/IFdcHub.sol). @@ -127,36 +131,7 @@ event RequestsOffsetSet( ## Usage Example -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcHub.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/fdc/IAddressValidity.sol"; - -contract AddressValidator { - IFdcHub private fdcHub; - - constructor(address _fdcHubAddress) { - fdcHub = IFdcHub(_fdcHubAddress); - } - - function validateAddress(string memory addressStr, bytes32 sourceId) external payable { - // Create address validity request - IAddressValidity.RequestBody memory requestBody = IAddressValidity.RequestBody({ - addressStr: addressStr - }); - - // Encode the full request - bytes memory encodedRequest = abi.encode( - bytes32(0x05), // attestationType for AddressValidity - sourceId, - bytes32(0), // messageIntegrityCode - should be calculated properly - requestBody - ); - - // Submit the request with appropriate fee - fdcHub.requestAttestation{value: msg.value}(encodedRequest); - } -} -``` + + {AddressSolidity} + +Open example in Remix diff --git a/docs/fdc/reference/IFdcInflationConfigurations.md b/docs/fdc/reference/IFdcInflationConfigurations.md index 6c0c475d..858847a5 100644 --- a/docs/fdc/reference/IFdcInflationConfigurations.md +++ b/docs/fdc/reference/IFdcInflationConfigurations.md @@ -4,6 +4,10 @@ sidebar_position: 5 description: Interface for managing FDC inflation configuration. --- +import CodeBlock from "@theme/CodeBlock"; +import InflationMonitor from "!!raw-loader!/examples/developer-hub-solidity/InflationMonitor.sol"; +import Remix from "@site/src/components/remix"; + Interface for managing Flare Data Connector (FDC) inflation configuration. Sourced from `IFdcInflationConfigurations.sol` on [GitHub](https://github.com/flare-foundation/flare-smart-contracts-v2/blob/main/contracts/userInterfaces/IFdcInflationConfigurations.sol). @@ -75,32 +79,7 @@ struct FdcConfiguration { ## Usage Example -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcHub.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcInflationConfigurations.sol"; - -contract InflationMonitor { - IFdcHub private fdcHub; - - constructor(address _fdcHubAddress) { - fdcHub = IFdcHub(_fdcHubAddress); - } - - // Get inflation share for a specific attestation type and source - function getInflationShare(bytes32 attestationType, bytes32 source) external view returns (uint24) { - IFdcInflationConfigurations inflationConfigs = fdcHub.fdcInflationConfigurations(); - IFdcInflationConfigurations.FdcConfiguration[] memory configs = inflationConfigs.getFdcConfigurations(); - - for (uint i = 0; i < configs.length; i++) { - if (configs[i].attestationType == attestationType && configs[i].source == source) { - return configs[i].inflationShare; - } - } - - return 0; // Not found or no inflation share allocated - } -} -``` + + {InflationMonitor} + +Open example in Remix diff --git a/docs/fdc/reference/IFdcRequestFeeConfigurations.md b/docs/fdc/reference/IFdcRequestFeeConfigurations.md index 82ad5e83..237e6c93 100644 --- a/docs/fdc/reference/IFdcRequestFeeConfigurations.md +++ b/docs/fdc/reference/IFdcRequestFeeConfigurations.md @@ -4,6 +4,10 @@ sidebar_position: 4 description: Interface for managing FDC request fee configuration. --- +import CodeBlock from "@theme/CodeBlock"; +import FeeChecker from "!!raw-loader!/examples/developer-hub-solidity/FeeChecker.sol"; +import Remix from "@site/src/components/remix"; + Interface for managing FDC request fee configuration. Sourced from `IFdcRequestFeeConfigurations.sol` on [GitHub](https://github.com/flare-foundation/flare-smart-contracts-v2/blob/main/contracts/userInterfaces/IFdcRequestFeeConfigurations.sol). @@ -72,34 +76,7 @@ event TypeAndSourceFeeSet( ## Usage Example -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcHub.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcRequestFeeConfigurations.sol"; - -contract FeeChecker { - IFdcHub private fdcHub; - IFdcRequestFeeConfigurations private feeConfigs; - - constructor(address _fdcHubAddress) { - fdcHub = IFdcHub(_fdcHubAddress); - feeConfigs = fdcHub.fdcRequestFeeConfigurations(); - } - - function checkRequestFee(bytes memory attestationData) external view returns (uint256) { - // Get the fee required for this attestation request - return feeConfigs.getRequestFee(attestationData); - } - - function submitRequestWithFee(bytes memory attestationData) external payable { - // Check if enough fee is provided - uint256 requiredFee = feeConfigs.getRequestFee(attestationData); - require(msg.value >= requiredFee, "Insufficient fee"); - - // Submit the attestation request - fdcHub.requestAttestation{value: msg.value}(attestationData); - } -} -``` + + {FeeChecker} + +Open example in Remix diff --git a/docs/fdc/reference/IFdcVerification.md b/docs/fdc/reference/IFdcVerification.md index 2f6691f9..59c51bde 100644 --- a/docs/fdc/reference/IFdcVerification.md +++ b/docs/fdc/reference/IFdcVerification.md @@ -4,6 +4,10 @@ sidebar_position: 3 description: Interface for verifying FDC requests. --- +import CodeBlock from "@theme/CodeBlock"; +import AddressSolidity from "!!raw-loader!/examples/developer-hub-solidity/AddressSolidity.sol"; +import Remix from "@site/src/components/remix"; + Interface for verifying Flare Data Connector (FDC) attestation requests. Sourced from `IFdcVerification.sol` on [GitHub](https://github.com/flare-foundation/flare-smart-contracts-v2/blob/main/contracts/userInterfaces/IFdcVerification.sol). @@ -138,33 +142,7 @@ function verifyReferencedPaymentNonexistence( ## Usage Example -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcVerification.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/fdc/IAddressValidity.sol"; - -contract AddressValidator { - IFdcVerification private fdcVerification; - - constructor(address _fdcVerificationAddress) { - fdcVerification = IFdcVerification(_fdcVerificationAddress); - } - - // Function to verify if an address is valid using a provided proof - function isAddressValid(IAddressValidity.Proof memory proof) external view returns (bool isValid, string memory standardAddress) { - bool proofVerified = fdcVerification.verifyAddressValidity(proof); - - if (proofVerified) { - // If proof is valid, extract the response data - isValid = proof.data.responseBody.isValid; - standardAddress = proof.data.responseBody.standardAddress; - return (isValid, standardAddress); - } - - // If proof verification failed - return (false, ""); - } -} -``` + + {AddressSolidity} + +Open example in Remix diff --git a/docs/fdc/reference/IPayment.mdx b/docs/fdc/reference/IPayment.mdx index f4896872..c415c91a 100644 --- a/docs/fdc/reference/IPayment.mdx +++ b/docs/fdc/reference/IPayment.mdx @@ -4,6 +4,10 @@ sidebar_position: 10 description: Relay a transaction in native currency. --- +import CodeBlock from "@theme/CodeBlock"; +import PaymentVerifier from "!!raw-loader!/examples/developer-hub-solidity/PaymentVerifier.sol"; +import Remix from "@site/src/components/remix"; + An interface to relay and verify payment transactions in native currencies across multiple external blockchains. Sourced from `IPayment.sol` on [GitHub](https://github.com/flare-foundation/flare-smart-contracts-v2/blob/main/contracts/userInterfaces/fdc/IPayment.sol). @@ -257,89 +261,7 @@ Payment references allow for correlation of payments across chains and facilitat ## Usage Example -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcHub.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcVerification.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/fdc/IPayment.sol"; - -contract PaymentVerifier { - IFdcHub private fdcHub; - IFdcVerification private fdcVerification; - - bytes32 private constant ATTESTATION_TYPE_PAYMENT = 0x0100000000000000000000000000000000000000000000000000000000000000; - bytes32 private constant SOURCE_ID_BTC = 0x4254430000000000000000000000000000000000000000000000000000000000; - - // Store verified payments - mapping(bytes32 => bool) public verifiedPayments; // transactionId => verified - - constructor(address _fdcHubAddress, address _fdcVerificationAddress) { - fdcHub = IFdcHub(_fdcHubAddress); - fdcVerification = IFdcVerification(_fdcVerificationAddress); - } - - // Request verification of a payment transaction - function requestPaymentVerification( - bytes32 transactionId, - uint256 inUtxo, - uint256 utxo - ) external payable { - // Create request body - IPayment.RequestBody memory requestBody = IPayment.RequestBody({ - transactionId: transactionId, - inUtxo: inUtxo, - utxo: utxo - }); - - // Encode the full request - bytes memory encodedRequest = abi.encode( - ATTESTATION_TYPE_PAYMENT, - SOURCE_ID_BTC, - bytes32(0), // messageIntegrityCode (would need to be calculated properly) - requestBody - ); - - // Submit the request with payment - fdcHub.requestAttestation{value: msg.value}(encodedRequest); - } - - // Verify a provided payment proof - function verifyPayment(IPayment.Proof calldata _proof) - external - returns ( - bool success, - bytes32 sourceAddressHash, - bytes32 receivingAddressHash, - int256 amount, - bytes32 paymentReference - ) - { - // Verify the proof using FdcVerification - bool proofVerified = fdcVerification.verifyPayment(_proof); - - if (proofVerified) { - // Extract the payment details from the proof - bytes32 transactionId = _proof.data.requestBody.transactionId; - IPayment.ResponseBody memory response = _proof.data.responseBody; - - // Check if this is a successful payment - if (response.status == 0) { - // Store that this transaction has been verified - verifiedPayments[transactionId] = true; - - return ( - true, - response.sourceAddressHash, - response.receivingAddressHash, - response.receivedAmount, - response.standardPaymentReference - ); - } - } - - return (false, bytes32(0), bytes32(0), 0, bytes32(0)); - } -} -``` + + {PaymentVerifier} + +Open example in Remix diff --git a/docs/fdc/reference/IReferencedPaymentNonexistence.mdx b/docs/fdc/reference/IReferencedPaymentNonexistence.mdx index 145131c2..13f4a795 100644 --- a/docs/fdc/reference/IReferencedPaymentNonexistence.mdx +++ b/docs/fdc/reference/IReferencedPaymentNonexistence.mdx @@ -4,6 +4,10 @@ sidebar_position: 11 description: Assert whether an agreed-upon payment has not been made. --- +import CodeBlock from "@theme/CodeBlock"; +import PaymentDeadlineEnforcer from "!!raw-loader!/examples/developer-hub-solidity/PaymentDeadlineEnforcer.sol"; +import Remix from "@site/src/components/remix"; + An interface to verify that a specific payment, agreed to be completed by a certain deadline, has **not been made** on an external blockchain. Sourced from `IReferencedPaymentNonexistence.sol` on [GitHub](https://github.com/flare-foundation/flare-smart-contracts-v2/blob/main/contracts/userInterfaces/fdc/IReferencedPaymentNonexistence.sol). @@ -283,136 +287,7 @@ The standardPaymentReference is critical for this attestation type as it uniquel ## Usage Example -```solidity -// SPDX-License-Identifier: MIT -pragma solidity ^0.8.0; - -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcHub.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/IFdcVerification.sol"; -import "@flare-foundation/flare-smart-contracts-v2/contracts/userInterfaces/fdc/IReferencedPaymentNonexistence.sol"; - -contract PaymentDeadlineEnforcer { - IFdcHub private fdcHub; - IFdcVerification private fdcVerification; - - bytes32 private constant ATTESTATION_TYPE_PAYMENT_NONEXISTENCE = 0x0400000000000000000000000000000000000000000000000000000000000000; - bytes32 private constant SOURCE_ID_BTC = 0x4254430000000000000000000000000000000000000000000000000000000000; - - struct Agreement { - bytes32 destinationAddressHash; - uint256 amount; - bytes32 paymentReference; - uint64 startBlockNumber; - uint64 deadlineBlockNumber; - uint64 deadlineTimestamp; - bool checkSourceAddresses; - bytes32 sourceAddressesRoot; - bool liquidated; - } - - mapping(uint256 => Agreement) public agreements; - uint256 public nextAgreementId; - - constructor(address _fdcHubAddress, address _fdcVerificationAddress) { - fdcHub = IFdcHub(_fdcHubAddress); - fdcVerification = IFdcVerification(_fdcVerificationAddress); - } - - // Create a new payment agreement - function createAgreement( - bytes32 destinationAddressHash, - uint256 amount, - bytes32 paymentReference, - uint64 startBlockNumber, - uint64 deadlineBlockNumber, - uint64 deadlineTimestamp, - bool checkSourceAddresses, - bytes32 sourceAddressesRoot - ) external returns (uint256 agreementId) { - require(paymentReference != bytes32(0), "Payment reference cannot be zero"); - - agreementId = nextAgreementId++; - - agreements[agreementId] = Agreement({ - destinationAddressHash: destinationAddressHash, - amount: amount, - paymentReference: paymentReference, - startBlockNumber: startBlockNumber, - deadlineBlockNumber: deadlineBlockNumber, - deadlineTimestamp: deadlineTimestamp, - checkSourceAddresses: checkSourceAddresses, - sourceAddressesRoot: sourceAddressesRoot, - liquidated: false - }); - - return agreementId; - } - - // Request verification of payment nonexistence for an agreement - function checkPaymentMissed(uint256 agreementId) external payable { - Agreement storage agreement = agreements[agreementId]; - require(!agreement.liquidated, "Agreement already liquidated"); - - // Create request body - IReferencedPaymentNonexistence.RequestBody memory requestBody = IReferencedPaymentNonexistence.RequestBody({ - minimalBlockNumber: agreement.startBlockNumber, - deadlineBlockNumber: agreement.deadlineBlockNumber, - deadlineTimestamp: agreement.deadlineTimestamp, - destinationAddressHash: agreement.destinationAddressHash, - amount: agreement.amount, - standardPaymentReference: agreement.paymentReference, - checkSourceAddresses: agreement.checkSourceAddresses, - sourceAddressesRoot: agreement.sourceAddressesRoot - }); - - // Encode the full request - bytes memory encodedRequest = abi.encode( - ATTESTATION_TYPE_PAYMENT_NONEXISTENCE, - SOURCE_ID_BTC, - bytes32(0), // messageIntegrityCode (would need to be calculated properly) - requestBody - ); - - // Submit the request with payment - fdcHub.requestAttestation{value: msg.value}(encodedRequest); - } - - // Verify a provided proof of payment nonexistence and trigger liquidation - function verifyMissedPayment(uint256 agreementId, IReferencedPaymentNonexistence.Proof calldata _proof) - external - returns (bool liquidated) - { - Agreement storage agreement = agreements[agreementId]; - require(!agreement.liquidated, "Agreement already liquidated"); - - // Verify the proof using FdcVerification - bool proofVerified = fdcVerification.verifyReferencedPaymentNonexistence(_proof); - - if (proofVerified) { - // Extract request details and validate they match our agreement - IReferencedPaymentNonexistence.RequestBody memory request = _proof.data.requestBody; - - // Verify this proof is for the correct agreement - require( - request.minimalBlockNumber == agreement.startBlockNumber && - request.deadlineBlockNumber == agreement.deadlineBlockNumber && - request.deadlineTimestamp == agreement.deadlineTimestamp && - request.destinationAddressHash == agreement.destinationAddressHash && - request.amount == agreement.amount && - request.standardPaymentReference == agreement.paymentReference, - "Proof does not match agreement" - ); - - // Mark the agreement as liquidated - agreement.liquidated = true; - - // Trigger liquidation logic here - // ... - - return true; - } - - return false; - } -} -``` + + {PaymentDeadlineEnforcer} + +Open example in Remix diff --git a/examples/developer-hub-solidity/AddressSolidity.sol b/examples/developer-hub-solidity/AddressSolidity.sol new file mode 100644 index 00000000..c9806c68 --- /dev/null +++ b/examples/developer-hub-solidity/AddressSolidity.sol @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol"; +import {IFdcVerification} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcVerification.sol"; +import {IAddressValidity} from "@flarenetwork/flare-periphery-contracts/coston2/IAddressValidity.sol"; + +interface IAddressRegistry { + function registerAddress( + IAddressValidity.Proof memory _transaction + ) external; +} + +contract AddressRegistry is IAddressRegistry { + string[] public verifiedAddresses; + + function registerAddress( + IAddressValidity.Proof memory _transaction + ) public { + // 1. FDC Logic + // Check that this AddressValidity has indeed been confirmed by the FDC + require( + isAddressValidityProofValid(_transaction), + "Invalid transaction proof" + ); + + // 2. Business logic + string memory provedAddress = _transaction.data.requestBody.addressStr; + + verifiedAddresses.push(provedAddress); + } + + function isAddressValidityProofValid( + IAddressValidity.Proof memory transaction + ) public view returns (bool) { + // Use the library to get the verifier contract and verify that this transaction was proved by state connector + IFdcVerification fdc = ContractRegistry.getFdcVerification(); + return fdc.verifyAddressValidity(transaction); + } +} diff --git a/examples/developer-hub-solidity/AddressVerifier.sol b/examples/developer-hub-solidity/AddressVerifier.sol new file mode 100644 index 00000000..1928daa5 --- /dev/null +++ b/examples/developer-hub-solidity/AddressVerifier.sol @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol"; +import {IFdcVerification} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcVerification.sol"; +import {IAddressValidity} from "@flarenetwork/flare-periphery-contracts/coston2/IAddressValidity.sol"; + +contract AddressVerifier { + // On-chain business logic: stores the verification status of an address string. + mapping(string => bool) public isAddressVerified; + + event AddressVerified( + string indexed addressStr, + string standardAddress, + bytes32 standardAddressHash + ); + + function processAddressProof( + IAddressValidity.Proof calldata _proof + ) external { + // 1. FDC Logic: Verify the proof's authenticity with the Flare network. + require(isProofValid(_proof), "Invalid address validity proof"); + + // 2. Business Logic: Execute actions based on the verified proof data. + bool isValid = _proof.data.responseBody.isValid; + string calldata originalAddress = _proof.data.requestBody.addressStr; + + // Only take action if the FDC confirms the address is valid. + if (isValid) { + // Take action: update state and emit an event. + isAddressVerified[originalAddress] = true; + + emit AddressVerified( + originalAddress, + _proof.data.responseBody.standardAddress, + _proof.data.responseBody.standardAddressHash + ); + } + } + + function isProofValid( + IAddressValidity.Proof memory _proof + ) public view returns (bool) { + IFdcVerification fdcVerification = ContractRegistry + .getFdcVerification(); + return fdcVerification.verifyAddressValidity(_proof); + } +} diff --git a/examples/developer-hub-solidity/BlockchainMonitor.sol b/examples/developer-hub-solidity/BlockchainMonitor.sol new file mode 100644 index 00000000..5584834c --- /dev/null +++ b/examples/developer-hub-solidity/BlockchainMonitor.sol @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol"; +import {IFdcVerification} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcVerification.sol"; +import {IConfirmedBlockHeightExists} from "@flarenetwork/flare-periphery-contracts/coston2/IConfirmedBlockHeightExists.sol"; + +contract BlockchainMonitor { + uint64 public latestAverageBlockTimeSeconds; + + event BlockTimeCalculated( + uint64 indexed blockNumber, + uint64 averageBlockTime + ); + + function processBlockHeightProof( + IConfirmedBlockHeightExists.Proof calldata _proof + ) external { + // 1. FDC Logic: Verify the proof's authenticity with the Flare network. + require(isProofValid(_proof), "Invalid block height proof"); + + // 2. Business Logic: Execute actions based on the verified proof data. + uint64 blockNumber = _proof.data.requestBody.blockNumber; + uint64 blockTimestamp = _proof.data.responseBody.blockTimestamp; + uint64 lowestNumber = _proof + .data + .responseBody + .lowestQueryWindowBlockNumber; + uint64 lowestTimestamp = _proof + .data + .responseBody + .lowestQueryWindowBlockTimestamp; + + uint64 avgBlockTimeSeconds = 0; + if (blockNumber > lowestNumber) { + uint64 blocksProduced = blockNumber - lowestNumber; + uint64 timeElapsed = blockTimestamp - lowestTimestamp; + avgBlockTimeSeconds = timeElapsed / blocksProduced; + } + + // Take action: update state and emit an event with the new data. + latestAverageBlockTimeSeconds = avgBlockTimeSeconds; + emit BlockTimeCalculated(blockNumber, avgBlockTimeSeconds); + } + + function isProofValid( + IConfirmedBlockHeightExists.Proof memory _proof + ) public view returns (bool) { + IFdcVerification fdcVerification = ContractRegistry + .getFdcVerification(); + return fdcVerification.verifyConfirmedBlockHeightExists(_proof); + } +} diff --git a/examples/developer-hub-solidity/EVMTransactionVerifier.sol b/examples/developer-hub-solidity/EVMTransactionVerifier.sol new file mode 100644 index 00000000..106cc56d --- /dev/null +++ b/examples/developer-hub-solidity/EVMTransactionVerifier.sol @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol"; +import {IFdcVerification} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcVerification.sol"; +import {IEVMTransaction} from "@flarenetwork/flare-periphery-contracts/coston2/IEVMTransaction.sol"; + +contract EVMTransactionVerifier { + // A struct to hold the data from a verified ERC-20 transfer + struct VerifiedTransfer { + address tokenContract; + address from; + address to; + uint256 amount; + bytes32 transactionHash; + } + + // An array to store all transfers verified by this contract + VerifiedTransfer[] public verifiedTransfers; + + // The signature of the ERC-20 Transfer event + bytes32 private constant EVENT_TRANSFER_SIGNATURE = + keccak256(abi.encodePacked("Transfer(address,address,uint256)")); + + event TransferVerified( + bytes32 indexed transactionHash, + address indexed tokenContract, + address from, + address to, + uint256 amount + ); + + function processTransactionProof( + IEVMTransaction.Proof calldata _proof, + address _tokenContract + ) external { + // 1. FDC Logic: Verify the proof's authenticity with the Flare network. + require(isProofValid(_proof), "Invalid EVM transaction proof"); + require( + _proof.data.responseBody.status == 1, + "Transaction reverted or not found" + ); + + // 2. Business Logic: Iterate through events to find and record ERC-20 transfers. + IEVMTransaction.Event[] memory events = _proof.data.responseBody.events; + bytes32 txHash = _proof.data.requestBody.transactionHash; + + for (uint i = 0; i < events.length; i++) { + IEVMTransaction.Event memory evt = events[i]; + + // Filter for the specific token contract if provided + if ( + _tokenContract != address(0) && + evt.emitterAddress != _tokenContract + ) { + continue; + } + + // Check if the event is an ERC-20 Transfer: Transfer(address,address,uint256) + if ( + evt.topics.length == 3 && + evt.topics[0] == EVENT_TRANSFER_SIGNATURE + ) { + // Decode the event data + address from = address(uint160(uint256(evt.topics[1]))); + address to = address(uint160(uint256(evt.topics[2]))); + uint256 amount = abi.decode(evt.data, (uint256)); + + // Record the verified transfer + verifiedTransfers.push( + VerifiedTransfer({ + tokenContract: evt.emitterAddress, + from: from, + to: to, + amount: amount, + transactionHash: txHash + }) + ); + + emit TransferVerified( + txHash, + evt.emitterAddress, + from, + to, + amount + ); + } + } + } + + function isProofValid( + IEVMTransaction.Proof memory _proof + ) public view returns (bool) { + IFdcVerification fdcVerification = ContractRegistry + .getFdcVerification(); + return fdcVerification.verifyEVMTransaction(_proof); + } +} diff --git a/examples/developer-hub-solidity/FeeChecker.sol b/examples/developer-hub-solidity/FeeChecker.sol new file mode 100644 index 00000000..70344c8b --- /dev/null +++ b/examples/developer-hub-solidity/FeeChecker.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol"; +import {IFdcHub} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcHub.sol"; +import {IFdcRequestFeeConfigurations} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcRequestFeeConfigurations.sol"; + +contract FeeChecker { + function getRequestFee( + bytes calldata _attestationData + ) external view returns (uint256) { + // Use the registry to find the FdcHub + IFdcHub fdcHub = ContractRegistry.getFdcHub(); + + // From the FdcHub, get the current fee configuration contract + IFdcRequestFeeConfigurations feeConfigs = fdcHub + .fdcRequestFeeConfigurations(); + + // Return the fee for the given request data + return feeConfigs.getRequestFee(_attestationData); + } +} diff --git a/examples/developer-hub-solidity/InflationMonitor.sol b/examples/developer-hub-solidity/InflationMonitor.sol new file mode 100644 index 00000000..cb9119d9 --- /dev/null +++ b/examples/developer-hub-solidity/InflationMonitor.sol @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol"; +import {IFdcHub} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcHub.sol"; +import {IFdcInflationConfigurations} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcInflationConfigurations.sol"; + +contract InflationMonitor { + function getInflationShare( + bytes32 attestationType, + bytes32 source + ) external view returns (uint24) { + // Fetch the FdcHub from the registry to access other FDC contracts + IFdcHub fdcHub = ContractRegistry.getFdcHub(); + + // Get the inflation configurations contract + IFdcInflationConfigurations inflationConfigs = fdcHub + .fdcInflationConfigurations(); + + // Retrieve the entire array of configurations + IFdcInflationConfigurations.FdcConfiguration[] + memory configs = inflationConfigs.getFdcConfigurations(); + + // Loop through the array to find the matching configuration + for (uint i = 0; i < configs.length; i++) { + if ( + configs[i].attestationType == attestationType && + configs[i].source == source + ) { + return configs[i].inflationShare; + } + } + + // Return 0 if no matching configuration is found + return 0; + } +} diff --git a/examples/developer-hub-solidity/LockMonitor.sol b/examples/developer-hub-solidity/LockMonitor.sol new file mode 100644 index 00000000..03e27776 --- /dev/null +++ b/examples/developer-hub-solidity/LockMonitor.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol"; +import {IFdcVerification} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcVerification.sol"; +import {IBalanceDecreasingTransaction} from "@flarenetwork/flare-periphery-contracts/coston2/IBalanceDecreasingTransaction.sol"; + +contract LockMonitor { + // Business logic: stores which addresses are being monitored + mapping(bytes32 => bool) public lockedAddresses; + // Business logic: prevents re-processing the same violation proof + mapping(bytes32 => bool) public confirmedViolations; + + event ViolationConfirmed( + bytes32 indexed transactionId, + bytes32 indexed sourceAddressHash + ); + + function registerLockedAddress(bytes32 sourceAddressHash) external { + lockedAddresses[sourceAddressHash] = true; + } + function processViolationProof( + IBalanceDecreasingTransaction.Proof calldata _proof + ) external { + // 1. FDC Logic: Verify the proof's authenticity with the Flare network. + require(isProofValid(_proof), "Invalid transaction proof"); + + // 2. Business Logic: Execute actions based on the verified proof data. + bytes32 sourceAddressHash = _proof.data.responseBody.sourceAddressHash; + int256 spentAmount = _proof.data.responseBody.spentAmount; + bytes32 transactionId = _proof.data.requestBody.transactionId; + + // Check if a monitored address spent funds (a violation). + if (lockedAddresses[sourceAddressHash] && spentAmount > 0) { + require( + !confirmedViolations[transactionId], + "Violation already confirmed" + ); + + // Take action: log the violation and update state. + confirmedViolations[transactionId] = true; + lockedAddresses[sourceAddressHash] = false; // Example: remove from monitoring after violation. + + emit ViolationConfirmed(transactionId, sourceAddressHash); + } + } + + function isProofValid( + IBalanceDecreasingTransaction.Proof memory _proof + ) public view returns (bool) { + IFdcVerification fdcVerification = ContractRegistry + .getFdcVerification(); + return fdcVerification.verifyBalanceDecreasingTransaction(_proof); + } +} diff --git a/examples/developer-hub-solidity/PaymentDeadlineEnforcer.sol b/examples/developer-hub-solidity/PaymentDeadlineEnforcer.sol new file mode 100644 index 00000000..a6905350 --- /dev/null +++ b/examples/developer-hub-solidity/PaymentDeadlineEnforcer.sol @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol"; +import {IFdcVerification} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcVerification.sol"; +import {IReferencedPaymentNonexistence} from "@flarenetwork/flare-periphery-contracts/coston2/IReferencedPaymentNonexistence.sol"; + +contract PaymentDeadlineEnforcer { + struct Agreement { + bytes32 destinationAddressHash; + uint256 amount; + bytes32 paymentReference; + uint64 startBlockNumber; + uint64 deadlineBlockNumber; + uint64 deadlineTimestamp; + bool checkSourceAddresses; + bytes32 sourceAddressesRoot; + bool liquidated; + } + + mapping(uint256 => Agreement) public agreements; + uint256 public nextAgreementId; + + event AgreementCreated( + uint256 indexed agreementId, + bytes32 indexed paymentReference + ); + event AgreementLiquidated( + uint256 indexed agreementId, + bytes32 indexed paymentReference + ); + + function createAgreement( + bytes32 destinationAddressHash, + uint256 amount, + bytes32 paymentReference, + uint64 startBlockNumber, + uint64 deadlineBlockNumber, + uint64 deadlineTimestamp, + bool checkSourceAddresses, + bytes32 sourceAddressesRoot + ) external returns (uint256 agreementId) { + require( + paymentReference != bytes32(0), + "Payment reference cannot be zero" + ); + agreementId = nextAgreementId++; + + agreements[agreementId] = Agreement({ + destinationAddressHash: destinationAddressHash, + amount: amount, + paymentReference: paymentReference, + startBlockNumber: startBlockNumber, + deadlineBlockNumber: deadlineBlockNumber, + deadlineTimestamp: deadlineTimestamp, + checkSourceAddresses: checkSourceAddresses, + sourceAddressesRoot: sourceAddressesRoot, + liquidated: false + }); + + emit AgreementCreated(agreementId, paymentReference); + return agreementId; + } + function processMissedPaymentProof( + uint256 _agreementId, + IReferencedPaymentNonexistence.Proof calldata _proof + ) external { + Agreement storage agreement = agreements[_agreementId]; + require(!agreement.liquidated, "Agreement already liquidated"); + + // 1. FDC Logic: Verify the proof's authenticity with the Flare network. + require(isProofValid(_proof), "Invalid payment non-existence proof"); + + // 2. Business Logic: Ensure the proof corresponds to the correct on-chain agreement. + IReferencedPaymentNonexistence.RequestBody memory request = _proof + .data + .requestBody; + require( + request.standardPaymentReference == agreement.paymentReference, + "Proof reference mismatch" + ); + require( + request.destinationAddressHash == agreement.destinationAddressHash, + "Proof destination mismatch" + ); + require(request.amount == agreement.amount, "Proof amount mismatch"); + require( + request.deadlineBlockNumber == agreement.deadlineBlockNumber, + "Proof deadline block mismatch" + ); + require( + request.deadlineTimestamp == agreement.deadlineTimestamp, + "Proof deadline timestamp mismatch" + ); + + // Take action: liquidate the agreement. + agreement.liquidated = true; + emit AgreementLiquidated(_agreementId, agreement.paymentReference); + } + function isProofValid( + IReferencedPaymentNonexistence.Proof memory _proof + ) public view returns (bool) { + IFdcVerification fdcVerification = ContractRegistry + .getFdcVerification(); + return fdcVerification.verifyReferencedPaymentNonexistence(_proof); + } +} diff --git a/examples/developer-hub-solidity/PaymentVerifier.sol b/examples/developer-hub-solidity/PaymentVerifier.sol new file mode 100644 index 00000000..fe0033cf --- /dev/null +++ b/examples/developer-hub-solidity/PaymentVerifier.sol @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.25; + +import {ContractRegistry} from "@flarenetwork/flare-periphery-contracts/coston2/ContractRegistry.sol"; +import {IFdcVerification} from "@flarenetwork/flare-periphery-contracts/coston2/IFdcVerification.sol"; +import {IPayment} from "@flarenetwork/flare-periphery-contracts/coston2/IPayment.sol"; + +contract PaymentVerifier { + // A struct to store the details of a successfully verified payment. + struct VerifiedPayment { + bytes32 transactionId; + bytes32 sourceAddressHash; + bytes32 receivingAddressHash; + int256 receivedAmount; + bytes32 standardPaymentReference; + } + + // A public array to keep a log of all payments verified by this contract. + VerifiedPayment[] public verifiedPayments; + // A mapping to prevent the same transaction proof from being processed more than once. + mapping(bytes32 => bool) public processedTransactions; + + event PaymentVerified( + bytes32 indexed transactionId, + bytes32 indexed sourceAddressHash, + bytes32 indexed receivingAddressHash, + int256 receivedAmount, + bytes32 standardPaymentReference + ); + + function processPaymentProof(IPayment.Proof calldata _proof) external { + // 1. FDC Logic: Verify the proof's authenticity with the Flare network. + require(isProofValid(_proof), "Invalid payment proof"); + + // 2. Business Logic: Execute actions based on the verified proof data. + bytes32 transactionId = _proof.data.requestBody.transactionId; + IPayment.ResponseBody memory response = _proof.data.responseBody; + + // Ensure the payment was successful (status 0) and hasn't been processed before. + require(response.status == 0, "Payment status not successful"); + require( + !processedTransactions[transactionId], + "Payment already processed" + ); + + // Take action: update state, store the payment details, and emit an event. + processedTransactions[transactionId] = true; + + verifiedPayments.push( + VerifiedPayment({ + transactionId: transactionId, + sourceAddressHash: response.sourceAddressHash, + receivingAddressHash: response.receivingAddressHash, + receivedAmount: response.receivedAmount, + standardPaymentReference: response.standardPaymentReference + }) + ); + + emit PaymentVerified( + transactionId, + response.sourceAddressHash, + response.receivingAddressHash, + response.receivedAmount, + response.standardPaymentReference + ); + } + + function isProofValid( + IPayment.Proof memory _proof + ) public view returns (bool) { + IFdcVerification fdcVerification = ContractRegistry + .getFdcVerification(); + return fdcVerification.verifyPayment(_proof); + } +}