Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Payments - Receive on chain payments for off chain items #13

Merged
merged 17 commits into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 136 additions & 98 deletions .gas-snapshot

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import util from 'util'
import {
BUILD_DIR,
DEPLOYABLE_CONTRACT_NAMES,
TOKEN_CONTRACT_NAMES,
PROXIED_TOKEN_CONTRACT_NAMES,
} from './constants'
const exec = util.promisify(execNonPromise)

Expand All @@ -27,7 +27,7 @@ const main = async () => {
// Create the compiler input files
for (const solFile of [
...DEPLOYABLE_CONTRACT_NAMES,
...TOKEN_CONTRACT_NAMES,
...PROXIED_TOKEN_CONTRACT_NAMES,
'TransparentUpgradeableBeaconProxy',
'UpgradeableBeacon',
]) {
Expand Down
4 changes: 3 additions & 1 deletion scripts/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@ export const DEPLOYABLE_CONTRACT_NAMES = [
'ERC1155SaleFactory',
'ERC1155SoulboundFactory',
'PaymentCombiner',
'PaymentsFactory',
'Clawback',
'ClawbackMetadata',
]
export const TOKEN_CONTRACT_NAMES = [
export const PROXIED_TOKEN_CONTRACT_NAMES = [
'ERC20Items',
'ERC721Items',
'ERC721Sale',
'ERC721Soulbound',
'ERC1155Items',
'ERC1155Sale',
'ERC1155Soulbound',
'Payments',
]
4 changes: 2 additions & 2 deletions scripts/outputSelectors.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TOKEN_CONTRACT_NAMES } from './constants'
import { PROXIED_TOKEN_CONTRACT_NAMES } from './constants'

const { spawn } = require('child_process')

Expand Down Expand Up @@ -31,4 +31,4 @@ const outputSelectors = (contractName: string) => {
})
}

TOKEN_CONTRACT_NAMES.forEach(outputSelectors)
PROXIED_TOKEN_CONTRACT_NAMES.forEach(outputSelectors)
139 changes: 139 additions & 0 deletions src/payments/IPayments.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;

interface IPaymentsFunctions {
enum TokenType {
ERC20,
ERC721,
ERC1155
}

struct PaymentRecipient {
// Payment recipient
address recipient;
// Payment amount
uint256 amount;
}

struct ChainedCallDetails {
// Address for chained call
address chainedCallAddress;
// Data for chained call
bytes chainedCallData;
}

struct PaymentDetails {
// Unique ID for this purchase
uint256 purchaseId;
// Recipient of the purchased product
address productRecipient;
// Type of payment token
TokenType tokenType;
// Token address to use for payment
address tokenAddress;
// Token ID to use for payment. Used for ERC-721 and 1155 payments
uint256 tokenId;
// Payment receipients
PaymentRecipient[] paymentRecipients;
// Expiration time of the payment
uint64 expiration;
// ID of the product
string productId;
// Chained call details
ChainedCallDetails chainedCallDetails;
}

/**
* Returns the hash of the payment details.
* @param paymentDetails The payment details.
* @return paymentHash The hash of the payment details for signing.
*/
function hashPaymentDetails(PaymentDetails calldata paymentDetails) external view returns (bytes32 paymentHash);

/**
* Check is a payment signature is valid.
* @param paymentDetails The payment details.
* @param signature The signature of the payment.
* @return isValid True if the signature is valid.
*/
function isValidPaymentSignature(PaymentDetails calldata paymentDetails, bytes calldata signature)
external
view
returns (bool isValid);

/**
* Make a payment for a product.
* @param paymentDetails The payment details.
* @param signature The signature of the payment.
*/
function makePayment(PaymentDetails calldata paymentDetails, bytes calldata signature) external payable;

/**
* Check if a payment has been accepted.
* @param purchaseId The ID of the purchase.
* @return accepted True if the payment has been accepted.
*/
function paymentAccepted(uint256 purchaseId) external view returns (bool);

/**
* Returns the hash of the chained call.
* @param chainedCallDetails The chained call details.
* @return callHash The hash of the chained call for signing.
*/
function hashChainedCallDetails(ChainedCallDetails calldata chainedCallDetails)
external
view
returns (bytes32 callHash);

/**
* Complete a chained call.
* @param chainedCallDetails The chained call details.
* @param signature The signature of the chained call.
* @dev This is called when a payment is accepted off/cross chain.
*/
function performChainedCall(ChainedCallDetails calldata chainedCallDetails, bytes calldata signature) external;

/**
* Check is a chained call signature is valid.
* @param chainedCallDetails The chained call details.
* @param signature The signature of the chained call.
* @return isValid True if the signature is valid.
*/
function isValidChainedCallSignature(ChainedCallDetails calldata chainedCallDetails, bytes calldata signature)
external
view
returns (bool isValid);

/**
* Get the signer address.
* @return signer The signer address.
*/
function signer() external view returns (address);
}

interface IPaymentsSignals {
/// @notice Emitted when contract is already initialized.
error InvalidInitialization();

/// @notice Emitted when a payment is already accepted. This prevents double spending.
error PaymentAlreadyAccepted();

/// @notice Emitted when a signature is invalid.
error InvalidSignature();

/// @notice Emitted when a payment has expired.
error PaymentExpired();

/// @notice Emitted when a token transfer is invalid.
error InvalidTokenTransfer();

/// @notice Emitted when a chained call fails.
error ChainedCallFailed();

/// @notice Emitted when a payment is made.
event PaymentMade(
address indexed spender, address indexed productRecipient, uint256 indexed purchaseId, string productId
);
}

interface IPayments is IPaymentsFunctions, IPaymentsSignals {}
36 changes: 36 additions & 0 deletions src/payments/IPaymentsFactory.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;

interface IPaymentsFactoryFunctions {
/**
* Creates a Payments proxy contract
* @param proxyOwner The owner of the Payments proxy
* @param paymentsOwner The owner of the Payments implementation
* @param paymentsSigner The signer of the Payments implementation
* @return proxyAddr The address of the Payments proxy
*/
function deploy(address proxyOwner, address paymentsOwner, address paymentsSigner)
external
returns (address proxyAddr);

/**
* Computes the address of a proxy instance.
* @param proxyOwner The owner of the Payments proxy
* @param paymentsOwner The owner of the Payments implementation
* @param paymentsSigner The signer of the Payments implementation
* @return proxyAddr The address of the Payments proxy
*/
function determineAddress(address proxyOwner, address paymentsOwner, address paymentsSigner)
external
returns (address proxyAddr);
}

interface IPaymentsFactorySignals {
/**
* Event emitted when a new Payments proxy contract is deployed.
* @param proxyAddr The address of the deployed proxy.
*/
event PaymentsDeployed(address proxyAddr);
}

interface IPaymentsFactory is IPaymentsFactoryFunctions, IPaymentsFactorySignals {}
Loading
Loading