Skip to content

Commit

Permalink
fix: add logs for transaction failing (#614)
Browse files Browse the repository at this point in the history
* fix: add logs for transaction failing
  • Loading branch information
Aetet authored Apr 16, 2024
1 parent ffe991b commit a23b740
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 28 deletions.
25 changes: 23 additions & 2 deletions packages/sdk/src/common/logger/logger-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,12 +149,33 @@ export function getInternalLoggerMiddleware(
remoteLogger.raw(dataContainer.getErrorData(wrappedError || err))
}
}
return wrappedError ? responsePromise.catch(() => { throw wrappedError })
: responsePromise

const returnedPromis = (wrappedError ? responsePromise.catch(() => { throw wrappedError })
: responsePromise)

returnedPromis.then(async (tx) => {
if (tx?.transaction?.constructor.name === "BlockchainEthereumTransaction") {
try {
await tx.transaction.wait()
await remoteLogger.raw(await dataContainer.getTraceData({ method: replaceMethodPart(callable.name, "wait") }))
} catch(err: any) {
wrappedError = wrapSpecialErrors(err)
await remoteLogger.raw(dataContainer.getErrorData(wrappedError || err, { method: replaceMethodPart(callable.name, "wait") }))
}
}
}).catch(() => {})

return returnedPromis

}]
}
}
function replaceMethodPart(method: string, argForReplace: string): string {
let parts = method.split(".")
parts[parts.length - 1] = argForReplace
return parts.join(".")
}

function isCallable(fn: any): fn is WrappedAdvancedFn {
return fn instanceof WrappedAdvancedFn || fn?.constructor?.name === "WrappedAdvancedFn"
}
Expand Down
172 changes: 148 additions & 24 deletions packages/sdk/src/common/logger/logger-overrides.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ import { getExecRevertedMessage, isErrorWarning } from "./logger-overrides"

