Skip to content
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
98 changes: 18 additions & 80 deletions packages/client/src/actions/transactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,17 @@ import type { AaveClient } from '../AaveClient';
*
* ```ts
* const result = await borrow(client, {
* market: market.address,
* amount: {
* erc20: {
* currency: evmAddress('0x5678…'),
* value: bigDecimal('1000'),
* },
* },
* borrower: evmAddress('0x9abc…'),
* chainId: market.chain.chainId,
* reserve: {
* spoke: evmAddress('0x87870bca…'),
* reserveId: reserveId(1),
* chainId: chainId(1),
* },
* sender: evmAddress('0x9abc…'),
* }).andThen(sendWith(wallet)).andThen(client.waitForTransaction);
*
* if (result.isErr()) {
Expand Down Expand Up @@ -76,7 +78,6 @@ export function borrow(
* },
* amount: {
* erc20: {
* currency: evmAddress('0x5678…'),
* value: bigDecimal('1000'),
* },
* },
Expand Down Expand Up @@ -109,17 +110,19 @@ export function supply(
*
* ```ts
* const result = await repay(client, {
* market: market.address,
* amount: {
* erc20: {
* currency: evmAddress('0x5678…'),
* value: {
* exact: bigDecimal('500'),
* },
* },
* },
* borrower: evmAddress('0x9abc…'),
* chainId: market.chain.chainId,
* sender: evmAddress('0x9abc…'),
* reserve: {
* spoke: evmAddress('0x87870bca…'),
* reserveId: reserveId(1),
* chainId: chainId(1),
* },
* }).andThen(sendWith(wallet)).andThen(client.waitForTransaction);
*
* if (result.isErr()) {
Expand Down Expand Up @@ -310,67 +313,6 @@ export function updateUserRiskPremium(
return client.query(UpdateUserRiskPremiumQuery, { request });
}

/**
* Creates a transaction to enable/disable a specific supplied asset as collateral.
*
* ```ts
* const result = await collateralToggle(client, {
* market: market.address,
* underlyingToken: market.supplyReserves[n].underlyingToken.address,
* user: evmAddress('0x9abc…'),
* chainId: market.chain.chainId,
* }).andThen(sendWith(wallet)).andThen(client.waitForTransaction);
*
* if (result.isErr()) {
* // Handle error, e.g. signing error, etc.
* return;
* }
*
* // result.value: TxHash
* ```
*
* @param client - Aave client.
* @param request - The collateral toggle request parameters.
* @returns The transaction request data to toggle collateral.
*/
// export function collateralToggle(
// client: AaveClient,
// request: CollateralToggleRequest,
// ): ResultAsync<TransactionRequest, UnexpectedError> {
// return client.query(CollateralToggleQuery, { request });
// }

/**
* Creates a transaction to liquidate a non-healthy position with Health Factor below 1.
*
* ```ts
* const result = await liquidate(client, {
* collateralToken: evmAddress('0x1234…'),
* debtToken: evmAddress('0x5678…'),
* user: evmAddress('0x9abc…'),
* debtToCover: { max: true },
* chainId: chainId(1),
* }).andThen(sendWith(wallet)).andThen(client.waitForTransaction);
*
* if (result.isErr()) {
* // Handle error, e.g. signing error, etc.
* return;
* }
*
* // result.value: TxHash
* ```
*
* @param client - Aave client.
* @param request - The liquidate request parameters.
* @returns The transaction request data to liquidate position.
*/
// export function liquidate(
// client: AaveClient,
// request: LiquidateRequest,
// ): ResultAsync<TransactionRequest, UnexpectedError> {
// return client.query(LiquidateQuery, { request });
// }

/**
* Creates a transaction to liquidate a user's position.
*
Expand All @@ -383,13 +325,10 @@ export function updateUserRiskPremium(
* collateral: reserveId(1),
* debt: reserveId(2),
* amount: {
* erc20: {
* currency: evmAddress('0x5678…'),
* value: '1000',
* },
* exact: bigDecimal('1000'),
* },
* liquidator: evmAddress('0x9abc…'),
* borrower: evmAddress('0xdef0…'),
* user: evmAddress('0xdef0…'),
* }).andThen(sendWith(wallet)).andThen(client.waitForTransaction);
*
* if (result.isErr()) {
Expand Down Expand Up @@ -466,18 +405,17 @@ export function setSpokeUserPositionManager(
* const result = await preview(client, {
* action: {
* supply: {
* spoke: {
* address: evmAddress('0x87870bca…'),
* reserve: {
* spoke: evmAddress('0x87870bca…'),
* reserveId: reserveId(1),
* chainId: chainId(1),
* },
* reserve: reserveId(1),
* amount: {
* erc20: {
* currency: evmAddress('0x5678…'),
* value: '1000',
* },
* },
* supplier: evmAddress('0x9abc…'),
* sender: evmAddress('0x9abc…'),
* },
* },
* });
Expand Down
19 changes: 19 additions & 0 deletions packages/client/src/ethers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import {
ValidationError,
} from '@aave/core-next';
import type {
CancelSwapTypedData,
InsufficientBalanceError,
PermitTypedDataResponse,
SwapByIntentTypedData,
TransactionRequest,
} from '@aave/graphql-next';
import {
Expand All @@ -21,6 +23,7 @@ import type { Signer, TransactionResponse } from 'ethers';
import type {
ExecutionPlanHandler,
PermitHandler,
SwapSignatureHandler,
TransactionResult,
} from './types';

Expand Down Expand Up @@ -117,3 +120,19 @@ export function signERC20PermitWith(signer: Signer): PermitHandler {
}));
};
}

/**
* Signs swap typed data using the provided ethers signer.
*/
export function signSwapTypedDataWith(signer: Signer): SwapSignatureHandler {
return (result: SwapByIntentTypedData | CancelSwapTypedData) => {
const message = JSON.parse(result.message);
return ResultAsync.fromPromise(
signer.signTypedData(result.domain, result.types, message),
(err) => SigningError.from(err),
).map((signature) => ({
deadline: message.deadline,
value: signatureFrom(signature),
}));
};
}
30 changes: 30 additions & 0 deletions packages/client/src/privy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {
ValidationError,
} from '@aave/core-next';
import type {
CancelSwapTypedData,
InsufficientBalanceError,
PermitTypedDataResponse,
SwapByIntentTypedData,
TransactionRequest,
} from '@aave/graphql-next';
import {
Expand All @@ -22,6 +24,7 @@ import { waitForTransactionReceipt } from 'viem/actions';
import type {
ExecutionPlanHandler,
PermitHandler,
SwapSignatureHandler,
TransactionResult,
} from './types';
import { supportedChains, transactionError } from './viem';
Expand Down Expand Up @@ -135,3 +138,30 @@ export function signERC20PermitWith(
}));
};
}

/**
* Signs swap typed data using the provided Privy client.
*/
export function signSwapTypedDataWith(
privy: PrivyClient,
walletId: string,
): SwapSignatureHandler {
return (result: SwapByIntentTypedData | CancelSwapTypedData) => {
const message = JSON.parse(result.message);
return ResultAsync.fromPromise(
privy.walletApi.ethereum.signTypedData({
walletId,
typedData: {
domain: result.domain,
types: result.types,
message,
primaryType: result.primaryType,
},
}),
(err) => SigningError.from(err),
).map((response) => ({
deadline: message.deadline,
value: signatureFrom(response.signature),
}));
};
}
39 changes: 39 additions & 0 deletions packages/client/src/thirdweb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import {
ValidationError,
} from '@aave/core-next';
import type {
CancelSwapTypedData,
InsufficientBalanceError,
PermitTypedDataResponse,
SwapByIntentTypedData,
TransactionRequest,
} from '@aave/graphql-next';
import {
Expand All @@ -26,6 +28,7 @@ import {
import type {
ExecutionPlanHandler,
PermitHandler,
SwapSignatureHandler,
TransactionResult,
} from './types';

Expand Down Expand Up @@ -139,3 +142,39 @@ export function signERC20PermitWith(client: ThirdwebClient): PermitHandler {
}));
};
}

/**
* Signs swap typed data using the provided Thirdweb client.
*/
export function signSwapTypedDataWith(
client: ThirdwebClient,
): SwapSignatureHandler {
return (result: SwapByIntentTypedData | CancelSwapTypedData) => {
const message = JSON.parse(result.message);

const signTypedDataPromise = async (): Promise<Signature> => {
const wallet = Engine.serverWallet({
client,
chain: defineChain({ id: result.domain.chainId }),
address: message.user,
});

const signature = await wallet.signTypedData({
// silence the rest of the type inference
types: result.types as Record<string, unknown>,
domain: result.domain,
primaryType: result.primaryType,
message,
});

return signatureFrom(signature);
};

return ResultAsync.fromPromise(signTypedDataPromise(), (err) =>
SigningError.from(err),
).map((value) => ({
deadline: message.deadline,
value,
}));
};
}
6 changes: 6 additions & 0 deletions packages/client/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import type {
ValidationError,
} from '@aave/core-next';
import type {
CancelSwapTypedData,
ERC712Signature,
ExecutionPlan,
HasProcessedKnownTransactionRequest,
InsufficientBalanceError,
OperationType,
PermitTypedDataResponse,
SwapByIntentTypedData,
} from '@aave/graphql-next';
import type { ResultAsync, TxHash } from '@aave/types-next';

Expand Down Expand Up @@ -46,3 +48,7 @@ export type ExecutionPlanHandler<T extends ExecutionPlan = ExecutionPlan> = (
export type PermitHandler = (
result: PermitTypedDataResponse,
) => ResultAsync<ERC712Signature, SigningError>;

export type SwapSignatureHandler = (
result: CancelSwapTypedData | SwapByIntentTypedData,
) => ResultAsync<ERC712Signature, SigningError>;
28 changes: 28 additions & 0 deletions packages/client/src/viem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import {
ValidationError,
} from '@aave/core-next';
import type {
CancelSwapTypedData,
InsufficientBalanceError,
PermitTypedDataResponse,
SwapByIntentTypedData,
TransactionRequest,
} from '@aave/graphql-next';
import {
Expand Down Expand Up @@ -39,6 +41,7 @@ import { mainnet } from 'viem/chains';
import type {
ExecutionPlanHandler,
PermitHandler,
SwapSignatureHandler,
TransactionResult,
} from './types';

Expand Down Expand Up @@ -195,3 +198,28 @@ export function signERC20PermitWith(walletClient: WalletClient): PermitHandler {
}));
};
}

/**
* Signs swap typed data using the provided wallet client.
*/
export function signSwapTypedDataWith(
walletClient: WalletClient,
): SwapSignatureHandler {
return (result: SwapByIntentTypedData | CancelSwapTypedData) => {
invariant(walletClient.account, 'Wallet account is required');

return ResultAsync.fromPromise(
signTypedData(walletClient, {
account: walletClient.account,
domain: result.domain as TypedDataDomain,
types: result.types as TypedData,
primaryType: result.primaryType,
message: JSON.parse(result.message),
}),
(err) => SigningError.from(err),
).map((hex) => ({
deadline: JSON.parse(result.message).deadline,
value: signatureFrom(hex),
}));
};
}
2 changes: 0 additions & 2 deletions packages/graphql/src/fragments/swaps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,6 @@ export const SwapStatusFragment: FragmentDocumentFor<SwapStatus, 'SwapStatus'> =

export const CancelSwapTypeDefinitionFragment = graphql(
`fragment CancelSwapTypeDefinition on CancelSwapTypeDefinition {
__typename
OrderCancellations {
...TypeField
}
Expand All @@ -369,7 +368,6 @@ export type CancelSwapTypeDefinition = FragmentOf<

export const CancelSwapTypedDataFragment = graphql(
`fragment CancelSwapTypedData on CancelSwapTypedData {
__typename
types {
...CancelSwapTypeDefinition
}
Expand Down
Loading