-
Notifications
You must be signed in to change notification settings - Fork 149
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: sip30 stx call contract, closes LEA-1954
- Loading branch information
Showing
11 changed files
with
4,323 additions
and
5,855 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
src/app/pages/rpc-stx-call-contract/rpc-stx-call-contract.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { StacksHighFeeWarningContainer } from '@app/features/stacks-high-fee-warning/stacks-high-fee-warning-container'; | ||
import { StacksTransactionSigner } from '@app/features/stacks-transaction-request/stacks-transaction-signer'; | ||
import { useBreakOnNonCompliantEntity } from '@app/query/common/compliance-checker/compliance-checker.query'; | ||
|
||
import { useRpcStxCallContract } from './use-rpc-stx-call-contract'; | ||
|
||
export function RpcStxCallContract() { | ||
const { onSignStacksTransaction, onCancel, stacksTransaction, txSender } = | ||
useRpcStxCallContract(); | ||
|
||
useBreakOnNonCompliantEntity(txSender); | ||
|
||
return ( | ||
<StacksHighFeeWarningContainer> | ||
<StacksTransactionSigner | ||
onSignStacksTransaction={onSignStacksTransaction} | ||
onCancel={onCancel} | ||
isMultisig={false} | ||
stacksTransaction={stacksTransaction} | ||
/> | ||
</StacksHighFeeWarningContainer> | ||
); | ||
} |
107 changes: 107 additions & 0 deletions
107
src/app/pages/rpc-stx-call-contract/use-rpc-stx-call-contract.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { useMemo } from 'react'; | ||
import { useAsync } from 'react-async-hook'; | ||
|
||
import { RpcErrorCode } from '@leather.io/rpc'; | ||
|
||
import { logger } from '@shared/logger'; | ||
import { makeRpcErrorResponse, makeRpcSuccessResponse } from '@shared/rpc/rpc-methods'; | ||
import { closeWindow } from '@shared/utils'; | ||
import { | ||
type TransactionPayload, | ||
getLegacyTransactionPayloadFromToken, | ||
} from '@shared/utils/legacy-requests'; | ||
|
||
import { useDefaultRequestParams } from '@app/common/hooks/use-default-request-search-params'; | ||
import { initialSearchParams } from '@app/common/initial-search-params'; | ||
import { | ||
type GenerateUnsignedTransactionOptions, | ||
generateUnsignedTransaction, | ||
} from '@app/common/transactions/stacks/generate-unsigned-txs'; | ||
import { getTxSenderAddress } from '@app/common/transactions/stacks/transaction.utils'; | ||
import { useCurrentStacksAccount } from '@app/store/accounts/blockchain/stacks/stacks-account.hooks'; | ||
import { useSignStacksTransaction } from '@app/store/transactions/transaction.hooks'; | ||
|
||
function useRpcStxCallContractParams() { | ||
const { origin, tabId } = useDefaultRequestParams(); | ||
const requestId = initialSearchParams.get('requestId'); | ||
const request = initialSearchParams.get('request'); | ||
|
||
if (!origin || !request || !requestId) throw new Error('Invalid params'); | ||
|
||
return useMemo( | ||
() => ({ | ||
origin, | ||
tabId: tabId ?? 0, | ||
request: getLegacyTransactionPayloadFromToken(request), | ||
requestId, | ||
}), | ||
[origin, tabId, request, requestId] | ||
); | ||
} | ||
|
||
function useUnsignedStacksTransactionFromRequest(request: TransactionPayload) { | ||
const account = useCurrentStacksAccount(); | ||
|
||
const tx = useAsync(async () => { | ||
if (!account) return; | ||
|
||
const options: GenerateUnsignedTransactionOptions = { | ||
publicKey: account.stxPublicKey, | ||
txData: request, | ||
fee: request.fee ?? 0, | ||
nonce: request.nonce, | ||
}; | ||
return generateUnsignedTransaction(options); | ||
}, [account]); | ||
|
||
return tx.result; | ||
} | ||
|
||
export function useRpcStxCallContract() { | ||
const { origin, request, requestId, tabId } = useRpcStxCallContractParams(); | ||
const signStacksTx = useSignStacksTransaction(); | ||
const stacksTransaction = useUnsignedStacksTransactionFromRequest(request); | ||
|
||
return { | ||
origin, | ||
txSender: stacksTransaction ? getTxSenderAddress(stacksTransaction) : '', | ||
stacksTransaction, | ||
async onSignStacksTransaction(fee: number, nonce: number) { | ||
if (!stacksTransaction) { | ||
return logger.error('No stacks transaction to sign'); | ||
} | ||
|
||
stacksTransaction.setFee(fee); | ||
stacksTransaction.setNonce(nonce); | ||
|
||
const signedTransaction = await signStacksTx(stacksTransaction); | ||
if (!signedTransaction) { | ||
throw new Error('Error signing stacks transaction'); | ||
} | ||
|
||
chrome.tabs.sendMessage( | ||
tabId, | ||
makeRpcSuccessResponse('stx_callContract', { | ||
id: requestId, | ||
result: { | ||
txid: '', // Broadcast transaction? | ||
transaction: signedTransaction.serialize(), | ||
} as any, // Fix this | ||
}) | ||
); | ||
closeWindow(); | ||
}, | ||
onCancel() { | ||
chrome.tabs.sendMessage( | ||
tabId, | ||
makeRpcErrorResponse('stx_callContract', { | ||
id: requestId, | ||
error: { | ||
message: 'User denied signing stacks transaction', | ||
code: RpcErrorCode.USER_REJECTION, | ||
}, | ||
}) | ||
); | ||
}, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
102 changes: 102 additions & 0 deletions
102
src/background/messaging/rpc-methods/stx-call-contract.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import { TransactionTypes } from '@stacks/connect'; | ||
import { type ClarityValue, serializeCV } from '@stacks/transactions'; | ||
import { createUnsecuredToken } from 'jsontokens'; | ||
|
||
import { | ||
RpcErrorCode, | ||
type StxCallContractRequest, | ||
type StxCallContractRequestParams, | ||
} from '@leather.io/rpc'; | ||
import { getStacksAssetStringParts } from '@leather.io/stacks'; | ||
import { isUndefined } from '@leather.io/utils'; | ||
|
||
import { RouteUrls } from '@shared/route-urls'; | ||
import { | ||
getRpcStxCallContractParamErrors, | ||
validateRpcStxCallContractParams, | ||
} from '@shared/rpc/methods/stx-call-contract'; | ||
import { makeRpcErrorResponse } from '@shared/rpc/rpc-methods'; | ||
|
||
import { | ||
RequestParams, | ||
getStxDefaultMessageParamsToTransactionRequest, | ||
getTabIdFromPort, | ||
listenForPopupClose, | ||
makeSearchParamsWithDefaults, | ||
triggerRequestWindowOpen, | ||
} from '../messaging-utils'; | ||
import { trackRpcRequestError, trackRpcRequestSuccess } from '../rpc-message-handler'; | ||
|
||
function getMessageParamsToTransactionRequest(params: StxCallContractRequestParams) { | ||
const { contractAddress, contractName } = getStacksAssetStringParts(params.contract); | ||
const defaultParams = getStxDefaultMessageParamsToTransactionRequest(params); | ||
|
||
return { | ||
txType: TransactionTypes.ContractCall, | ||
contractAddress, | ||
contractName, | ||
functionArgs: (params.functionArgs ?? []).map(arg => | ||
serializeCV(arg as unknown as ClarityValue) | ||
), | ||
functionName: params.functionName, | ||
...defaultParams, | ||
}; | ||
} | ||
|
||
export async function rpcStxCallContract( | ||
message: StxCallContractRequest, | ||
port: chrome.runtime.Port | ||
) { | ||
if (isUndefined(message.params)) { | ||
void trackRpcRequestError({ endpoint: message.method, error: 'Undefined parameters' }); | ||
chrome.tabs.sendMessage( | ||
getTabIdFromPort(port), | ||
makeRpcErrorResponse('stx_callContract', { | ||
id: message.id, | ||
error: { code: RpcErrorCode.INVALID_REQUEST, message: 'Parameters undefined' }, | ||
}) | ||
); | ||
return; | ||
} | ||
|
||
if (!validateRpcStxCallContractParams(message.params)) { | ||
void trackRpcRequestError({ endpoint: message.method, error: 'Invalid parameters' }); | ||
|
||
chrome.tabs.sendMessage( | ||
getTabIdFromPort(port), | ||
makeRpcErrorResponse('stx_callContract', { | ||
id: message.id, | ||
error: { | ||
code: RpcErrorCode.INVALID_PARAMS, | ||
message: getRpcStxCallContractParamErrors(message.params), | ||
}, | ||
}) | ||
); | ||
return; | ||
} | ||
|
||
const request = getMessageParamsToTransactionRequest(message.params); | ||
|
||
void trackRpcRequestSuccess({ endpoint: message.method }); | ||
|
||
const requestParams: RequestParams = [ | ||
['requestId', message.id], | ||
['request', createUnsecuredToken(request)], | ||
]; | ||
|
||
const { urlParams, tabId } = makeSearchParamsWithDefaults(port, requestParams); | ||
|
||
const { id } = await triggerRequestWindowOpen(RouteUrls.RpcStxCallContract, urlParams); | ||
|
||
listenForPopupClose({ | ||
tabId, | ||
id, | ||
response: makeRpcErrorResponse('stx_callContract', { | ||
id: message.id, | ||
error: { | ||
code: RpcErrorCode.USER_REJECTION, | ||
message: 'User denied signing stacks transaction', | ||
}, | ||
}), | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.