describe("logger overrides", () => {
describe("isErrorWarning", () => {

test("EthereumProviderError (transaction underpriced)", async () => {
const err = new EthereumProviderError({
data: null,
error: {
code: -32603,
message: '[ethjs-query] while formatting outputs from RPC \'{"value":{"code":-32603,"data":{"code":-32000,"message":"transaction underpriced"}}}',
message:
'[ethjs-query] while formatting outputs from RPC \'{"value":{"code":-32603,"data":{"code":-32000,"message":"transaction underpriced"}}}',
},
method: "any",
})
Expand Down Expand Up @@ -55,7 +55,7 @@ describe("logger overrides", () => {
{ message: "Popup closed" },
{ code: 4001 },
]
test.each(errors)("isInfoLevel test with message=$message and code=$code", (error) => {
test.each(errors)("isInfoLevel test with message=$message and code=$code", error => {
const err = new EthereumProviderError({
data: null,
error,
Expand All @@ -71,12 +71,13 @@ describe("logger overrides", () => {
})

test("ethers error", () => {
const ethersError = "Error while gas estimation with message cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (reason=\"execution reverted: Function call not successful\", method=\"estimateGas\", transaction={\"from\":\"0x2Cbc450E04a6379d37F1b85655d1fc09bdA3E6dA\",\"to\":\"0x12b3897a36fDB436ddE2788C06Eff0ffD997066e\",\"data\":\"0x0c53c5"
const ethersError =
'Error while gas estimation with message cannot estimate gas; transaction may fail or may require manual gas limit [ See: https://links.ethers.org/v5-errors-UNPREDICTABLE_GAS_LIMIT ] (reason="execution reverted: Function call not successful", method="estimateGas", transaction={"from":"0x2Cbc450E04a6379d37F1b85655d1fc09bdA3E6dA","to":"0x12b3897a36fDB436ddE2788C06Eff0ffD997066e","data":"0x0c53c5'
expect(getExecRevertedMessage(ethersError)).toEqual("Function call not successful")
})

test("RPC error", () => {
const error = "Internal JSON-RPC error.\n{\n \"code\": -32000,\n \"message\": \"execution reverted\"\n}"
const error = 'Internal JSON-RPC error.\n{\n "code": -32000,\n "message": "execution reverted"\n}'
expect(getExecRevertedMessage(error)).toEqual(error)
})

Expand All @@ -96,7 +97,9 @@ describe("logger overrides", () => {
})

test("flow proposal key error error", () => {
const error = new Error("[Error Code: 1007] error caused by: 1 error occurred:\\n\\t* checking sequence number failed: [Error Code: 1007] invalid proposal key: public key 0 on account 201362ac764cf16f has sequence number 284, but given 283\\n\\n")
const error = new Error(
"[Error Code: 1007] error caused by: 1 error occurred:\\n\\t* checking sequence number failed: [Error Code: 1007] invalid proposal key: public key 0 on account 201362ac764cf16f has sequence number 284, but given 283\\n\\n",
)
expect(isErrorWarning(error, WalletType.FLOW)).toBeTruthy()
})

Expand All @@ -105,26 +108,27 @@ describe("logger overrides", () => {
const ethereum = new Web3Ethereum({ web3: new Web3(provider) })

const ethereumWallet = new EthereumWallet(ethereum)
const erc721Address = convertEthereumContractAddress("0xF3348949Db80297C78EC17d19611c263fc61f987", Blockchain.ETHEREUM)
const erc721Address = convertEthereumContractAddress(
"0xF3348949Db80297C78EC17d19611c263fc61f987",
Blockchain.ETHEREUM,
)

test("should mint ERC721 token", async () => {
const mockLogger = jest.fn()

const sdk = createRaribleSdk(ethereumWallet, "development", {
apiKey: getAPIKey("development"),
logger: new RemoteLogger(
async (msg: LoggableValue) => mockLogger(msg),
{
initialContext: getSdkContext({
env: "development",
sessionId: "",
config: {
logs: LogsLevel.ERROR,
},
}),
dropBatchInterval: 100,
maxByteSize: 5 * 10240,
logger: new RemoteLogger(async (msg: LoggableValue) => mockLogger(msg), {
initialContext: getSdkContext({
env: "development",
sessionId: "",
config: {
logs: LogsLevel.ERROR,
},
}),
dropBatchInterval: 100,
maxByteSize: 5 * 10240,
}),
logs: LogsLevel.ERROR,
})

Expand All @@ -137,10 +141,12 @@ describe("logger overrides", () => {
})
const result = await action.submit({
uri: "ipfs://ipfs/QmfVqzkQcKR1vCNqcZkeVVy94684hyLki7QcVzd9rmjuG5",
creators: [{
account: sender,
value: 10000,
}],
creators: [
{
account: sender,
value: 10000,
},
],
royalties: [],
lazyMint: false,
supply: 1,
Expand All @@ -162,6 +168,124 @@ describe("logger overrides", () => {
expect(logObject.status).toBe(404)
expect(logObject.code).toBe("NETWORK_ERR")
})
})

test("successful transaction wait", async () => {
const mockLogger = jest.fn()

const sdk = createRaribleSdk(ethereumWallet, "development", {
apiKey: getAPIKey("development"),
logger: new RemoteLogger(async (msg: LoggableValue) => mockLogger(msg), {
initialContext: getSdkContext({
env: "development",
sessionId: "",
config: {
logs: LogsLevel.ERROR,
},
}),
dropBatchInterval: 100,
maxByteSize: 5 * 10240,
}),
logs: LogsLevel.ERROR,
})

const senderRaw = wallet.getAddressString()
const sender = convertEthereumToUnionAddress(senderRaw, Blockchain.ETHEREUM)

try {
const rightAddress = "ETHEREUM:0x5fc5fc8693211d29b53c2923222083a81fced33c"
const action = await sdk.nft.mint.prepare({
collectionId: toCollectionId(rightAddress),
})
const result = await action.submit({
uri: "ipfs://ipfs/QmfVqzkQcKR1vCNqcZkeVVy94684hyLki7QcVzd9rmjuG5",
creators: [
{
account: sender,
value: 10000,
},
],
royalties: [],
lazyMint: false,
supply: 1,
})

if (result.type === MintType.ON_CHAIN) {
const transaction = await result.transaction.wait()
expect(transaction.blockchain).toEqual("ETHEREUM")
expect(transaction.hash).toBeTruthy()
} else {
throw new Error("Must be on chain")
}
} catch (e) { }

await delay(1000)

const trace = mockLogger.mock.calls[0][0][0].level
expect(trace).toBe("TRACE")
})

test("failed transaction wait", async () => {
class BlockchainEthereumTransaction {
async wait(): Promise<any> { return Promise.reject("asd") }
}

jest.mock("@rarible/sdk-transaction", () => { // replace with actual path
return {
BlockchainEthereumTransaction: jest.fn().mockImplementation(() => {
return new BlockchainEthereumTransaction()
}),
}
})
const mockLogger = jest.fn()

const sdk = createRaribleSdk(ethereumWallet, "development", {
apiKey: getAPIKey("development"),
logger: new RemoteLogger(async (msg: LoggableValue) => mockLogger(msg), {
initialContext: getSdkContext({
env: "development",
sessionId: "",
config: {
logs: LogsLevel.ERROR,
},
}),
dropBatchInterval: 100,
maxByteSize: 5 * 10240,
}),
logs: LogsLevel.ERROR,
})

const senderRaw = wallet.getAddressString()
const sender = convertEthereumToUnionAddress(senderRaw, Blockchain.ETHEREUM)

try {
const rightAddress = "ETHEREUM:0x5fc5fc8693211d29b53c2923222083a81fced33c"
const action = await sdk.nft.mint.prepare({
collectionId: toCollectionId(rightAddress),
})
const result = await action.submit({
uri: "ipfs://ipfs/QmfVqzkQcKR1vCNqcZkeVVy94684hyLki7QcVzd9rmjuG5",
creators: [
{
account: sender,
value: 10000,
},
],
royalties: [],
lazyMint: false,
supply: 1,
})

if (result.type === MintType.ON_CHAIN) {
await result.transaction.wait()
} else {
throw new Error("Must be on chain")
}
} catch (e) { }

await delay(2000)
const trace = mockLogger.mock.calls[0][0]
const foundCall = trace.find((call: any) => call.method === "nft.mint.prepare.submit.wait")
expect(foundCall).toBeTruthy()
})
})
})
6 changes: 4 additions & 2 deletions packages/sdk/src/common/logger/logger-overrides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ export class LoggerDataContainer {
}
return parsedArgs
}
async getTraceData() {
async getTraceData(additionalFields?: Record<string, any>) {
const res = await this.input.responsePromise
return {
level: LogLevel.TRACE,
Expand All @@ -174,10 +174,11 @@ export class LoggerDataContainer {
args: this.stringifiedArgs,
resp: JSON.stringify(res),
...(this.extraFields || {}),
...(additionalFields || {}),
}
}

getErrorData<T extends Error | WrappedError>(rawError: T) {
getErrorData<T extends Error | WrappedError>(rawError: T, additionalFields?: Record<string, any>) {
let data
const error = WrappedError.isWrappedError(rawError) ? rawError.error as Error : rawError
try {
Expand All @@ -190,6 +191,7 @@ export class LoggerDataContainer {
args: this.stringifiedArgs,
requestAddress: undefined as undefined | string,
...(this.extraFields || {}),
...(additionalFields || {}),
}
if (error instanceof NetworkError || error?.name === "NetworkError") {
data.requestAddress = (error as NetworkError)?.url
Expand Down

0 comments on commit a23b740

Please sign in to comment.