@coolwallet/sol
Version:
Coolwallet Solana sdk
136 lines (117 loc) • 4.37 kB
text/typescript
import base58 from 'bs58';
import BN from 'bn.js';
import * as types from '../config/types';
import { ComputeBudgetInstruction } from '../config/types';
const HEX_REGEX = /[0-9A-Fa-f]{6}/g;
export const isBase58Format = (value?: string): boolean => {
if (!value) return false;
return /^[A-HJ-NP-Za-km-z1-9]*$/.test(value);
};
function isHexFormat(value: string): boolean {
const match = value.match(HEX_REGEX);
return !!match;
}
export function toBase58(publicKey: types.Address): string {
if (typeof publicKey === 'string') {
if (isBase58Format(publicKey)) return publicKey;
if (isHexFormat(publicKey)) return base58.encode(Buffer.from(publicKey, 'hex'));
return publicKey;
}
return base58.encode(publicKey);
}
export function toBase58Buffer(publicKey: types.Address): Buffer {
if (typeof publicKey === 'string') {
if (isBase58Format(publicKey)) return base58.decode(publicKey);
if (isHexFormat(publicKey)) return Buffer.from(publicKey, 'hex');
return Buffer.from(publicKey);
}
return publicKey;
}
export function toPublicKey(publicKey: string | Buffer): string {
if (typeof publicKey === 'string') return publicKey;
return base58.encode(publicKey);
}
export function pubKeyToAddress(publicKey: string): string {
const pubKeyBuf = Buffer.from(publicKey, 'hex');
return base58.encode(pubKeyBuf);
}
/**
* CW-21334 Fixed user's publicKey just matches the base58 encoding, resulting in repeated decoding.
*
* The user's Solana address (base58 encoded) is:
* 5XZiuCyozesbRJsSdoJQCTHQRnTGDfSms5bV1ybLn9yg
*
* After converting it to Hex:
* fc238b62abd32cd576f1d5568d3b6b5cb2fbc57b419cc2b4cd8a2814973919a7
* This hex conform to the Base58 format (without 0, O, i, I, +, /), causing base58.decode to be executed again, resulting in an incorrect publicKey.
*
* How to fix it:
* Adjust base58 verification method. A 32-byte public key can only be base58 encoded using 43 or 44 characters.
*/
export const formHex = (address: string | Buffer | undefined): string => {
if (!address) return '';
if (typeof address === 'string') {
if (isBase58Format(address)) return base58.decode(address).toString('hex');
return address;
}
return address.toString('hex');
};
export const numberToStringHex = (value: number | number[], pad: number): string =>
Buffer.from(typeof value === 'number' ? [value] : value)
.toString('hex')
.padStart(pad, '0');
export const encodeLength = (bytes: number[], len: number): void => {
let rem_len = len;
for (;;) {
let elem = rem_len & 0x7f;
rem_len >>= 7;
if (rem_len == 0) {
bytes.push(elem);
break;
} else {
elem |= 0x80;
bytes.push(elem);
}
}
};
export function toReverseUintBuffer(numberOrString: number | string, byteSize: number): Buffer {
const bn = new BN(numberOrString);
const buf = Buffer.from(bn.toArray()).reverse();
return Buffer.alloc(byteSize).fill(buf, 0, buf.length);
}
export function toUintBuffer(numberOrString: number | string, byteSize: number): Buffer {
const bn = new BN(numberOrString);
const buf = Buffer.from(bn.toArray());
return Buffer.alloc(byteSize).fill(buf, byteSize - buf.length, byteSize);
}
export function computeBudgetEncode(type: ComputeBudgetInstruction, amount: number | string): Buffer {
let data;
let length;
switch (type) {
case ComputeBudgetInstruction.SetComputeUnitLimit:
data = Buffer.alloc(5);
length = 4;
break;
case ComputeBudgetInstruction.SetComputeUnitPrice:
data = Buffer.alloc(9);
length = 8;
break;
default:
throw new Error('Not supported ComputeBudgetInstruction type: ' + type);
}
const typeSpan = 1;
data.writeUIntLE(type, 0, typeSpan);
const valueBuf = toReverseUintBuffer(amount, length);
data.write(valueBuf.toString('hex'), typeSpan, length, 'hex');
return data;
}
export function splDataEncode(amount: number | string, tokenDecimals: number | string): Buffer {
const data = Buffer.alloc(10);
const programIdIndexSpan = 1;
data.writeUIntLE(types.TokenInstruction.TransferChecked, 0, programIdIndexSpan);
const valueHex = new BN(amount).toString(16, 8 * 2);
const valueBuf = Buffer.from(valueHex, 'hex').reverse();
data.write(valueBuf.toString('hex'), programIdIndexSpan, 8, 'hex');
data.writeUInt8(+tokenDecimals, 9);
return data;
}