ethstorage-sdk-ts
Version:
eip-4844 blobs upload sdk from ethstorage-sdk
167 lines (166 loc) • 7.58 kB
JavaScript
;
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _BlobUploader_instances, _BlobUploader_kzg, _BlobUploader_jsonRpc, _BlobUploader_provider, _BlobUploader_wallet, _BlobUploader_getKzg;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BlobUploader = void 0;
const ethers_1 = require("ethers");
const kzg_wasm_1 = require("kzg-wasm");
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
function parseBigintValue(value) {
if (typeof value == "bigint") {
return "0x" + value.toString(16);
}
if (typeof value == "object") {
const { _hex } = value;
const c = BigInt(_hex);
return "0x" + c.toString(16);
}
return value;
}
function computeVersionedHash(commitment, blobCommitmentVersion) {
const computedVersionedHash = new Uint8Array(32);
computedVersionedHash.set([blobCommitmentVersion], 0);
const hash = ethers_1.ethers.getBytes(ethers_1.ethers.sha256(commitment));
computedVersionedHash.set(hash.subarray(1), 1);
return computedVersionedHash;
}
function commitmentsToVersionedHashes(commitment) {
return computeVersionedHash(commitment, 0x01);
}
// blob gas price
const MIN_BLOB_GASPRICE = 1n;
const BLOB_GASPRICE_UPDATE_FRACTION = 3338477n;
function fakeExponential(factor, numerator, denominator) {
let i = 1n;
let output = 0n;
let numerator_accum = factor * denominator;
while (numerator_accum > 0) {
output += BigInt(numerator_accum);
numerator_accum = (numerator_accum * BigInt(numerator)) / (denominator * i);
i++;
}
return output / denominator;
}
class BlobUploader {
constructor(rpc, pk) {
_BlobUploader_instances.add(this);
_BlobUploader_kzg.set(this, void 0);
_BlobUploader_jsonRpc.set(this, void 0);
_BlobUploader_provider.set(this, void 0);
_BlobUploader_wallet.set(this, void 0);
__classPrivateFieldSet(this, _BlobUploader_jsonRpc, rpc, "f");
__classPrivateFieldSet(this, _BlobUploader_provider, new ethers_1.ethers.JsonRpcProvider(rpc), "f");
__classPrivateFieldSet(this, _BlobUploader_wallet, new ethers_1.ethers.Wallet(pk, __classPrivateFieldGet(this, _BlobUploader_provider, "f")), "f");
}
async getNonce() {
return await __classPrivateFieldGet(this, _BlobUploader_wallet, "f").getNonce();
}
async getBlobGasPrice() {
// get current block
const block = (await __classPrivateFieldGet(this, _BlobUploader_provider, "f").getBlock("latest"));
const excessBlobGas = BigInt(block.excessBlobGas);
return fakeExponential(MIN_BLOB_GASPRICE, excessBlobGas, BLOB_GASPRICE_UPDATE_FRACTION);
}
async getGasPrice() {
return await __classPrivateFieldGet(this, _BlobUploader_provider, "f").getFeeData();
}
async estimateGas(params) {
const limit = await __classPrivateFieldGet(this, _BlobUploader_provider, "f").send("eth_estimateGas", [params]);
if (limit) {
return (BigInt(limit) * 6n) / 5n;
}
return null;
}
async sendTx(tx, blobs) {
if (!blobs) {
return await __classPrivateFieldGet(this, _BlobUploader_wallet, "f").sendTransaction(tx);
}
// blobs
const kzg = await __classPrivateFieldGet(this, _BlobUploader_instances, "m", _BlobUploader_getKzg).call(this);
const ethersBlobs = [];
const versionedHashes = [];
for (let i = 0; i < blobs.length; i++) {
const blob = blobs[i];
const commitment = kzg.blobToKzgCommitment(blob);
const proof = kzg.computeBlobKzgProof(blob, commitment);
ethersBlobs.push({
data: blob,
proof: proof,
commitment: commitment,
});
const hash = commitmentsToVersionedHashes(commitment);
versionedHashes.push(ethers_1.ethers.hexlify(hash));
}
let { to, value, data, gasLimit, maxFeePerBlobGas } = tx;
if (gasLimit == null) {
const hexValue = parseBigintValue(value);
gasLimit = await this.estimateGas({
from: __classPrivateFieldGet(this, _BlobUploader_wallet, "f").address,
to,
data,
value: hexValue,
blobVersionedHashes: versionedHashes,
});
if (gasLimit == null) {
throw Error("estimateGas: execution reverted");
}
tx.gasLimit = gasLimit;
}
if (maxFeePerBlobGas == null) {
maxFeePerBlobGas = await this.getBlobGasPrice();
maxFeePerBlobGas = (maxFeePerBlobGas * 6n) / 5n;
tx.maxFeePerBlobGas = maxFeePerBlobGas;
}
// send
tx.type = 3;
tx.blobVersionedHashes = versionedHashes;
tx.blobs = ethersBlobs;
tx.kzg = kzg;
return await __classPrivateFieldGet(this, _BlobUploader_wallet, "f").sendTransaction(tx);
}
async getBlobHash(blob) {
const kzg = await __classPrivateFieldGet(this, _BlobUploader_instances, "m", _BlobUploader_getKzg).call(this);
const commit = kzg.blobToKzgCommitment(blob);
const localHash = commitmentsToVersionedHashes(commit);
const hash = new Uint8Array(32);
hash.set(localHash.subarray(0, 32 - 8));
return ethers_1.ethers.hexlify(hash);
}
async isTransactionMined(transactionHash) {
const txReceipt = await __classPrivateFieldGet(this, _BlobUploader_provider, "f").getTransactionReceipt(transactionHash);
if (txReceipt && txReceipt.blockNumber) {
return txReceipt;
}
}
async getTxReceipt(transactionHash) {
let txReceipt;
while (!txReceipt) {
txReceipt = await this.isTransactionMined(transactionHash);
if (txReceipt)
break;
await sleep(5000);
}
return txReceipt;
}
}
exports.BlobUploader = BlobUploader;
_BlobUploader_kzg = new WeakMap(), _BlobUploader_jsonRpc = new WeakMap(), _BlobUploader_provider = new WeakMap(), _BlobUploader_wallet = new WeakMap(), _BlobUploader_instances = new WeakSet(), _BlobUploader_getKzg = async function _BlobUploader_getKzg() {
if (!__classPrivateFieldGet(this, _BlobUploader_kzg, "f")) {
__classPrivateFieldSet(this, _BlobUploader_kzg, await (0, kzg_wasm_1.loadKZG)(), "f");
}
return __classPrivateFieldGet(this, _BlobUploader_kzg, "f");
};