old_Loopcrypto.xyz
  • Introduction
  • Supported networks and tokens
  • Loop + Frames
  • Learn
    • How Loop works
    • Core components
      • Collecting authorization
        • Enabling payment on multiple networks
        • Accepting ETH and MATIC
      • Sending payment requests
      • Checking a customer's balance & allowance
      • Receipts and reminders
      • Customer portal
    • Loop + your financial stack
      • Linking on-chain transactions with invoices in your ERP system
      • Connecting with accounting software
      • Crypto off-ramp
    • Case studies
  • Dashboard functionality
    • Subscriptions
      • Free trials, discounts and more
      • Auto-invoicing
      • Auto-cancelations
    • One-time payments
    • Scheduling outbound payments
      • Internal notes
    • Editing an upcoming payment
    • Payments for platforms
  • Integrations
    • Stripe + Loop
      • Getting setup
      • Stripe Connect setup
      • Subscriptions
        • Free trials
        • Upgrading a customer or editing a subscription's products
      • Invoicing
      • One-time payments
      • Coupon codes
      • Stripe Connect - Subscriptions
      • FAQs about Stripe integration
    • Chargebee + Loop
      • Getting setup
      • Subscriptions
      • One-time payments
      • Coupon codes
    • Quickbooks + Loop
      • Invoicing
    • Xero + Loop
      • Invoicing
    • Ghost.org + Loop
    • Zapier + Loop
    • Manually add integrations
  • Technical Docs
    • APIs
      • Entity
        • Adding child entities
        • Adding user to child entity
        • Get child entities
      • Items
        • Adding items
          • Item types
          • Categories
        • Retrieving an item
        • Updating an item
        • Deactivating an item
      • Agreements
      • Transfer requests
        • Signing transfer requests
        • Loop CLI
        • Canceling transfer requests
        • Transfer request status
        • Handling unfulfilled transfer requests
        • Validations
      • Webhooks
        • Checking webhook signatures
        • Demo App
        • Slack, Airtable, Discord, Telegram
    • Archeticture
      • Smart contract
        • Deploying your smart contract
          • Modifying smart contract properties
      • Collecting authorization
        • Checkout page
          • Additional functionality
          • Add "pay with crypto" button
        • Checkout widget
          • NPM package readme
        • Checkout parameter examples
      • Providing on-chain payment based access
        • Subscription gated communities
    • Loop SDK
      • Verify Webhook
      • Transfers
      • Error Handling
      • Generating API keys
    • Sample guide: Collect a subscription or one-time payment
    • Integrating the Loop Protocol into your dApp
      • Payroll applications
      • Loan platforms (credit cards, BNPL)
    • Security
      • API Authentication
      • Securing with signatures
      • API Trust assumptions
      • Audits
  • FAQs
  • Company Dashboard
  • Loop Portal
Powered by GitBook
On this page
  1. Technical Docs
  2. Security

Securing with signatures

The Loop smart contract validates all transfer requests sent to it by validating that the message signer matches the signer address that is stored in the contact. If the signer values don't match, the transfer request fails and the contract moves onto the next transfer request.

This validation is performed regardless of whether a Company has delegated signing of on-chain transactions to Loop, or whether a Company optionally has elected to sign transfer requests themselves.

All transfer requests must be signed in accordance with EIP-712.

Transfer request data structure

The JSON structure of the transfer request object is as follows:

{ 
    "invoiceId": "ch_3Ljpa52eZvKYlo2C1VHbn91O", 
    "to": "0x0f2672BA12aed17BEe075F7AEabC24b98E3098Ca", 
    "from": "0xad4efce746f129a9df375af2ddcf9097531eb466",     
    "token": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "amount": "1000000000",  
    "usd": false
}

From which we can derive the following data structure:

Transfer: { 
    invoiceId: string,
    from: address,
    to: address,
    token: address,
    amount: uint256,
    usd: bool
}

Domain separator

The domain separator ensures that the signatures generated for transfer requests are only compatible with the Loop smart contract

Attribute
Value
Description

name

LoopVariableRatesContract

The name of the application

version

1

The current version of the signing domain

chainId

Network dependent

This prevents a signature meant for one network from working on another

verifyingContract

Network dependent

The contract address that will verify the signature

Putting it all together with code

This example code is written in Javascript and shows how to use the domain, types and message content together to sign and generate a signature using the EIP-712 standard.

1. Define the domain data, example uses Polygon as the network:

const domain = {
    name: "LoopVariableRatesContract",
    version: "1",
    chainId: 137,
    verifyingContract: "0x26f1cB8611b15E6e3859d8Cf0ef294b7855d2135"
};

2. Define the data types:

const types = {
    Transfer: [
        { name: "invoiceId", type: "string" },
        { name: "from", type: "address" },
        { name: "to", type: "address" },
        { name: "token", type: "address" },
        { name: "amount", type: "uint256" },
        { name: "usd", type: "bool" }
    ]
};

3. Define the message:

const transferParams = {
    invoiceId: "ch_3LjpW92eZvKYlo2C0RYz8S7X",
    from: "0xad4efce746f129a9df375af2ddcf9097531eb466",
    to: "0x0f2672BA12aed17BEe075F7AEabC24b98E3098Ca",
    token: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
    amount: 100000000,  // e.g. 100 USDC
    usd: false
};

4. Sign the message using ethers:

Note: If using ethers V5, the signTypedData function is prefixed with an underscore:

const signature = await signer._signTypedData(...)
const signer = new ethers.Wallet("YOUR_PRIVATE_KEY", ethers.provider)
const signature = await signer.signTypedData(
    domain,
    types,
    transferParams
);
PreviousAPI AuthenticationNextAPI Trust assumptions

Last updated 1 year ago

The chain id.

EIP-155