You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In React Native applications, when trying to use @coral-xyz/anchor >= v0.29.0, users will run into this error when using the library to fetch and decode certain accounts (i.e in program.account.accountName.fetch()):
TypeError: b.readUIntLE is not a function (it is undefined)
Other expected Buffer methods like readUInt32LE will fail too (have not tested myself).
Specifically, in my case, the stack trace is throwing an error in buffer-layout's UInt layout class decode method.
Root issue
The root of the issue stems from this subarray function call in decodeUnchecked.
publicdecodeUnchecked<T=any>(accountName: A,acc: Buffer): T{// In RN, `subarray` returns `data` as a Uint8Array, rather than a Buffer.
const data=acc.subarray(DISCRIMINATOR_SIZE);constlayout=this.accountLayouts.get(accountName);if(!layout){thrownewError(`Unknown account: ${accountName}`);}returnlayout.decode(data);}
The returned data is a Uint8Array when it should be a Buffer. This means it is missing the function readUIntLE and this causes the error later in buffer-layout's decode method.
Explanation
acc is aBuffer that comes from @solana/web3,js which uses the buffer npm package.
In React Native runtime environment (Hermes) Buffer.subarray behaves differently than on Browser/Node environment. This is a known issue(1, 2). As a result, the subarray call incorrectly returns an instance of a Uint8Array rather than a Buffer.
We can manually fix the subarray function by patching the Buffer.subarray prototype to explicitly return an object
that has the expected Buffer methods (like readUIntLE).
In polyfills.ts:
import{Buffer}from"buffer";global.Buffer=Buffer;Buffer.prototype.subarray=functionsubarray(begin: number|undefined,end: number|undefined){constresult=Uint8Array.prototype.subarray.apply(this,[begin,end]);Object.setPrototypeOf(result,Buffer.prototype);// Explicitly add the `Buffer` prototype (adds `readUIntLE`!)returnresult;};
2. Patch @coral-xyz/anchor to use slice instead of subarray
Not an ideal because subarray should be more performant than slice.
The text was updated successfully, but these errors were encountered:
In React Native applications, when trying to use @coral-xyz/anchor >= v0.29.0
Why is it specifically >= 0.29.0? The library has been using Buffer pretty much since the beginning, so this issue should exist on all versions.
Locally patch the Buffer.subarray function
Not pretty but at least it's a short fix. Is there a published polyfill that does this?
2. Patch @coral-xyz/anchor to use slice instead of subarray
Not an ideal because subarray should be more performant than slice.
Not only that but also slice method is deprecated afaik.
Buffer compatibility has not only been an issue for React Native, but also browsers too. The best solution long term would be to completely get rid of it, but unfortunately, we still depend on packages that use it internally.
Why is it specifically >= 0.29.0? The library has been using Buffer pretty much since the beginning, so this issue should exist on all versions.
The issue lies with the usage of subarray in decodeUnchecked, not just with Buffer. This is the commit that introduced subarray into decodeUnchecked.
So whichever version of the package includes that commit, is when it started becoming problematic for React Native. On second glance, seems like that commit began inclusion in some version of v0.28.X?
Let me know what is the starting version that includes that commit, and I can update the issue title for more accurate documentation.
Not pretty but at least it's a short fix. Is there a published polyfill that does this?
Not that I know of, most discussion online just encourages the project to manually polyfill. The @craftzdog/react-native-bufferpackage actually includes this polyfill into their implementation of Buffer but it wouldn't help in this case, because acc: Buffer is produced by @solana/web3.js which itself uses the problematic buffer package.
The best solution long term would be to completely get rid of it, but unfortunately, we still depend on packages that use it internally.
Yup, like mentioned above, this issue comes all the way from the Connection class from @solana/web3.js which itself depends on buffer.
For an interim solution, this issue/behavior should be properly documented and the fix I mentioned should be discoverable.
Is there anywhere on the Anchor documentation we can add some warning/disclaimer for React Native behavior?
Describe the bug
In React Native applications, when trying to use
@coral-xyz/anchor
>=v0.29.0
, users will run into this error when using the library to fetch and decode certain accounts (i.e inprogram.account.accountName.fetch()
):Other expected
Buffer
methods likereadUInt32LE
will fail too (have not tested myself).Specifically, in my case, the stack trace is throwing an error in
buffer-layout
'sUInt
layout classdecode
method.Root issue
The root of the issue stems from this
subarray
function call indecodeUnchecked
.The returned
data
is aUint8Array
when it should be aBuffer
. This means it is missing the functionreadUIntLE
and this causes the error later inbuffer-layout
'sdecode
method.Explanation
acc
is aBuffer
that comes from@solana/web3,js
which uses thebuffer
npm package.In React Native runtime environment (Hermes)
Buffer.subarray
behaves differently than on Browser/Node environment. This is a known issue(1, 2). As a result, thesubarray
call incorrectly returns an instance of aUint8Array
rather than aBuffer
.For a full understanding, read this issue.
Solution
1. Locally patch the
Buffer.subarray
functionWe can manually fix the
subarray
function by patching theBuffer.subarray
prototype to explicitly return an objectthat has the expected
Buffer
methods (likereadUIntLE
).In
polyfills.ts
:2. Patch
@coral-xyz/anchor
to useslice
instead ofsubarray
Not an ideal because
subarray
should be more performant thanslice
.The text was updated successfully, but these errors were encountered: