-
Notifications
You must be signed in to change notification settings - Fork 639
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
raps v2 #6138
raps v2 #6138
Changes from all commits
382c49d
d4dd19b
3d8d9d1
c268875
9beb669
8d7b65b
d6d69ce
112fd07
d624f5c
2226d95
e556e60
8b64245
198310c
1ceea03
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { ActionProps } from '../references'; | ||
import { sendTransaction } from '@/model/wallet'; | ||
import { getProvider } from '@/handlers/web3'; | ||
import { RainbowError } from '@/logger'; | ||
import { addNewTransaction } from '@/state/pendingTransactions'; | ||
import { NewTransaction } from '@/entities'; | ||
import { chainsName } from '@/chains'; | ||
|
||
export async function claimTransactionClaimable({ parameters, wallet }: ActionProps<'claimTransactionClaimableAction'>) { | ||
// will uncomment actual logic in follow-up PR, don't worry about it for now | ||
return { nonce: undefined, hash: undefined }; | ||
|
||
// const { claimTx } = parameters; | ||
|
||
// const provider = getProvider({ chainId: claimTx.chainId }); | ||
// const result = await sendTransaction({ transaction: claimTx, existingWallet: wallet, provider }); | ||
|
||
// if (!result?.result || !!result.error || !result.result.hash) { | ||
// throw new RainbowError('[CLAIM-TRANSACTION-CLAIMABLE]: failed to execute claim transaction'); | ||
// } | ||
|
||
// const transaction = { | ||
// amount: result.result.value.toString(), | ||
// gasLimit: result.result.gasLimit, | ||
// from: result.result.from ?? null, | ||
// to: result.result.to ?? null, | ||
// chainId: result.result.chainId, | ||
// hash: result.result.hash, | ||
// network: chainsName[result.result.chainId], | ||
// status: 'pending', | ||
// type: 'send', | ||
// nonce: result.result.nonce, | ||
// } satisfies NewTransaction; | ||
|
||
// addNewTransaction({ | ||
// address: claimTx.from, | ||
// chainId: claimTx.chainId, | ||
// transaction, | ||
// }); | ||
|
||
// return { | ||
// nonce: result.result.nonce, | ||
// hash: result.result.hash, | ||
// }; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { claimTransactionClaimable } from './claimTransactionClaimableAction'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { createNewAction, createNewRap } from './common'; | ||
import { RapAction, RapParameters } from './references'; | ||
|
||
export async function createClaimTransactionClaimableRap(parameters: Extract<RapParameters, { type: 'claimTransactionClaimableRap' }>) { | ||
let actions: RapAction<'claimTransactionClaimableAction'>[] = []; | ||
|
||
const claim = createNewAction('claimTransactionClaimableAction', parameters.claimTransactionClaimableActionParameters); | ||
actions = actions.concat(claim); | ||
|
||
// create the overall rap | ||
const newRap = createNewRap(actions); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this could just be const claim = createNewAction('claimTransactionClaimableAction', parameters.claimTransactionClaimableActionParameters); if I'm remembering correctly concat. actions was for raps with 2 or more actions There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah unnecessary for now but my next task after getting these merged is to add more actions to this rap so i think it's fine to keep it |
||
return newRap; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import { RapAction, RapActionParameterMap, RapActionTypes } from './references'; | ||
|
||
export interface RapActionTransaction { | ||
hash: string | null; | ||
} | ||
|
||
export function createNewAction<T extends RapActionTypes>(type: T, parameters: RapActionParameterMap[T]): RapAction<T> { | ||
const newAction = { | ||
parameters, | ||
transaction: { confirmed: null, hash: null }, | ||
type, | ||
}; | ||
return newAction; | ||
} | ||
|
||
export function createNewRap<T extends RapActionTypes>(actions: RapAction<T>[]) { | ||
return { | ||
actions, | ||
}; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this the same than old raps? feels like a unnecessary code duplication |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
/* eslint-disable no-await-in-loop */ | ||
/* eslint-disable no-async-promise-executor */ | ||
/* eslint-disable no-promise-executor-return */ | ||
import { Signer } from '@ethersproject/abstract-signer'; | ||
|
||
import { RainbowError, logger } from '@/logger'; | ||
|
||
import { ActionProps, RapResponse, Rap, RapAction, RapActionResponse, RapActionTypes, RapParameters } from './references'; | ||
import { createClaimTransactionClaimableRap } from './claimTransactionClaimableRap'; | ||
import { claimTransactionClaimable } from './actions/claimTransactionClaimableAction'; | ||
import { delay } from '@/utils/delay'; | ||
|
||
// get the rap by type | ||
export function createRap(parameters: RapParameters): Promise<{ actions: RapAction<RapActionTypes>[] }> { | ||
switch (parameters.type) { | ||
case 'claimTransactionClaimableRap': | ||
return createClaimTransactionClaimableRap(parameters); | ||
default: | ||
return Promise.resolve({ actions: [] }); | ||
} | ||
} | ||
|
||
// get the action executable by type | ||
function getActionExecutableByType<T extends RapActionTypes>(type: T, props: ActionProps<T>) { | ||
switch (type) { | ||
case 'claimTransactionClaimableAction': | ||
return () => claimTransactionClaimable(props); | ||
default: | ||
throw new RainbowError(`[rapsV2/execute]: T - unknown action type ${type}`); | ||
} | ||
} | ||
|
||
// executes a single action in the rap | ||
// if the action executes a tx on-chain, it will return the nonce it used | ||
// if an error occurs, we return the error message | ||
export async function executeAction<T extends RapActionTypes>({ | ||
action, | ||
wallet, | ||
rap, | ||
nonceToUse, | ||
rapName, | ||
}: { | ||
action: RapAction<T>; | ||
wallet: Signer; | ||
rap: Rap; | ||
nonceToUse: number | undefined; | ||
rapName: string; | ||
}): Promise<RapActionResponse> { | ||
const { type, parameters } = action; | ||
try { | ||
const actionProps = { | ||
wallet, | ||
currentRap: rap, | ||
parameters, | ||
nonceToUse, | ||
}; | ||
const { nonce, hash } = await getActionExecutableByType<T>(type, actionProps)(); | ||
return { nonce, errorMessage: null, hash }; | ||
} catch (error) { | ||
logger.error(new RainbowError(`[rapsV2/execute]: ${rapName} - error execute action`), { | ||
message: (error as Error)?.message, | ||
}); | ||
return { nonce: null, errorMessage: String(error), hash: null }; | ||
} | ||
} | ||
|
||
function getRapFullName<T extends RapActionTypes>(actions: RapAction<T>[]) { | ||
const actionTypes = actions.map(action => action.type); | ||
return actionTypes.join(' + '); | ||
} | ||
|
||
const waitForNodeAck = async (hash: string, provider: Signer['provider']): Promise<void> => { | ||
return new Promise(async resolve => { | ||
const tx = await provider?.getTransaction(hash); | ||
// This means the node is aware of the tx, we're good to go | ||
if ((tx && tx.blockNumber === null) || (tx && tx?.blockNumber && tx?.blockNumber > 0)) { | ||
resolve(); | ||
} else { | ||
// Wait for 1 second and try again | ||
await delay(1000); | ||
return waitForNodeAck(hash, provider); | ||
} | ||
}); | ||
}; | ||
|
||
// goes through each action in the rap and executes it | ||
// if an action executes a tx on-chain, increment the nonceToUse for the next tx | ||
// if an action fails, it will return the error message | ||
const executeRap = async (wallet: Signer, rap: Rap): Promise<RapResponse> => { | ||
const { actions } = rap; | ||
const rapName = getRapFullName(rap.actions); | ||
let nonceToUse: number | undefined; | ||
|
||
while (actions.length) { | ||
const action = actions.shift(); | ||
|
||
if (!action) break; | ||
|
||
const { nonce, errorMessage, hash } = await executeAction({ | ||
action, | ||
wallet, | ||
rap, | ||
nonceToUse, | ||
rapName, | ||
}); | ||
|
||
if (errorMessage) return { errorMessage }; | ||
|
||
if (typeof nonce === 'number') { | ||
actions.length >= 1 && hash && (await waitForNodeAck(hash, wallet.provider)); | ||
nonceToUse = nonce + 1; | ||
} | ||
} | ||
|
||
return { errorMessage: null }; | ||
}; | ||
|
||
export async function walletExecuteRap(wallet: Signer, rapParameters: RapParameters): Promise<RapResponse> { | ||
const rap = await createRap(rapParameters); | ||
return executeRap(wallet, rap); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i see a lot of this is a dupe from old raps, I understand there are types conflicts but there's no chance to avoid this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's definitely avoidable, i felt that it was safer and more clear to keep v1 and v2 isolated. i can understand why that could be confusing when trying to tell which code is new and which is old. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
import { Signer } from '@ethersproject/abstract-signer'; | ||
import { TransactionRequest } from '@ethersproject/abstract-provider'; | ||
|
||
// supports legacy and new gas types | ||
export type TransactionClaimableTxPayload = TransactionRequest & | ||
( | ||
| { | ||
to: string; | ||
from: string; | ||
nonce: number; | ||
gasLimit: string; | ||
maxFeePerGas: string; | ||
maxPriorityFeePerGas: string; | ||
data: string; | ||
value: '0x0'; | ||
chainId: number; | ||
} | ||
| { | ||
to: string; | ||
from: string; | ||
nonce: number; | ||
gasLimit: string; | ||
gasPrice: string; | ||
data: string; | ||
value: '0x0'; | ||
chainId: number; | ||
} | ||
); | ||
|
||
export interface ClaimTransactionClaimableActionParameters { | ||
claimTx: TransactionClaimableTxPayload; | ||
} | ||
|
||
export interface RapActionTransaction { | ||
hash: string | null; | ||
} | ||
|
||
export type RapActionParameterMap = { | ||
claimTransactionClaimableAction: ClaimTransactionClaimableActionParameters; | ||
}; | ||
|
||
export type RapParameters = { | ||
type: 'claimTransactionClaimableRap'; | ||
claimTransactionClaimableActionParameters: ClaimTransactionClaimableActionParameters; | ||
}; | ||
|
||
export interface RapAction<T extends RapActionTypes> { | ||
parameters: RapActionParameterMap[T]; | ||
transaction: RapActionTransaction; | ||
type: T; | ||
} | ||
|
||
export interface Rap { | ||
actions: RapAction<'claimTransactionClaimableAction'>[]; | ||
} | ||
|
||
export enum rapActions { | ||
claimTransactionClaimableAction = 'claimTransactionClaimableAction', | ||
} | ||
|
||
export type RapActionTypes = keyof typeof rapActions; | ||
|
||
export enum rapTypes { | ||
claimTransactionClaimableRap = 'claimTransactionClaimableRap', | ||
} | ||
|
||
export type RapTypes = keyof typeof rapTypes; | ||
|
||
export interface RapActionResponse { | ||
nonce: number | null | undefined; | ||
errorMessage: string | null; | ||
hash: string | null | undefined; | ||
} | ||
|
||
export interface ActionProps<T extends RapActionTypes> { | ||
nonceToUse: number | undefined; | ||
parameters: RapActionParameterMap[T]; | ||
wallet: Signer; | ||
} | ||
|
||
export interface RapResponse { | ||
errorMessage: string | null; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
necessary comments?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i uncomment in a followup pr that's currently open for review, i commented this code temporarily just so i could split my large branch into isolated PRs