micro-sol-signer
Version:
Create, sign & decode Solana transactions with minimum deps
58 lines • 2.46 kB
JavaScript
import { ed25519 } from '@noble/curves/ed25519.js';
import { base58, utf8 } from '@scure/base';
import * as P from 'micro-packed';
// Offchain Messages: ttps://docs.anza.xyz/cli/examples/sign-offchain-message/
// This is compatible with solana-cli sign-offchain-message
const isAscii = (data) => data.every((b) => b >= 0x20 && b <= 0x7e);
const MAX_LEN_LEDGER = 1212;
const MessageV0 = P.struct({
format: P.map(P.U8, {
ascii: 0,
utf8: 1,
utf8ext: 2,
}),
// NOTE: we use bytes here because we need to check ascii-utf8 stuff
msg: P.prefix(P.U16LE, P.bytes(null)),
});
const MessageRaw = P.validate(P.struct({
// NOTE: we cannot encode 0xff as string (not valid utf8)
magic: P.magicBytes(P.utils.concatBytes(new Uint8Array([0xff]), P.string(null).encode('solana offchain'))),
version: P.tag(P.U8, { 0: MessageV0 }),
}), (msg) => {
if (msg.version.TAG !== 0)
throw new Error('Offchain.MessageRaw: unknown version');
if (msg.version.data.msg.length > 65515)
throw new Error('Offchain.MessageRaw: size limit');
return msg;
});
const Message = P.apply(MessageRaw, {
encode(from) {
const { msg, format } = from.version.data;
if (isAscii(msg) && format !== 'ascii')
throw new Error('Offchain.Message: non-ascii encoding of ascii message');
if (msg.length > MAX_LEN_LEDGER && format !== 'utf8ext')
throw new Error('Offchain.Message: non-extended utf8 message');
return { version: from.version.TAG, msg: utf8.encode(from.version.data.msg) };
},
decode(to) {
// no need to check for utf8 here, since decoder will fail otherwise
const bytes = utf8.decode(to.msg);
if (!bytes.length)
throw new Error('Empty message');
const format = bytes.length > MAX_LEN_LEDGER ? 'utf8ext' : isAscii(bytes) ? 'ascii' : 'utf8';
return { version: { TAG: 0, data: { format, msg: bytes } } };
},
});
export const Offchain = {
Message,
MessageRaw,
sign(privateKey, msg, version = 0) {
return base58.encode(ed25519.sign(Message.encode({ version, msg }), privateKey));
},
verify(sigature, publicKey, msg, version = 0) {
if (typeof publicKey === 'string')
publicKey = base58.decode(publicKey);
return ed25519.verify(base58.decode(sigature), Message.encode({ version, msg }), publicKey);
},
};
//# sourceMappingURL=offchain.js.map