feat: add borsh utilities and public key support (#17239)
* feat: add borsh utilities and public key support * fix: make bn internal for flow * fix: add Buffer import in borsh file
This commit is contained in:
parent
75335b4f58
commit
00e198d169
|
@ -11,6 +11,7 @@
|
|||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"bn.js": "^5.0.0",
|
||||
"borsh": "^0.4.0",
|
||||
"bs58": "^4.0.1",
|
||||
"buffer": "6.0.1",
|
||||
"buffer-layout": "^1.2.0",
|
||||
|
@ -4682,6 +4683,25 @@
|
|||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/borsh": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/borsh/-/borsh-0.4.0.tgz",
|
||||
"integrity": "sha512-aX6qtLya3K0AkT66CmYWCCDr77qsE9arV05OmdFpmat9qu8Pg9J5tBUPDztAW5fNh/d/MyVG/OYziP52Ndzx1g==",
|
||||
"dependencies": {
|
||||
"@types/bn.js": "^4.11.5",
|
||||
"bn.js": "^5.0.0",
|
||||
"bs58": "^4.0.0",
|
||||
"text-encoding-utf-8": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/borsh/node_modules/@types/bn.js": {
|
||||
"version": "4.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz",
|
||||
"integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/bottleneck": {
|
||||
"version": "2.19.5",
|
||||
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
|
||||
|
@ -4799,6 +4819,7 @@
|
|||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.3.tgz",
|
||||
"integrity": "sha512-yEYTwGndELGvfXsImMBLop58eaGW+YdONi1fNjTINSY98tmMmFijBG6WXgdkfuLNt4imzQNtIE+eBp1PVpMCSw==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.2.0"
|
||||
|
@ -17828,6 +17849,7 @@
|
|||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.2.tgz",
|
||||
"integrity": "sha512-UDar4sKvWAksIlfX3xIaQReADn+WFnHvbVujpcbr+9Sf/69odMwy2MUsz5CKLQgX9nsIyrjuxL2imVyoNHa3fg==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"elliptic": "^6.5.2",
|
||||
"node-addon-api": "^2.0.0",
|
||||
|
@ -19672,6 +19694,11 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/text-encoding-utf-8": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz",
|
||||
"integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg=="
|
||||
},
|
||||
"node_modules/text-extensions": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz",
|
||||
|
@ -20157,6 +20184,7 @@
|
|||
"version": "5.0.4",
|
||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.4.tgz",
|
||||
"integrity": "sha512-MEF05cPSq3AwJ2C7B7sHAA6i53vONoZbMGX8My5auEVm6W+dJ2Jd/TZPyGJ5CH42V2XtbI5FD28HeHeqlPzZ3Q==",
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.2.0"
|
||||
|
@ -24684,6 +24712,27 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"borsh": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/borsh/-/borsh-0.4.0.tgz",
|
||||
"integrity": "sha512-aX6qtLya3K0AkT66CmYWCCDr77qsE9arV05OmdFpmat9qu8Pg9J5tBUPDztAW5fNh/d/MyVG/OYziP52Ndzx1g==",
|
||||
"requires": {
|
||||
"@types/bn.js": "^4.11.5",
|
||||
"bn.js": "^5.0.0",
|
||||
"bs58": "^4.0.0",
|
||||
"text-encoding-utf-8": "^1.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/bn.js": {
|
||||
"version": "4.11.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz",
|
||||
"integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"bottleneck": {
|
||||
"version": "2.19.5",
|
||||
"resolved": "https://registry.npmjs.org/bottleneck/-/bottleneck-2.19.5.tgz",
|
||||
|
@ -36400,6 +36449,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"text-encoding-utf-8": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz",
|
||||
"integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg=="
|
||||
},
|
||||
"text-extensions": {
|
||||
"version": "1.9.0",
|
||||
"resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.9.0.tgz",
|
||||
|
|
|
@ -64,6 +64,7 @@
|
|||
"dependencies": {
|
||||
"@babel/runtime": "^7.12.5",
|
||||
"bn.js": "^5.0.0",
|
||||
"borsh": "^0.4.0",
|
||||
"bs58": "^4.0.1",
|
||||
"buffer": "6.0.1",
|
||||
"buffer-layout": "^1.2.0",
|
||||
|
|
|
@ -52,6 +52,7 @@ function generateConfig(configType, format) {
|
|||
config.external = [
|
||||
/@babel\/runtime/,
|
||||
'bn.js',
|
||||
'borsh',
|
||||
'bs58',
|
||||
'buffer-layout',
|
||||
'crypto-hash',
|
||||
|
@ -81,6 +82,7 @@ function generateConfig(configType, format) {
|
|||
config.external = [
|
||||
/@babel\/runtime/,
|
||||
'bn.js',
|
||||
'borsh',
|
||||
'bs58',
|
||||
'buffer',
|
||||
'buffer-layout',
|
||||
|
|
|
@ -16,6 +16,7 @@ export * from './transaction';
|
|||
export * from './validator-info';
|
||||
export * from './vote-account';
|
||||
export * from './sysvar';
|
||||
export * from './util/borsh-schema';
|
||||
export * from './util/send-and-confirm-transaction';
|
||||
export * from './util/send-and-confirm-raw-transaction';
|
||||
export * from './util/cluster';
|
||||
|
|
|
@ -4,6 +4,7 @@ import nacl from 'tweetnacl';
|
|||
import {sha256} from 'crypto-hash';
|
||||
import {Buffer} from 'buffer';
|
||||
|
||||
import {Struct, SOLANA_SCHEMA} from './util/borsh-schema';
|
||||
import {toBuffer} from './util/to-buffer';
|
||||
|
||||
/**
|
||||
|
@ -11,10 +12,27 @@ import {toBuffer} from './util/to-buffer';
|
|||
*/
|
||||
export const MAX_SEED_LENGTH = 32;
|
||||
|
||||
type PublicKeyInitData =
|
||||
| number
|
||||
| string
|
||||
| Buffer
|
||||
| Uint8Array
|
||||
| Array<number>
|
||||
| PublicKeyData;
|
||||
|
||||
type PublicKeyData = {
|
||||
/** @internal */
|
||||
_bn: BN;
|
||||
};
|
||||
|
||||
function isPublicKeyData(value: PublicKeyInitData): value is PublicKeyData {
|
||||
return (value as PublicKeyData)._bn !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* A public key
|
||||
*/
|
||||
export class PublicKey {
|
||||
export class PublicKey extends Struct {
|
||||
/** @internal */
|
||||
_bn: BN;
|
||||
|
||||
|
@ -22,20 +40,25 @@ export class PublicKey {
|
|||
* Create a new PublicKey object
|
||||
* @param value ed25519 public key as buffer or base-58 encoded string
|
||||
*/
|
||||
constructor(value: number | string | Buffer | Uint8Array | Array<number>) {
|
||||
if (typeof value === 'string') {
|
||||
// assume base 58 encoding by default
|
||||
const decoded = bs58.decode(value);
|
||||
if (decoded.length != 32) {
|
||||
constructor(value: PublicKeyInitData) {
|
||||
super({});
|
||||
if (isPublicKeyData(value)) {
|
||||
this._bn = value._bn;
|
||||
} else {
|
||||
if (typeof value === 'string') {
|
||||
// assume base 58 encoding by default
|
||||
const decoded = bs58.decode(value);
|
||||
if (decoded.length != 32) {
|
||||
throw new Error(`Invalid public key input`);
|
||||
}
|
||||
this._bn = new BN(decoded);
|
||||
} else {
|
||||
this._bn = new BN(value);
|
||||
}
|
||||
|
||||
if (this._bn.byteLength() > 32) {
|
||||
throw new Error(`Invalid public key input`);
|
||||
}
|
||||
this._bn = new BN(decoded);
|
||||
} else {
|
||||
this._bn = new BN(value);
|
||||
}
|
||||
|
||||
if (this._bn.byteLength() > 32) {
|
||||
throw new Error(`Invalid public key input`);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,6 +190,11 @@ export class PublicKey {
|
|||
}
|
||||
}
|
||||
|
||||
SOLANA_SCHEMA.set(PublicKey, {
|
||||
kind: 'struct',
|
||||
fields: [['_bn', 'u256']],
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
let naclLowLevel = nacl.lowlevel;
|
||||
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
import {Buffer} from 'buffer';
|
||||
import {serialize, deserialize} from 'borsh';
|
||||
|
||||
// Class wrapping a plain object
|
||||
export class Struct {
|
||||
constructor(properties: any) {
|
||||
Object.assign(this, properties);
|
||||
}
|
||||
|
||||
encode(): Buffer {
|
||||
return Buffer.from(serialize(SOLANA_SCHEMA, this));
|
||||
}
|
||||
|
||||
static decode(data: Buffer): any {
|
||||
return deserialize(SOLANA_SCHEMA, this, data);
|
||||
}
|
||||
}
|
||||
|
||||
// Class representing a Rust-compatible enum, since enums are only strings or
|
||||
// numbers in pure JS
|
||||
export class Enum extends Struct {
|
||||
enum: string = '';
|
||||
constructor(properties: any) {
|
||||
super(properties);
|
||||
if (Object.keys(properties).length !== 1) {
|
||||
throw new Error('Enum can only take single value');
|
||||
}
|
||||
Object.keys(properties).map(key => {
|
||||
this.enum = key;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export const SOLANA_SCHEMA: Map<Function, any> = new Map();
|
|
@ -342,4 +342,11 @@ describe('PublicKey', function () {
|
|||
);
|
||||
expect(PublicKey.isOnCurve(offCurve.toBuffer())).to.be.false;
|
||||
});
|
||||
|
||||
it('canBeSerializedWithBorsh', () => {
|
||||
const publicKey = Keypair.generate().publicKey;
|
||||
const encoded = publicKey.encode();
|
||||
const decoded = PublicKey.decode(encoded);
|
||||
expect(decoded.equals(publicKey)).to.be.true;
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue