Skip to content

Commit

Permalink
Feat: Rework encodeRunestoneUnsafe logic to support SpacedRunes in …
Browse files Browse the repository at this point in the history
…a seamless manner; add support for returning commitment (#37)

* fix spaced runes support

* fix spaced runes support - need to export rune

* rework the lib a bit to take into consideration calculating itself if there are spacers and which position they are in; and add etchingCommitment return value

* fix return typing

* fix spacers logic

* add spaced rune export again
  • Loading branch information
kevinfaveri authored Apr 14, 2024
1 parent 381b2b9 commit 6dec80d
Show file tree
Hide file tree
Showing 2 changed files with 31 additions and 24 deletions.
54 changes: 31 additions & 23 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { None, Option, Some } from './src/monads';
import { Rune } from './src/rune';
import { RuneId } from './src/runeid';
import { Runestone } from './src/runestone';
import { SpacedRune } from './src/spacedrune';
import { Terms } from './src/terms';

export {
Expand All @@ -28,9 +29,9 @@ export { Edict } from './src/edict';
export { Etching } from './src/etching';
export { Network } from './src/network';
export { Rune } from './src/rune';
export { SpacedRune } from './src/spacedrune';
export { RuneId } from './src/runeid';
export { Runestone } from './src/runestone';
export { SpacedRune } from './src/spacedrune';
export { Terms } from './src/terms';

export {
Expand Down Expand Up @@ -90,6 +91,8 @@ const u128Strict = (n: bigint) => {
return u128(bigN);
};

const SPACERS = ['•', '.'];

// TODO: Add unit tests
/**
* Low level function to allow for encoding runestones without any indexer and transaction checks.
Expand All @@ -98,7 +101,10 @@ const u128Strict = (n: bigint) => {
* @returns encoded runestone bytes
* @throws Error if encoding is detected to be considered a cenotaph
*/
export function encodeRunestoneUnsafe(runestone: RunestoneSpec): Buffer {
export function encodeRunestoneUnsafe(runestone: RunestoneSpec): {
encodedRune: Buffer;
etchingCommitment: Buffer | undefined;
} {
const mint = runestone.mint
? Some(new RuneId(u64Strict(runestone.mint.block), u32Strict(runestone.mint.tx)))
: None;
Expand All @@ -112,20 +118,28 @@ export function encodeRunestoneUnsafe(runestone: RunestoneSpec): Buffer {
}));

let etching: Option<Etching> = None;
let etchingCommitment: string | undefined = undefined;
if (runestone.etching) {
const etchingSpec = runestone.etching;

if (!etchingSpec.rune && etchingSpec.spacers?.length) {
throw Error('Spacers specified with no rune');
let hasSpacers = false;
for (const spacer of SPACERS) {
if (runestone.etching?.rune?.includes(spacer)) {
hasSpacers = true;
break;
}
}

if (
etchingSpec.rune &&
etchingSpec.spacers?.length &&
Math.max(...etchingSpec.spacers)! >= etchingSpec.rune.length - 1
) {
throw Error('Spacers specified out of bounds of rune');
let runeSpacers: number | undefined = undefined;
let parsedRawRune: Rune | undefined = undefined;
if (hasSpacers) {
const spacedRune = etchingSpec.rune ? SpacedRune.fromString(etchingSpec.rune) : undefined;
runeSpacers = spacedRune?.spacers;
parsedRawRune = spacedRune?.rune;
} else {
parsedRawRune = etchingSpec.rune ? Rune.fromString(etchingSpec.rune) : undefined;
}
const rune: Option<Rune> =
parsedRawRune !== undefined ? Some(parsedRawRune).map(() => parsedRawRune!) : None;

if (etchingSpec.symbol && etchingSpec.symbol.codePointAt(1) !== undefined) {
throw Error('Symbol must be one code point');
Expand All @@ -135,17 +149,7 @@ export function encodeRunestoneUnsafe(runestone: RunestoneSpec): Buffer {
etchingSpec.divisibility !== undefined ? Some(etchingSpec.divisibility).map(u8Strict) : None;
const premine =
etchingSpec.premine !== undefined ? Some(etchingSpec.premine).map(u128Strict) : None;
const rune =
etchingSpec.rune !== undefined
? Some(etchingSpec.rune).map((rune) => Rune.fromString(rune))
: None;
const spacers = etchingSpec.spacers
? Some(
u32Strict(
etchingSpec.spacers.reduce((spacers, flagIndex) => spacers | (1 << flagIndex), 0)
)
)
: None;
const spacers: Option<u32> = hasSpacers && runeSpacers ? Some(u32Strict(runeSpacers)) : None;
const symbol = etchingSpec.symbol ? Some(etchingSpec.symbol) : None;

if (divisibility.isSome() && divisibility.unwrap() > MAX_DIVISIBILITY) {
Expand Down Expand Up @@ -185,7 +189,11 @@ export function encodeRunestoneUnsafe(runestone: RunestoneSpec): Buffer {
const turbo = etchingSpec.turbo ?? false;

etching = Some(new Etching(divisibility, rune, spacers, symbol, terms, premine, turbo));
etchingCommitment = (parsedRawRune as Rune)?.commitment;
}

return new Runestone(mint, pointer, edicts, etching).encipher();
return {
encodedRune: new Runestone(mint, pointer, edicts, etching).encipher(),
etchingCommitment,
};
}
1 change: 0 additions & 1 deletion src/indexer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ export type RuneEtchingSpec = {
rune?: string;
divisibility?: number;
premine?: bigint;
spacers?: number[];
symbol?: string;
terms?: {
cap?: bigint;
Expand Down

0 comments on commit 6dec80d

Please sign in to comment.