UNPKG

iso-filecoin

Version:

Isomorphic filecoin abstractions for RPC, signatures, address, token and wallet

212 lines (185 loc) 5.21 kB
'use strict'; var index = require('../node_modules/.pnpm/@ipld_dag-cbor@9.2.4/node_modules/@ipld/dag-cbor/src/index.cjs'); var rfc4648 = require('../node_modules/.pnpm/iso-base@4.1.0/node_modules/iso-base/src/rfc4648.cjs'); var src_address = require('./address.cjs'); var src_token = require('./token.cjs'); var src_utils = require('./utils.cjs'); var schemas = require('../node_modules/.pnpm/zod@4.0.10/node_modules/zod/v4/classic/schemas.cjs'); /** * @typedef {import('./types.js').MessageObj} MessageObj * @typedef {import('./types.js').PartialMessageObj} PartialMessageObj */ /** * Message validation schema */ const MessageSchema = schemas.object({ version: schemas.literal(0).default(0), nonce: schemas.int().nonnegative().default(0), gasLimit: schemas.int().nonnegative().default(0), gasFeeCap: schemas.string().default('0'), gasPremium: schemas.string().default('0'), method: schemas.int().nonnegative().default(0), to: schemas.string(), from: schemas.string(), /** * Value in attoFIL */ value: schemas.string() .min(1) .refine((v) => !v.startsWith('-'), { message: 'value must not be negative', }), /** * Params encoded as base64pad */ params: schemas.base64().default(''), }); const MessageSchemaPartial = MessageSchema.partial({ version: true, nonce: true, gasLimit: true, gasFeeCap: true, gasPremium: true, method: true, params: true, }); const Schemas = { message: MessageSchema, messagePartial: MessageSchemaPartial, }; /** * Filecoin Message class */ class Message { /** @type {Uint8Array | undefined} */ #bytes /** @type {Uint8Array | undefined} */ #cidBytes /** * * @param {PartialMessageObj} msg */ constructor(msg) { const _msg = MessageSchema.parse(msg); this.version = _msg.version; this.to = _msg.to; this.from = _msg.from; this.nonce = _msg.nonce; this.value = _msg.value; this.gasLimit = _msg.gasLimit; this.gasFeeCap = _msg.gasFeeCap; this.gasPremium = _msg.gasPremium; this.method = _msg.method; this.params = _msg.params; } /** * Convert message to Lotus message */ toLotus() { return { Version: this.version, To: this.to, From: this.from, Nonce: this.nonce, Value: this.value, GasLimit: this.gasLimit, GasFeeCap: this.gasFeeCap, GasPremium: this.gasPremium, Method: this.method, Params: this.params, } } /** * Create message from Lotus message * * @param {import('./types').LotusMessage} json */ static fromLotus(json) { /** @type {MessageObj} */ const obj = { version: json.Version, to: json.To, from: json.From, nonce: json.Nonce, value: json.Value, gasLimit: json.GasLimit, gasFeeCap: json.GasFeeCap, gasPremium: json.GasPremium, method: json.Method, params: json.Params, }; return new Message(obj) } /** * Prepare message for signing with nonce and gas estimation * * @param {import('./rpc.js').RPC} rpc */ async prepare(rpc) { if (src_address.isIdMaskAddress(this.to)) { throw new Error('ID mask addresses are not supported for recipient') } const parsedTo = src_address.from(this.to, rpc.network); // Change to method to InvokeEVM for Bare value sends to 0x address to avoid losing funds // @see https://docs.filecoin.io/smart-contracts/filecoin-evm-runtime/difference-with-ethereum#bare-value-sends if (src_address.isAddressDelegated(parsedTo) && this.method === 0) { this.method = 3844450837; } this.to = parsedTo.toString(); if (this.nonce === 0) { const nonce = await rpc.nonce(this.from); if (nonce.error) { throw new Error(nonce.error.message) } this.nonce = nonce.result; } if ( (this.gasLimit === 0 && this.gasFeeCap === '0') || this.gasPremium === '0' ) { const gas = await rpc.gasEstimate({ msg: this }); if (gas.error) { throw new Error(gas.error.message) } this.gasLimit = gas.result.GasLimit; this.gasFeeCap = gas.result.GasFeeCap; this.gasPremium = gas.result.GasPremium; } return this } /** * Serialize message using dag-cbor */ serialize() { if (this.#bytes) { return this.#bytes } const msg = [ this.version, src_address.fromString(this.to).toBytes(), src_address.fromString(this.from).toBytes(), this.nonce, src_token.Token.fromAttoFIL(this.value).toBytes(), this.gasLimit, src_token.Token.fromAttoFIL(this.gasFeeCap).toBytes(), src_token.Token.fromAttoFIL(this.gasPremium).toBytes(), this.method, rfc4648.base64pad.decode(this.params), ]; this.#bytes = /** @type {Uint8Array}*/ (index.encode(msg)); return this.#bytes } /** * CID bytes of the filecoin message */ cidBytes() { if (this.#cidBytes) { return this.#cidBytes } this.#cidBytes = src_utils.lotusCid(this.serialize()); return this.#cidBytes } } exports.Message = Message; exports.MessageSchema = MessageSchema; exports.Schemas = Schemas;