Security
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
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.
- Define the domain data, example uses Polygon as the network:
const domain = {
name: "LoopVariableRatesContract",
version: "1",
chainId: 137,
verifyingContract: "0x26f1cB8611b15E6e3859d8Cf0ef294b7855d2135"
};
- 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" }
]
};
- Define the message:
const transferParams = {
invoiceId: "ch_3LjpW92eZvKYlo2C0RYz8S7X",
from: "0xad4efce746f129a9df375af2ddcf9097531eb466",
to: "0x0f2672BA12aed17BEe075F7AEabC24b98E3098Ca",
token: "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
amount: 100000000, // e.g. 100 USDC
usd: false
};
- Sign the message using ethers:
const signer = new ethers.Wallet("YOUR_PRIVATE_KEY", ethers.provider)
const signature = await signer.signTypedData(
domain,
types,
transferParams
);
Note: If using ethers V5, the signTypedData function is prefixed with an underscore:
const signature = await signer._signTypedData(...)
Updated about 1 month ago