@anuragchvn-blip/mandatekit
Version:
Production-ready Web3 autopay SDK for crypto-based recurring payments using EIP-712 mandates
204 lines • 5.63 kB
JavaScript
/**
* Adapters for protocol integrations (Permit2, Vaults, Account Abstraction)
* @module adapters
*/
/**
* Permit2 contract address (same across all networks)
*/
export const PERMIT2_ADDRESS = '0x000000000022D473030F116dDEE9F6B43aC78BA3';
/**
* Create Permit2 approval data for a mandate
*
* @param mandate - Mandate requiring token approval
* @param permit2Signature - Permit2 signature from user
* @returns Permit2 data for batch processing
*
* @example
* ```typescript
* const permit2Data = createPermit2Approval(mandate, signature);
* // Use this data when executing mandate to avoid separate approve tx
* ```
*/
export function createPermit2Approval(mandate, permit2Signature) {
return {
token: mandate.token,
amount: BigInt(mandate.amount),
expiration: mandate.validBefore,
nonce: BigInt(mandate.nonce),
signature: permit2Signature,
};
}
/**
* Create a vault-backed mandate
*
* @param mandate - Base mandate
* @param vaultConfig - Vault configuration
* @returns Vault mandate with vault metadata
*
* @example
* ```typescript
* const vaultMandate = createVaultMandate(mandate, {
* vaultAddress: '0x...',
* vaultType: 'gnosis-safe',
* threshold: 2,
* });
* ```
*/
export function createVaultMandate(mandate, vaultConfig) {
return {
...mandate,
vault: vaultConfig,
// Subscriber should be the vault address
subscriber: vaultConfig.vaultAddress,
};
}
/**
* Gnosis Safe adapter helpers
*/
export const GnosisSafeAdapter = {
/**
* Encode mandate execution for Gnosis Safe
*/
encodeExecution(_mandate) {
// In real implementation, this would encode the proper calldata
return '0x...';
},
/**
* Get required signers for a Safe transaction
*/
async getRequiredSigners(_safeAddress, _threshold) {
// In real implementation, this would query the Safe contract
return [];
},
};
/**
* Create a user operation for mandate execution with paymaster
*
* @param mandate - Mandate to execute
* @param paymasterConfig - Paymaster configuration
* @returns User operation for bundler submission
*
* @example
* ```typescript
* const userOp = await createMandateUserOp(mandate, {
* paymasterAddress: '0x...',
* type: 'verifying',
* maxGasSponsorship: parseEther('0.01'),
* });
*
* // Submit to bundler
* await bundler.sendUserOperation(userOp);
* ```
*/
export async function createMandateUserOp(mandate, paymasterConfig) {
// In real implementation, this would construct full UserOperation
return {
sender: mandate.subscriber,
nonce: BigInt(mandate.nonce),
callData: '0x...',
paymasterAndData: encodePaymasterData(paymasterConfig),
};
}
/**
* Encode paymaster data
*/
function encodePaymasterData(config) {
// In real implementation, this would encode proper paymaster data
return `${config.paymasterAddress}000000000000000000000000`;
}
/**
* Create a session key for mandate operations
*
* @param config - Session key configuration
* @returns Session key data for storage
*
* @example
* ```typescript
* const sessionKey = createSessionKey({
* sessionKey: '0x...',
* permissions: {
* canSign: true,
* canExecute: false,
* canCancel: false,
* },
* expiresAt: Date.now() / 1000 + 86400, // 24 hours
* maxAmount: parseEther('100'),
* allowedTokens: [USDC_ADDRESS],
* });
* ```
*/
export function createSessionKey(config) {
return config;
}
/**
* Validate session key permissions for an operation
*/
export function validateSessionKey(sessionKey, operation, mandate) {
// Check expiration
if (sessionKey.expiresAt < Date.now() / 1000) {
return false;
}
// Check permissions
const canPerform = {
sign: sessionKey.permissions.canSign,
execute: sessionKey.permissions.canExecute,
cancel: sessionKey.permissions.canCancel,
}[operation];
if (!canPerform) {
return false;
}
// Check mandate-specific restrictions
if (mandate) {
// Check amount limit
if (sessionKey.maxAmount && BigInt(mandate.amount) > sessionKey.maxAmount) {
return false;
}
// Check allowed tokens
if (sessionKey.allowedTokens && !sessionKey.allowedTokens.includes(mandate.token)) {
return false;
}
}
return true;
}
/**
* DeFi protocol adapters
*/
/**
* Aave adapter for subscription payments from lending positions
*/
export const AaveAdapter = {
/**
* Create mandate that pulls from Aave aToken balance
*/
createATokenMandate(baseMandate, aTokenAddress) {
return {
...baseMandate,
token: aTokenAddress, // Use aToken instead of underlying
metadata: JSON.stringify({
protocol: 'aave',
underlyingToken: baseMandate.token,
...JSON.parse(baseMandate.metadata ?? '{}'),
}),
};
},
};
/**
* Compound adapter for subscription payments from lending positions
*/
export const CompoundAdapter = {
/**
* Create mandate that pulls from Compound cToken balance
*/
createCTokenMandate(baseMandate, cTokenAddress) {
return {
...baseMandate,
token: cTokenAddress,
metadata: JSON.stringify({
protocol: 'compound',
underlyingToken: baseMandate.token,
...JSON.parse(baseMandate.metadata ?? '{}'),
}),
};
},
};
//# sourceMappingURL=index.js.map