@rozoai/checkout 0.1.20 → 0.1.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1562,7 +1562,7 @@ function assertSize(hexOrBytes, { size: size5 }) {
1562
1562
  maxSize: size5
1563
1563
  });
1564
1564
  }
1565
- function hexToBigInt(hex, opts = {}) {
1565
+ function hexToBigInt2(hex, opts = {}) {
1566
1566
  const { signed } = opts;
1567
1567
  if (opts.size)
1568
1568
  assertSize(hex, { size: opts.size });
@@ -1588,7 +1588,7 @@ function hexToBool(hex_, opts = {}) {
1588
1588
  throw new InvalidHexBooleanError(hex);
1589
1589
  }
1590
1590
  function hexToNumber(hex, opts = {}) {
1591
- const value = hexToBigInt(hex, opts);
1591
+ const value = hexToBigInt2(hex, opts);
1592
1592
  const number = Number(value);
1593
1593
  if (!Number.isSafeInteger(number))
1594
1594
  throw new IntegerOutOfRangeError({
@@ -3102,7 +3102,7 @@ function bytesToBigInt(bytes, opts = {}) {
3102
3102
  if (typeof opts.size !== "undefined")
3103
3103
  assertSize(bytes, { size: opts.size });
3104
3104
  const hex = bytesToHex(bytes);
3105
- return hexToBigInt(hex, opts);
3105
+ return hexToBigInt2(hex, opts);
3106
3106
  }
3107
3107
  function bytesToBool(bytes_, opts = {}) {
3108
3108
  let bytes = bytes_;
@@ -32374,7 +32374,7 @@ var require_index_cjs = __commonJS({
32374
32374
  return value._bn !== void 0;
32375
32375
  }
32376
32376
  var uniquePublicKeyCounter = 1;
32377
- var PublicKey3 = class _PublicKey2 extends Struct {
32377
+ var PublicKey4 = class _PublicKey2 extends Struct {
32378
32378
  /**
32379
32379
  * Create a new PublicKey object
32380
32380
  * @param value ed25519 public key as buffer or base-58 encoded string
@@ -32536,9 +32536,9 @@ var require_index_cjs = __commonJS({
32536
32536
  return isOnCurve(pubkey.toBytes());
32537
32537
  }
32538
32538
  };
32539
- _PublicKey = PublicKey3;
32540
- PublicKey3.default = new _PublicKey("11111111111111111111111111111111");
32541
- SOLANA_SCHEMA.set(PublicKey3, {
32539
+ _PublicKey = PublicKey4;
32540
+ PublicKey4.default = new _PublicKey("11111111111111111111111111111111");
32541
+ SOLANA_SCHEMA.set(PublicKey4, {
32542
32542
  kind: "struct",
32543
32543
  fields: [["_bn", "u256"]]
32544
32544
  });
@@ -32570,7 +32570,7 @@ var require_index_cjs = __commonJS({
32570
32570
  * The public key for this account
32571
32571
  */
32572
32572
  get publicKey() {
32573
- return new PublicKey3(this._publicKey);
32573
+ return new PublicKey4(this._publicKey);
32574
32574
  }
32575
32575
  /**
32576
32576
  * The **unencrypted** secret key for this account. The first 32 bytes
@@ -32581,7 +32581,7 @@ var require_index_cjs = __commonJS({
32581
32581
  return buffer2.Buffer.concat([this._secretKey, this._publicKey], 64);
32582
32582
  }
32583
32583
  };
32584
- var BPF_LOADER_DEPRECATED_PROGRAM_ID = new PublicKey3("BPFLoader1111111111111111111111111111111111");
32584
+ var BPF_LOADER_DEPRECATED_PROGRAM_ID = new PublicKey4("BPFLoader1111111111111111111111111111111111");
32585
32585
  var PACKET_DATA_SIZE = 1280 - 40 - 8;
32586
32586
  var VERSION_PREFIX_MASK = 127;
32587
32587
  var SIGNATURE_LENGTH_IN_BYTES = 64;
@@ -32812,7 +32812,7 @@ var require_index_cjs = __commonJS({
32812
32812
  const [payerAddress] = writableSigners[0];
32813
32813
  assert8(payerAddress === this.payer.toBase58(), "Expected first writable signer key to be the fee payer");
32814
32814
  }
32815
- const staticAccountKeys = [...writableSigners.map(([address]) => new PublicKey3(address)), ...readonlySigners.map(([address]) => new PublicKey3(address)), ...writableNonSigners.map(([address]) => new PublicKey3(address)), ...readonlyNonSigners.map(([address]) => new PublicKey3(address))];
32815
+ const staticAccountKeys = [...writableSigners.map(([address]) => new PublicKey4(address)), ...readonlySigners.map(([address]) => new PublicKey4(address)), ...writableNonSigners.map(([address]) => new PublicKey4(address)), ...readonlyNonSigners.map(([address]) => new PublicKey4(address))];
32816
32816
  return [header, staticAccountKeys];
32817
32817
  }
32818
32818
  extractTableLookup(lookupTable) {
@@ -32836,7 +32836,7 @@ var require_index_cjs = __commonJS({
32836
32836
  const drainedKeys = new Array();
32837
32837
  for (const [address, keyMeta] of this.keyMetaMap.entries()) {
32838
32838
  if (keyMetaFilter(keyMeta)) {
32839
- const key = new PublicKey3(address);
32839
+ const key = new PublicKey4(address);
32840
32840
  const lookupTableIndex = lookupTableEntries.findIndex((entry) => entry.equals(key));
32841
32841
  if (lookupTableIndex >= 0) {
32842
32842
  assert8(lookupTableIndex < 256, "Max lookup table index exceeded");
@@ -32871,7 +32871,7 @@ var require_index_cjs = __commonJS({
32871
32871
  this.instructions = void 0;
32872
32872
  this.indexToProgramIds = /* @__PURE__ */ new Map();
32873
32873
  this.header = args.header;
32874
- this.accountKeys = args.accountKeys.map((account) => new PublicKey3(account));
32874
+ this.accountKeys = args.accountKeys.map((account) => new PublicKey4(account));
32875
32875
  this.recentBlockhash = args.recentBlockhash;
32876
32876
  this.instructions = args.instructions;
32877
32877
  this.instructions.forEach((ix) => this.indexToProgramIds.set(ix.programIdIndex, this.accountKeys[ix.programIdIndex]));
@@ -32997,7 +32997,7 @@ var require_index_cjs = __commonJS({
32997
32997
  let accountKeys = [];
32998
32998
  for (let i = 0; i < accountCount; i++) {
32999
32999
  const account = guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH);
33000
- accountKeys.push(new PublicKey3(buffer2.Buffer.from(account)));
33000
+ accountKeys.push(new PublicKey4(buffer2.Buffer.from(account)));
33001
33001
  }
33002
33002
  const recentBlockhash = guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH);
33003
33003
  const instructionCount = decodeLength(byteArray);
@@ -33221,7 +33221,7 @@ var require_index_cjs = __commonJS({
33221
33221
  const staticAccountKeys = [];
33222
33222
  const staticAccountKeysLength = decodeLength(byteArray);
33223
33223
  for (let i = 0; i < staticAccountKeysLength; i++) {
33224
- staticAccountKeys.push(new PublicKey3(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH)));
33224
+ staticAccountKeys.push(new PublicKey4(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH)));
33225
33225
  }
33226
33226
  const recentBlockhash = bs58__default.default.encode(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
33227
33227
  const instructionCount = decodeLength(byteArray);
@@ -33241,7 +33241,7 @@ var require_index_cjs = __commonJS({
33241
33241
  const addressTableLookupsCount = decodeLength(byteArray);
33242
33242
  const addressTableLookups = [];
33243
33243
  for (let i = 0; i < addressTableLookupsCount; i++) {
33244
- const accountKey = new PublicKey3(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
33244
+ const accountKey = new PublicKey4(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
33245
33245
  const writableIndexesLength = decodeLength(byteArray);
33246
33246
  const writableIndexes = guardedSplice(byteArray, 0, writableIndexesLength);
33247
33247
  const readonlyIndexesLength = decodeLength(byteArray);
@@ -33290,7 +33290,7 @@ var require_index_cjs = __commonJS({
33290
33290
  return TransactionStatus2;
33291
33291
  })({});
33292
33292
  var DEFAULT_SIGNATURE = buffer2.Buffer.alloc(SIGNATURE_LENGTH_IN_BYTES).fill(0);
33293
- var TransactionInstruction3 = class {
33293
+ var TransactionInstruction4 = class {
33294
33294
  constructor(opts) {
33295
33295
  this.keys = void 0;
33296
33296
  this.programId = void 0;
@@ -33320,7 +33320,7 @@ var require_index_cjs = __commonJS({
33320
33320
  };
33321
33321
  }
33322
33322
  };
33323
- var Transaction2 = class _Transaction {
33323
+ var Transaction3 = class _Transaction {
33324
33324
  /**
33325
33325
  * The first (payer) Transaction signature
33326
33326
  *
@@ -33422,7 +33422,7 @@ var require_index_cjs = __commonJS({
33422
33422
  } else if ("data" in item && "programId" in item && "keys" in item) {
33423
33423
  this.instructions.push(item);
33424
33424
  } else {
33425
- this.instructions.push(new TransactionInstruction3(item));
33425
+ this.instructions.push(new TransactionInstruction4(item));
33426
33426
  }
33427
33427
  });
33428
33428
  return this;
@@ -33481,7 +33481,7 @@ var require_index_cjs = __commonJS({
33481
33481
  });
33482
33482
  programIds.forEach((programId) => {
33483
33483
  accountMetas.push({
33484
- pubkey: new PublicKey3(programId),
33484
+ pubkey: new PublicKey4(programId),
33485
33485
  isSigner: false,
33486
33486
  isWritable: false
33487
33487
  });
@@ -33915,7 +33915,7 @@ Missing signature for public key${sigErrors.missing.length === 1 ? "" : "(s)"} [
33915
33915
  isWritable: message.isAccountWritable(account)
33916
33916
  };
33917
33917
  });
33918
- transaction.instructions.push(new TransactionInstruction3({
33918
+ transaction.instructions.push(new TransactionInstruction4({
33919
33919
  keys,
33920
33920
  programId: message.accountKeys[instruction.programIdIndex],
33921
33921
  data: bs58__default.default.decode(instruction.data)
@@ -33983,7 +33983,7 @@ Missing signature for public key${sigErrors.missing.length === 1 ? "" : "(s)"} [
33983
33983
  if (programId === void 0) {
33984
33984
  throw new Error(`Failed to find program id for program id index ${compiledIx.programIdIndex}`);
33985
33985
  }
33986
- instructions.push(new TransactionInstruction3({
33986
+ instructions.push(new TransactionInstruction4({
33987
33987
  programId,
33988
33988
  data: toBuffer(compiledIx.data),
33989
33989
  keys
@@ -34074,15 +34074,15 @@ Missing signature for public key${sigErrors.missing.length === 1 ? "" : "(s)"} [
34074
34074
  var DEFAULT_TICKS_PER_SLOT = 64;
34075
34075
  var NUM_SLOTS_PER_SECOND = NUM_TICKS_PER_SECOND / DEFAULT_TICKS_PER_SLOT;
34076
34076
  var MS_PER_SLOT = 1e3 / NUM_SLOTS_PER_SECOND;
34077
- var SYSVAR_CLOCK_PUBKEY = new PublicKey3("SysvarC1ock11111111111111111111111111111111");
34078
- var SYSVAR_EPOCH_SCHEDULE_PUBKEY = new PublicKey3("SysvarEpochSchedu1e111111111111111111111111");
34079
- var SYSVAR_INSTRUCTIONS_PUBKEY = new PublicKey3("Sysvar1nstructions1111111111111111111111111");
34080
- var SYSVAR_RECENT_BLOCKHASHES_PUBKEY = new PublicKey3("SysvarRecentB1ockHashes11111111111111111111");
34081
- var SYSVAR_RENT_PUBKEY = new PublicKey3("SysvarRent111111111111111111111111111111111");
34082
- var SYSVAR_REWARDS_PUBKEY = new PublicKey3("SysvarRewards111111111111111111111111111111");
34083
- var SYSVAR_SLOT_HASHES_PUBKEY = new PublicKey3("SysvarS1otHashes111111111111111111111111111");
34084
- var SYSVAR_SLOT_HISTORY_PUBKEY = new PublicKey3("SysvarS1otHistory11111111111111111111111111");
34085
- var SYSVAR_STAKE_HISTORY_PUBKEY = new PublicKey3("SysvarStakeHistory1111111111111111111111111");
34077
+ var SYSVAR_CLOCK_PUBKEY = new PublicKey4("SysvarC1ock11111111111111111111111111111111");
34078
+ var SYSVAR_EPOCH_SCHEDULE_PUBKEY = new PublicKey4("SysvarEpochSchedu1e111111111111111111111111");
34079
+ var SYSVAR_INSTRUCTIONS_PUBKEY = new PublicKey4("Sysvar1nstructions1111111111111111111111111");
34080
+ var SYSVAR_RECENT_BLOCKHASHES_PUBKEY = new PublicKey4("SysvarRecentB1ockHashes11111111111111111111");
34081
+ var SYSVAR_RENT_PUBKEY = new PublicKey4("SysvarRent111111111111111111111111111111111");
34082
+ var SYSVAR_REWARDS_PUBKEY = new PublicKey4("SysvarRewards111111111111111111111111111111");
34083
+ var SYSVAR_SLOT_HASHES_PUBKEY = new PublicKey4("SysvarS1otHashes111111111111111111111111111");
34084
+ var SYSVAR_SLOT_HISTORY_PUBKEY = new PublicKey4("SysvarS1otHistory11111111111111111111111111");
34085
+ var SYSVAR_STAKE_HISTORY_PUBKEY = new PublicKey4("SysvarStakeHistory1111111111111111111111111");
34086
34086
  var SendTransactionError = class extends Error {
34087
34087
  constructor({
34088
34088
  action,
@@ -34273,8 +34273,8 @@ Message: ${transactionMessage}.
34273
34273
  static fromAccountData(buffer3) {
34274
34274
  const nonceAccount = NonceAccountLayout.decode(toBuffer(buffer3), 0);
34275
34275
  return new _NonceAccount({
34276
- authorizedPubkey: new PublicKey3(nonceAccount.authorizedPubkey),
34277
- nonce: new PublicKey3(nonceAccount.nonce).toString(),
34276
+ authorizedPubkey: new PublicKey4(nonceAccount.authorizedPubkey),
34277
+ nonce: new PublicKey4(nonceAccount.nonce).toString(),
34278
34278
  feeCalculator: nonceAccount.feeCalculator
34279
34279
  });
34280
34280
  }
@@ -34336,7 +34336,7 @@ Message: ${transactionMessage}.
34336
34336
  newAccountPubkey: instruction.keys[1].pubkey,
34337
34337
  lamports,
34338
34338
  space,
34339
- programId: new PublicKey3(programId)
34339
+ programId: new PublicKey4(programId)
34340
34340
  };
34341
34341
  }
34342
34342
  /**
@@ -34371,7 +34371,7 @@ Message: ${transactionMessage}.
34371
34371
  toPubkey: instruction.keys[2].pubkey,
34372
34372
  lamports,
34373
34373
  seed,
34374
- programId: new PublicKey3(programId)
34374
+ programId: new PublicKey4(programId)
34375
34375
  };
34376
34376
  }
34377
34377
  /**
@@ -34402,10 +34402,10 @@ Message: ${transactionMessage}.
34402
34402
  } = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.AllocateWithSeed, instruction.data);
34403
34403
  return {
34404
34404
  accountPubkey: instruction.keys[0].pubkey,
34405
- basePubkey: new PublicKey3(base),
34405
+ basePubkey: new PublicKey4(base),
34406
34406
  seed,
34407
34407
  space,
34408
- programId: new PublicKey3(programId)
34408
+ programId: new PublicKey4(programId)
34409
34409
  };
34410
34410
  }
34411
34411
  /**
@@ -34419,7 +34419,7 @@ Message: ${transactionMessage}.
34419
34419
  } = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.Assign, instruction.data);
34420
34420
  return {
34421
34421
  accountPubkey: instruction.keys[0].pubkey,
34422
- programId: new PublicKey3(programId)
34422
+ programId: new PublicKey4(programId)
34423
34423
  };
34424
34424
  }
34425
34425
  /**
@@ -34435,9 +34435,9 @@ Message: ${transactionMessage}.
34435
34435
  } = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.AssignWithSeed, instruction.data);
34436
34436
  return {
34437
34437
  accountPubkey: instruction.keys[0].pubkey,
34438
- basePubkey: new PublicKey3(base),
34438
+ basePubkey: new PublicKey4(base),
34439
34439
  seed,
34440
- programId: new PublicKey3(programId)
34440
+ programId: new PublicKey4(programId)
34441
34441
  };
34442
34442
  }
34443
34443
  /**
@@ -34456,11 +34456,11 @@ Message: ${transactionMessage}.
34456
34456
  return {
34457
34457
  fromPubkey: instruction.keys[0].pubkey,
34458
34458
  newAccountPubkey: instruction.keys[1].pubkey,
34459
- basePubkey: new PublicKey3(base),
34459
+ basePubkey: new PublicKey4(base),
34460
34460
  seed,
34461
34461
  lamports,
34462
34462
  space,
34463
- programId: new PublicKey3(programId)
34463
+ programId: new PublicKey4(programId)
34464
34464
  };
34465
34465
  }
34466
34466
  /**
@@ -34474,7 +34474,7 @@ Message: ${transactionMessage}.
34474
34474
  } = decodeData$1(SYSTEM_INSTRUCTION_LAYOUTS.InitializeNonceAccount, instruction.data);
34475
34475
  return {
34476
34476
  noncePubkey: instruction.keys[0].pubkey,
34477
- authorizedPubkey: new PublicKey3(authorized2)
34477
+ authorizedPubkey: new PublicKey4(authorized2)
34478
34478
  };
34479
34479
  }
34480
34480
  /**
@@ -34517,14 +34517,14 @@ Message: ${transactionMessage}.
34517
34517
  return {
34518
34518
  noncePubkey: instruction.keys[0].pubkey,
34519
34519
  authorizedPubkey: instruction.keys[1].pubkey,
34520
- newAuthorizedPubkey: new PublicKey3(authorized2)
34520
+ newAuthorizedPubkey: new PublicKey4(authorized2)
34521
34521
  };
34522
34522
  }
34523
34523
  /**
34524
34524
  * @internal
34525
34525
  */
34526
34526
  static checkProgramId(programId) {
34527
- if (!programId.equals(SystemProgram.programId)) {
34527
+ if (!programId.equals(SystemProgram2.programId)) {
34528
34528
  throw new Error("invalid instruction; programId is not SystemProgram");
34529
34529
  }
34530
34530
  }
@@ -34591,7 +34591,7 @@ Message: ${transactionMessage}.
34591
34591
  layout: BufferLayout__namespace.struct([BufferLayout__namespace.u32("instruction")])
34592
34592
  }
34593
34593
  });
34594
- var SystemProgram = class _SystemProgram {
34594
+ var SystemProgram2 = class _SystemProgram {
34595
34595
  /**
34596
34596
  * @internal
34597
34597
  */
@@ -34610,7 +34610,7 @@ Message: ${transactionMessage}.
34610
34610
  space: params.space,
34611
34611
  programId: toBuffer(params.programId.toBuffer())
34612
34612
  });
34613
- return new TransactionInstruction3({
34613
+ return new TransactionInstruction4({
34614
34614
  keys: [{
34615
34615
  pubkey: params.fromPubkey,
34616
34616
  isSigner: true,
@@ -34665,7 +34665,7 @@ Message: ${transactionMessage}.
34665
34665
  isWritable: true
34666
34666
  }];
34667
34667
  }
34668
- return new TransactionInstruction3({
34668
+ return new TransactionInstruction4({
34669
34669
  keys,
34670
34670
  programId: this.programId,
34671
34671
  data
@@ -34704,7 +34704,7 @@ Message: ${transactionMessage}.
34704
34704
  isWritable: true
34705
34705
  }];
34706
34706
  }
34707
- return new TransactionInstruction3({
34707
+ return new TransactionInstruction4({
34708
34708
  keys,
34709
34709
  programId: this.programId,
34710
34710
  data
@@ -34739,7 +34739,7 @@ Message: ${transactionMessage}.
34739
34739
  isWritable: false
34740
34740
  });
34741
34741
  }
34742
- return new TransactionInstruction3({
34742
+ return new TransactionInstruction4({
34743
34743
  keys,
34744
34744
  programId: this.programId,
34745
34745
  data
@@ -34749,7 +34749,7 @@ Message: ${transactionMessage}.
34749
34749
  * Generate a transaction that creates a new Nonce account
34750
34750
  */
34751
34751
  static createNonceAccount(params) {
34752
- const transaction = new Transaction2();
34752
+ const transaction = new Transaction3();
34753
34753
  if ("basePubkey" in params && "seed" in params) {
34754
34754
  transaction.add(_SystemProgram.createAccountWithSeed({
34755
34755
  fromPubkey: params.fromPubkey,
@@ -34801,7 +34801,7 @@ Message: ${transactionMessage}.
34801
34801
  programId: this.programId,
34802
34802
  data
34803
34803
  };
34804
- return new TransactionInstruction3(instructionData);
34804
+ return new TransactionInstruction4(instructionData);
34805
34805
  }
34806
34806
  /**
34807
34807
  * Generate an instruction to advance the nonce in a Nonce account
@@ -34826,7 +34826,7 @@ Message: ${transactionMessage}.
34826
34826
  programId: this.programId,
34827
34827
  data
34828
34828
  };
34829
- return new TransactionInstruction3(instructionData);
34829
+ return new TransactionInstruction4(instructionData);
34830
34830
  }
34831
34831
  /**
34832
34832
  * Generate a transaction instruction that withdraws lamports from a Nonce account
@@ -34836,7 +34836,7 @@ Message: ${transactionMessage}.
34836
34836
  const data = encodeData3(type, {
34837
34837
  lamports: params.lamports
34838
34838
  });
34839
- return new TransactionInstruction3({
34839
+ return new TransactionInstruction4({
34840
34840
  keys: [{
34841
34841
  pubkey: params.noncePubkey,
34842
34842
  isSigner: false,
@@ -34871,7 +34871,7 @@ Message: ${transactionMessage}.
34871
34871
  const data = encodeData3(type, {
34872
34872
  authorized: toBuffer(params.newAuthorizedPubkey.toBuffer())
34873
34873
  });
34874
- return new TransactionInstruction3({
34874
+ return new TransactionInstruction4({
34875
34875
  keys: [{
34876
34876
  pubkey: params.noncePubkey,
34877
34877
  isSigner: false,
@@ -34919,14 +34919,14 @@ Message: ${transactionMessage}.
34919
34919
  isWritable: true
34920
34920
  }];
34921
34921
  }
34922
- return new TransactionInstruction3({
34922
+ return new TransactionInstruction4({
34923
34923
  keys,
34924
34924
  programId: this.programId,
34925
34925
  data
34926
34926
  });
34927
34927
  }
34928
34928
  };
34929
- SystemProgram.programId = new PublicKey3("11111111111111111111111111111111");
34929
+ SystemProgram2.programId = new PublicKey4("11111111111111111111111111111111");
34930
34930
  var CHUNK_SIZE = PACKET_DATA_SIZE - 300;
34931
34931
  var Loader = class _Loader {
34932
34932
  /**
@@ -34969,29 +34969,29 @@ Message: ${transactionMessage}.
34969
34969
  return false;
34970
34970
  }
34971
34971
  if (programInfo.data.length !== data.length) {
34972
- transaction = transaction || new Transaction2();
34973
- transaction.add(SystemProgram.allocate({
34972
+ transaction = transaction || new Transaction3();
34973
+ transaction.add(SystemProgram2.allocate({
34974
34974
  accountPubkey: program.publicKey,
34975
34975
  space: data.length
34976
34976
  }));
34977
34977
  }
34978
34978
  if (!programInfo.owner.equals(programId)) {
34979
- transaction = transaction || new Transaction2();
34980
- transaction.add(SystemProgram.assign({
34979
+ transaction = transaction || new Transaction3();
34980
+ transaction.add(SystemProgram2.assign({
34981
34981
  accountPubkey: program.publicKey,
34982
34982
  programId
34983
34983
  }));
34984
34984
  }
34985
34985
  if (programInfo.lamports < balanceNeeded) {
34986
- transaction = transaction || new Transaction2();
34987
- transaction.add(SystemProgram.transfer({
34986
+ transaction = transaction || new Transaction3();
34987
+ transaction.add(SystemProgram2.transfer({
34988
34988
  fromPubkey: payer.publicKey,
34989
34989
  toPubkey: program.publicKey,
34990
34990
  lamports: balanceNeeded - programInfo.lamports
34991
34991
  }));
34992
34992
  }
34993
34993
  } else {
34994
- transaction = new Transaction2().add(SystemProgram.createAccount({
34994
+ transaction = new Transaction3().add(SystemProgram2.createAccount({
34995
34995
  fromPubkey: payer.publicKey,
34996
34996
  newAccountPubkey: program.publicKey,
34997
34997
  lamports: balanceNeeded > 0 ? balanceNeeded : 1,
@@ -35021,7 +35021,7 @@ Message: ${transactionMessage}.
35021
35021
  bytesLength: 0,
35022
35022
  bytesLengthPadding: 0
35023
35023
  }, data2);
35024
- const transaction = new Transaction2().add({
35024
+ const transaction = new Transaction3().add({
35025
35025
  keys: [{
35026
35026
  pubkey: program.publicKey,
35027
35027
  isSigner: true,
@@ -35048,7 +35048,7 @@ Message: ${transactionMessage}.
35048
35048
  instruction: 1
35049
35049
  // Finalize instruction
35050
35050
  }, data2);
35051
- const transaction = new Transaction2().add({
35051
+ const transaction = new Transaction3().add({
35052
35052
  keys: [{
35053
35053
  pubkey: program.publicKey,
35054
35054
  isSigner: true,
@@ -35093,7 +35093,7 @@ Message: ${transactionMessage}.
35093
35093
  }
35094
35094
  };
35095
35095
  Loader.chunkSize = CHUNK_SIZE;
35096
- var BPF_LOADER_PROGRAM_ID = new PublicKey3("BPFLoader2111111111111111111111111111111111");
35096
+ var BPF_LOADER_PROGRAM_ID = new PublicKey4("BPFLoader2111111111111111111111111111111111");
35097
35097
  var BpfLoader = class {
35098
35098
  /**
35099
35099
  * Minimum number of signatures required to load a program not including
@@ -35889,8 +35889,8 @@ Message: ${transactionMessage}.
35889
35889
  deactivationSlot: meta.deactivationSlot,
35890
35890
  lastExtendedSlot: meta.lastExtendedSlot,
35891
35891
  lastExtendedSlotStartIndex: meta.lastExtendedStartIndex,
35892
- authority: meta.authority.length !== 0 ? new PublicKey3(meta.authority[0]) : void 0,
35893
- addresses: addresses.map((address) => new PublicKey3(address))
35892
+ authority: meta.authority.length !== 0 ? new PublicKey4(meta.authority[0]) : void 0,
35893
+ addresses: addresses.map((address) => new PublicKey4(address))
35894
35894
  };
35895
35895
  }
35896
35896
  };
@@ -35932,7 +35932,7 @@ Message: ${transactionMessage}.
35932
35932
  );
35933
35933
  return `${protocol}//${hostish}${websocketPort}${rest}`;
35934
35934
  }
35935
- var PublicKeyFromString = superstruct.coerce(superstruct.instance(PublicKey3), superstruct.string(), (value) => new PublicKey3(value));
35935
+ var PublicKeyFromString = superstruct.coerce(superstruct.instance(PublicKey4), superstruct.string(), (value) => new PublicKey4(value));
35936
35936
  var RawAccountDataResult = superstruct.tuple([superstruct.string(), superstruct.literal("base64")]);
35937
35937
  var BufferFromRawAccountData = superstruct.coerce(superstruct.instance(buffer2.Buffer), RawAccountDataResult, (value) => buffer2.Buffer.from(value[0], "base64"));
35938
35938
  var BLOCKHASH_CACHE_TIMEOUT_MS = 30 * 1e3;
@@ -36017,7 +36017,7 @@ Message: ${transactionMessage}.
36017
36017
  if (version5 === 0) {
36018
36018
  return new MessageV0({
36019
36019
  header: response.header,
36020
- staticAccountKeys: response.accountKeys.map((accountKey) => new PublicKey3(accountKey)),
36020
+ staticAccountKeys: response.accountKeys.map((accountKey) => new PublicKey4(accountKey)),
36021
36021
  recentBlockhash: response.recentBlockhash,
36022
36022
  compiledInstructions: response.instructions.map((ix) => ({
36023
36023
  programIdIndex: ix.programIdIndex,
@@ -38207,7 +38207,7 @@ Message: ${transactionMessage}.
38207
38207
  }) => {
38208
38208
  return {
38209
38209
  meta,
38210
- transaction: Transaction2.populate(transaction.message, transaction.signatures)
38210
+ transaction: Transaction3.populate(transaction.message, transaction.signatures)
38211
38211
  };
38212
38212
  })
38213
38213
  };
@@ -38282,7 +38282,7 @@ Message: ${transactionMessage}.
38282
38282
  const signatures = result.transaction.signatures;
38283
38283
  return {
38284
38284
  ...result,
38285
- transaction: Transaction2.populate(message, signatures)
38285
+ transaction: Transaction3.populate(message, signatures)
38286
38286
  };
38287
38287
  }
38288
38288
  /**
@@ -38569,15 +38569,15 @@ Message: ${transactionMessage}.
38569
38569
  return res2.result;
38570
38570
  }
38571
38571
  let transaction;
38572
- if (transactionOrMessage instanceof Transaction2) {
38572
+ if (transactionOrMessage instanceof Transaction3) {
38573
38573
  let originalTx = transactionOrMessage;
38574
- transaction = new Transaction2();
38574
+ transaction = new Transaction3();
38575
38575
  transaction.feePayer = originalTx.feePayer;
38576
38576
  transaction.instructions = transactionOrMessage.instructions;
38577
38577
  transaction.nonceInfo = originalTx.nonceInfo;
38578
38578
  transaction.signatures = originalTx.signatures;
38579
38579
  } else {
38580
- transaction = Transaction2.populate(transactionOrMessage);
38580
+ transaction = Transaction3.populate(transactionOrMessage);
38581
38581
  transaction._message = transaction._json = void 0;
38582
38582
  }
38583
38583
  if (configOrSigners !== void 0 && !Array.isArray(configOrSigners)) {
@@ -39457,7 +39457,7 @@ Message: ${transactionMessage}.
39457
39457
  * @returns {PublicKey} PublicKey
39458
39458
  */
39459
39459
  get publicKey() {
39460
- return new PublicKey3(this._keypair.publicKey);
39460
+ return new PublicKey4(this._keypair.publicKey);
39461
39461
  }
39462
39462
  /**
39463
39463
  * The raw secret key for this keypair
@@ -39535,7 +39535,7 @@ Message: ${transactionMessage}.
39535
39535
  lookupTable: instruction.keys[0].pubkey,
39536
39536
  authority: instruction.keys[1].pubkey,
39537
39537
  payer: instruction.keys.length > 2 ? instruction.keys[2].pubkey : void 0,
39538
- addresses: addresses.map((buffer3) => new PublicKey3(buffer3))
39538
+ addresses: addresses.map((buffer3) => new PublicKey4(buffer3))
39539
39539
  };
39540
39540
  }
39541
39541
  static decodeCloseLookupTable(instruction) {
@@ -39587,7 +39587,7 @@ Message: ${transactionMessage}.
39587
39587
  constructor() {
39588
39588
  }
39589
39589
  static createLookupTable(params) {
39590
- const [lookupTableAddress, bumpSeed] = PublicKey3.findProgramAddressSync([params.authority.toBuffer(), codecsNumbers.getU64Encoder().encode(params.recentSlot)], this.programId);
39590
+ const [lookupTableAddress, bumpSeed] = PublicKey4.findProgramAddressSync([params.authority.toBuffer(), codecsNumbers.getU64Encoder().encode(params.recentSlot)], this.programId);
39591
39591
  const type = LOOKUP_TABLE_INSTRUCTION_LAYOUTS.CreateLookupTable;
39592
39592
  const data = encodeData3(type, {
39593
39593
  recentSlot: BigInt(params.recentSlot),
@@ -39606,11 +39606,11 @@ Message: ${transactionMessage}.
39606
39606
  isSigner: true,
39607
39607
  isWritable: true
39608
39608
  }, {
39609
- pubkey: SystemProgram.programId,
39609
+ pubkey: SystemProgram2.programId,
39610
39610
  isSigner: false,
39611
39611
  isWritable: false
39612
39612
  }];
39613
- return [new TransactionInstruction3({
39613
+ return [new TransactionInstruction4({
39614
39614
  programId: this.programId,
39615
39615
  keys,
39616
39616
  data
@@ -39628,7 +39628,7 @@ Message: ${transactionMessage}.
39628
39628
  isSigner: true,
39629
39629
  isWritable: false
39630
39630
  }];
39631
- return new TransactionInstruction3({
39631
+ return new TransactionInstruction4({
39632
39632
  programId: this.programId,
39633
39633
  keys,
39634
39634
  data
@@ -39654,12 +39654,12 @@ Message: ${transactionMessage}.
39654
39654
  isSigner: true,
39655
39655
  isWritable: true
39656
39656
  }, {
39657
- pubkey: SystemProgram.programId,
39657
+ pubkey: SystemProgram2.programId,
39658
39658
  isSigner: false,
39659
39659
  isWritable: false
39660
39660
  });
39661
39661
  }
39662
- return new TransactionInstruction3({
39662
+ return new TransactionInstruction4({
39663
39663
  programId: this.programId,
39664
39664
  keys,
39665
39665
  data
@@ -39677,7 +39677,7 @@ Message: ${transactionMessage}.
39677
39677
  isSigner: true,
39678
39678
  isWritable: false
39679
39679
  }];
39680
- return new TransactionInstruction3({
39680
+ return new TransactionInstruction4({
39681
39681
  programId: this.programId,
39682
39682
  keys,
39683
39683
  data
@@ -39699,14 +39699,14 @@ Message: ${transactionMessage}.
39699
39699
  isSigner: false,
39700
39700
  isWritable: true
39701
39701
  }];
39702
- return new TransactionInstruction3({
39702
+ return new TransactionInstruction4({
39703
39703
  programId: this.programId,
39704
39704
  keys,
39705
39705
  data
39706
39706
  });
39707
39707
  }
39708
39708
  };
39709
- AddressLookupTableProgram.programId = new PublicKey3("AddressLookupTab1e1111111111111111111111111");
39709
+ AddressLookupTableProgram.programId = new PublicKey4("AddressLookupTab1e1111111111111111111111111");
39710
39710
  var ComputeBudgetInstruction = class {
39711
39711
  /**
39712
39712
  * @internal
@@ -39824,7 +39824,7 @@ Message: ${transactionMessage}.
39824
39824
  static requestUnits(params) {
39825
39825
  const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestUnits;
39826
39826
  const data = encodeData3(type, params);
39827
- return new TransactionInstruction3({
39827
+ return new TransactionInstruction4({
39828
39828
  keys: [],
39829
39829
  programId: this.programId,
39830
39830
  data
@@ -39833,7 +39833,7 @@ Message: ${transactionMessage}.
39833
39833
  static requestHeapFrame(params) {
39834
39834
  const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.RequestHeapFrame;
39835
39835
  const data = encodeData3(type, params);
39836
- return new TransactionInstruction3({
39836
+ return new TransactionInstruction4({
39837
39837
  keys: [],
39838
39838
  programId: this.programId,
39839
39839
  data
@@ -39842,7 +39842,7 @@ Message: ${transactionMessage}.
39842
39842
  static setComputeUnitLimit(params) {
39843
39843
  const type = COMPUTE_BUDGET_INSTRUCTION_LAYOUTS.SetComputeUnitLimit;
39844
39844
  const data = encodeData3(type, params);
39845
- return new TransactionInstruction3({
39845
+ return new TransactionInstruction4({
39846
39846
  keys: [],
39847
39847
  programId: this.programId,
39848
39848
  data
@@ -39853,14 +39853,14 @@ Message: ${transactionMessage}.
39853
39853
  const data = encodeData3(type, {
39854
39854
  microLamports: BigInt(params.microLamports)
39855
39855
  });
39856
- return new TransactionInstruction3({
39856
+ return new TransactionInstruction4({
39857
39857
  keys: [],
39858
39858
  programId: this.programId,
39859
39859
  data
39860
39860
  });
39861
39861
  }
39862
39862
  };
39863
- ComputeBudgetProgram.programId = new PublicKey3("ComputeBudget111111111111111111111111111111");
39863
+ ComputeBudgetProgram.programId = new PublicKey4("ComputeBudget111111111111111111111111111111");
39864
39864
  var PRIVATE_KEY_BYTES$1 = 64;
39865
39865
  var PUBLIC_KEY_BYTES$1 = 32;
39866
39866
  var SIGNATURE_BYTES = 64;
@@ -39908,7 +39908,7 @@ Message: ${transactionMessage}.
39908
39908
  instructionData.fill(publicKey2, publicKeyOffset);
39909
39909
  instructionData.fill(signature2, signatureOffset);
39910
39910
  instructionData.fill(message, messageDataOffset);
39911
- return new TransactionInstruction3({
39911
+ return new TransactionInstruction4({
39912
39912
  keys: [],
39913
39913
  programId: _Ed25519Program.programId,
39914
39914
  data: instructionData
@@ -39940,7 +39940,7 @@ Message: ${transactionMessage}.
39940
39940
  }
39941
39941
  }
39942
39942
  };
39943
- Ed25519Program.programId = new PublicKey3("Ed25519SigVerify111111111111111111111111111");
39943
+ Ed25519Program.programId = new PublicKey4("Ed25519SigVerify111111111111111111111111111");
39944
39944
  var ecdsaSign = (msgHash, privKey) => {
39945
39945
  const signature2 = secp256k13.secp256k1.sign(msgHash, privKey);
39946
39946
  return [signature2.toCompactRawBytes(), signature2.recovery];
@@ -40036,7 +40036,7 @@ Message: ${transactionMessage}.
40036
40036
  recoveryId
40037
40037
  }, instructionData);
40038
40038
  instructionData.fill(toBuffer(message), SECP256K1_INSTRUCTION_LAYOUT.span);
40039
- return new TransactionInstruction3({
40039
+ return new TransactionInstruction4({
40040
40040
  keys: [],
40041
40041
  programId: _Secp256k1Program.programId,
40042
40042
  data: instructionData
@@ -40074,9 +40074,9 @@ Message: ${transactionMessage}.
40074
40074
  }
40075
40075
  }
40076
40076
  };
40077
- Secp256k1Program.programId = new PublicKey3("KeccakSecp256k11111111111111111111111111111");
40077
+ Secp256k1Program.programId = new PublicKey4("KeccakSecp256k11111111111111111111111111111");
40078
40078
  var _Lockup;
40079
- var STAKE_CONFIG_ID = new PublicKey3("StakeConfig11111111111111111111111111111111");
40079
+ var STAKE_CONFIG_ID = new PublicKey4("StakeConfig11111111111111111111111111111111");
40080
40080
  var Authorized = class {
40081
40081
  /**
40082
40082
  * Create a new Authorized object
@@ -40107,7 +40107,7 @@ Message: ${transactionMessage}.
40107
40107
  */
40108
40108
  };
40109
40109
  _Lockup = Lockup;
40110
- Lockup.default = new _Lockup(0, 0, PublicKey3.default);
40110
+ Lockup.default = new _Lockup(0, 0, PublicKey4.default);
40111
40111
  var StakeInstruction = class {
40112
40112
  /**
40113
40113
  * @internal
@@ -40145,8 +40145,8 @@ Message: ${transactionMessage}.
40145
40145
  } = decodeData$1(STAKE_INSTRUCTION_LAYOUTS.Initialize, instruction.data);
40146
40146
  return {
40147
40147
  stakePubkey: instruction.keys[0].pubkey,
40148
- authorized: new Authorized(new PublicKey3(authorized2.staker), new PublicKey3(authorized2.withdrawer)),
40149
- lockup: new Lockup(lockup2.unixTimestamp, lockup2.epoch, new PublicKey3(lockup2.custodian))
40148
+ authorized: new Authorized(new PublicKey4(authorized2.staker), new PublicKey4(authorized2.withdrawer)),
40149
+ lockup: new Lockup(lockup2.unixTimestamp, lockup2.epoch, new PublicKey4(lockup2.custodian))
40150
40150
  };
40151
40151
  }
40152
40152
  /**
@@ -40175,7 +40175,7 @@ Message: ${transactionMessage}.
40175
40175
  const o = {
40176
40176
  stakePubkey: instruction.keys[0].pubkey,
40177
40177
  authorizedPubkey: instruction.keys[2].pubkey,
40178
- newAuthorizedPubkey: new PublicKey3(newAuthorized),
40178
+ newAuthorizedPubkey: new PublicKey4(newAuthorized),
40179
40179
  stakeAuthorizationType: {
40180
40180
  index: stakeAuthorizationType
40181
40181
  }
@@ -40201,8 +40201,8 @@ Message: ${transactionMessage}.
40201
40201
  stakePubkey: instruction.keys[0].pubkey,
40202
40202
  authorityBase: instruction.keys[1].pubkey,
40203
40203
  authoritySeed,
40204
- authorityOwner: new PublicKey3(authorityOwner),
40205
- newAuthorizedPubkey: new PublicKey3(newAuthorized),
40204
+ authorityOwner: new PublicKey4(authorityOwner),
40205
+ newAuthorizedPubkey: new PublicKey4(newAuthorized),
40206
40206
  stakeAuthorizationType: {
40207
40207
  index: stakeAuthorizationType
40208
40208
  }
@@ -40376,15 +40376,15 @@ Message: ${transactionMessage}.
40376
40376
  programId: this.programId,
40377
40377
  data
40378
40378
  };
40379
- return new TransactionInstruction3(instructionData);
40379
+ return new TransactionInstruction4(instructionData);
40380
40380
  }
40381
40381
  /**
40382
40382
  * Generate a Transaction that creates a new Stake account at
40383
40383
  * an address generated with `from`, a seed, and the Stake programId
40384
40384
  */
40385
40385
  static createAccountWithSeed(params) {
40386
- const transaction = new Transaction2();
40387
- transaction.add(SystemProgram.createAccountWithSeed({
40386
+ const transaction = new Transaction3();
40387
+ transaction.add(SystemProgram2.createAccountWithSeed({
40388
40388
  fromPubkey: params.fromPubkey,
40389
40389
  newAccountPubkey: params.stakePubkey,
40390
40390
  basePubkey: params.basePubkey,
@@ -40408,8 +40408,8 @@ Message: ${transactionMessage}.
40408
40408
  * Generate a Transaction that creates a new Stake account
40409
40409
  */
40410
40410
  static createAccount(params) {
40411
- const transaction = new Transaction2();
40412
- transaction.add(SystemProgram.createAccount({
40411
+ const transaction = new Transaction3();
40412
+ transaction.add(SystemProgram2.createAccount({
40413
40413
  fromPubkey: params.fromPubkey,
40414
40414
  newAccountPubkey: params.stakePubkey,
40415
40415
  lamports: params.lamports,
@@ -40440,7 +40440,7 @@ Message: ${transactionMessage}.
40440
40440
  } = params;
40441
40441
  const type = STAKE_INSTRUCTION_LAYOUTS.Delegate;
40442
40442
  const data = encodeData3(type);
40443
- return new Transaction2().add({
40443
+ return new Transaction3().add({
40444
40444
  keys: [{
40445
40445
  pubkey: stakePubkey,
40446
40446
  isSigner: false,
@@ -40507,7 +40507,7 @@ Message: ${transactionMessage}.
40507
40507
  isWritable: false
40508
40508
  });
40509
40509
  }
40510
- return new Transaction2().add({
40510
+ return new Transaction3().add({
40511
40511
  keys,
40512
40512
  programId: this.programId,
40513
40513
  data
@@ -40554,7 +40554,7 @@ Message: ${transactionMessage}.
40554
40554
  isWritable: false
40555
40555
  });
40556
40556
  }
40557
- return new Transaction2().add({
40557
+ return new Transaction3().add({
40558
40558
  keys,
40559
40559
  programId: this.programId,
40560
40560
  data
@@ -40574,7 +40574,7 @@ Message: ${transactionMessage}.
40574
40574
  const data = encodeData3(type, {
40575
40575
  lamports
40576
40576
  });
40577
- return new TransactionInstruction3({
40577
+ return new TransactionInstruction4({
40578
40578
  keys: [{
40579
40579
  pubkey: stakePubkey,
40580
40580
  isSigner: false,
@@ -40596,8 +40596,8 @@ Message: ${transactionMessage}.
40596
40596
  * Generate a Transaction that splits Stake tokens into another stake account
40597
40597
  */
40598
40598
  static split(params, rentExemptReserve) {
40599
- const transaction = new Transaction2();
40600
- transaction.add(SystemProgram.createAccount({
40599
+ const transaction = new Transaction3();
40600
+ transaction.add(SystemProgram2.createAccount({
40601
40601
  fromPubkey: params.authorizedPubkey,
40602
40602
  newAccountPubkey: params.splitStakePubkey,
40603
40603
  lamports: rentExemptReserve,
@@ -40619,8 +40619,8 @@ Message: ${transactionMessage}.
40619
40619
  seed,
40620
40620
  lamports
40621
40621
  } = params;
40622
- const transaction = new Transaction2();
40623
- transaction.add(SystemProgram.allocate({
40622
+ const transaction = new Transaction3();
40623
+ transaction.add(SystemProgram2.allocate({
40624
40624
  accountPubkey: splitStakePubkey,
40625
40625
  basePubkey,
40626
40626
  seed,
@@ -40628,7 +40628,7 @@ Message: ${transactionMessage}.
40628
40628
  programId: this.programId
40629
40629
  }));
40630
40630
  if (rentExemptReserve && rentExemptReserve > 0) {
40631
- transaction.add(SystemProgram.transfer({
40631
+ transaction.add(SystemProgram2.transfer({
40632
40632
  fromPubkey: params.authorizedPubkey,
40633
40633
  toPubkey: splitStakePubkey,
40634
40634
  lamports: rentExemptReserve
@@ -40652,7 +40652,7 @@ Message: ${transactionMessage}.
40652
40652
  } = params;
40653
40653
  const type = STAKE_INSTRUCTION_LAYOUTS.Merge;
40654
40654
  const data = encodeData3(type);
40655
- return new Transaction2().add({
40655
+ return new Transaction3().add({
40656
40656
  keys: [{
40657
40657
  pubkey: stakePubkey,
40658
40658
  isSigner: false,
@@ -40721,7 +40721,7 @@ Message: ${transactionMessage}.
40721
40721
  isWritable: false
40722
40722
  });
40723
40723
  }
40724
- return new Transaction2().add({
40724
+ return new Transaction3().add({
40725
40725
  keys,
40726
40726
  programId: this.programId,
40727
40727
  data
@@ -40737,7 +40737,7 @@ Message: ${transactionMessage}.
40737
40737
  } = params;
40738
40738
  const type = STAKE_INSTRUCTION_LAYOUTS.Deactivate;
40739
40739
  const data = encodeData3(type);
40740
- return new Transaction2().add({
40740
+ return new Transaction3().add({
40741
40741
  keys: [{
40742
40742
  pubkey: stakePubkey,
40743
40743
  isSigner: false,
@@ -40756,7 +40756,7 @@ Message: ${transactionMessage}.
40756
40756
  });
40757
40757
  }
40758
40758
  };
40759
- StakeProgram.programId = new PublicKey3("Stake11111111111111111111111111111111111111");
40759
+ StakeProgram.programId = new PublicKey4("Stake11111111111111111111111111111111111111");
40760
40760
  StakeProgram.space = 200;
40761
40761
  var VoteInit = class {
40762
40762
  /** [0, 100] */
@@ -40808,7 +40808,7 @@ Message: ${transactionMessage}.
40808
40808
  return {
40809
40809
  votePubkey: instruction.keys[0].pubkey,
40810
40810
  nodePubkey: instruction.keys[3].pubkey,
40811
- voteInit: new VoteInit(new PublicKey3(voteInit2.nodePubkey), new PublicKey3(voteInit2.authorizedVoter), new PublicKey3(voteInit2.authorizedWithdrawer), voteInit2.commission)
40811
+ voteInit: new VoteInit(new PublicKey4(voteInit2.nodePubkey), new PublicKey4(voteInit2.authorizedVoter), new PublicKey4(voteInit2.authorizedWithdrawer), voteInit2.commission)
40812
40812
  };
40813
40813
  }
40814
40814
  /**
@@ -40824,7 +40824,7 @@ Message: ${transactionMessage}.
40824
40824
  return {
40825
40825
  votePubkey: instruction.keys[0].pubkey,
40826
40826
  authorizedPubkey: instruction.keys[2].pubkey,
40827
- newAuthorizedPubkey: new PublicKey3(newAuthorized),
40827
+ newAuthorizedPubkey: new PublicKey4(newAuthorized),
40828
40828
  voteAuthorizationType: {
40829
40829
  index: voteAuthorizationType
40830
40830
  }
@@ -40846,9 +40846,9 @@ Message: ${transactionMessage}.
40846
40846
  } = decodeData$1(VOTE_INSTRUCTION_LAYOUTS.AuthorizeWithSeed, instruction.data);
40847
40847
  return {
40848
40848
  currentAuthorityDerivedKeyBasePubkey: instruction.keys[2].pubkey,
40849
- currentAuthorityDerivedKeyOwnerPubkey: new PublicKey3(currentAuthorityDerivedKeyOwnerPubkey),
40849
+ currentAuthorityDerivedKeyOwnerPubkey: new PublicKey4(currentAuthorityDerivedKeyOwnerPubkey),
40850
40850
  currentAuthorityDerivedKeySeed,
40851
- newAuthorizedPubkey: new PublicKey3(newAuthorized),
40851
+ newAuthorizedPubkey: new PublicKey4(newAuthorized),
40852
40852
  voteAuthorizationType: {
40853
40853
  index: voteAuthorizationType
40854
40854
  },
@@ -40966,14 +40966,14 @@ Message: ${transactionMessage}.
40966
40966
  programId: this.programId,
40967
40967
  data
40968
40968
  };
40969
- return new TransactionInstruction3(instructionData);
40969
+ return new TransactionInstruction4(instructionData);
40970
40970
  }
40971
40971
  /**
40972
40972
  * Generate a transaction that creates a new Vote account.
40973
40973
  */
40974
40974
  static createAccount(params) {
40975
- const transaction = new Transaction2();
40976
- transaction.add(SystemProgram.createAccount({
40975
+ const transaction = new Transaction3();
40976
+ transaction.add(SystemProgram2.createAccount({
40977
40977
  fromPubkey: params.fromPubkey,
40978
40978
  newAccountPubkey: params.votePubkey,
40979
40979
  lamports: params.lamports,
@@ -41014,7 +41014,7 @@ Message: ${transactionMessage}.
41014
41014
  isSigner: true,
41015
41015
  isWritable: false
41016
41016
  }];
41017
- return new Transaction2().add({
41017
+ return new Transaction3().add({
41018
41018
  keys,
41019
41019
  programId: this.programId,
41020
41020
  data
@@ -41055,7 +41055,7 @@ Message: ${transactionMessage}.
41055
41055
  isSigner: true,
41056
41056
  isWritable: false
41057
41057
  }];
41058
- return new Transaction2().add({
41058
+ return new Transaction3().add({
41059
41059
  keys,
41060
41060
  programId: this.programId,
41061
41061
  data
@@ -41088,7 +41088,7 @@ Message: ${transactionMessage}.
41088
41088
  isSigner: true,
41089
41089
  isWritable: false
41090
41090
  }];
41091
- return new Transaction2().add({
41091
+ return new Transaction3().add({
41092
41092
  keys,
41093
41093
  programId: this.programId,
41094
41094
  data
@@ -41132,16 +41132,16 @@ Message: ${transactionMessage}.
41132
41132
  isSigner: true,
41133
41133
  isWritable: false
41134
41134
  }];
41135
- return new Transaction2().add({
41135
+ return new Transaction3().add({
41136
41136
  keys,
41137
41137
  programId: this.programId,
41138
41138
  data
41139
41139
  });
41140
41140
  }
41141
41141
  };
41142
- VoteProgram.programId = new PublicKey3("Vote111111111111111111111111111111111111111");
41142
+ VoteProgram.programId = new PublicKey4("Vote111111111111111111111111111111111111111");
41143
41143
  VoteProgram.space = 3762;
41144
- var VALIDATOR_INFO_KEY = new PublicKey3("Va1idator1nfo111111111111111111111111111111");
41144
+ var VALIDATOR_INFO_KEY = new PublicKey4("Va1idator1nfo111111111111111111111111111111");
41145
41145
  var InfoString = superstruct.type({
41146
41146
  name: superstruct.string(),
41147
41147
  website: superstruct.optional(superstruct.string()),
@@ -41175,7 +41175,7 @@ Message: ${transactionMessage}.
41175
41175
  if (configKeyCount !== 2) return null;
41176
41176
  const configKeys = [];
41177
41177
  for (let i = 0; i < 2; i++) {
41178
- const publicKey2 = new PublicKey3(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
41178
+ const publicKey2 = new PublicKey4(guardedSplice(byteArray, 0, PUBLIC_KEY_LENGTH));
41179
41179
  const isSigner = guardedShift(byteArray) === 1;
41180
41180
  configKeys.push({
41181
41181
  publicKey: publicKey2,
@@ -41193,7 +41193,7 @@ Message: ${transactionMessage}.
41193
41193
  return null;
41194
41194
  }
41195
41195
  };
41196
- var VOTE_PROGRAM_ID = new PublicKey3("Vote111111111111111111111111111111111111111");
41196
+ var VOTE_PROGRAM_ID = new PublicKey4("Vote111111111111111111111111111111111111111");
41197
41197
  var VoteAccountLayout = BufferLayout__namespace.struct([
41198
41198
  publicKey("nodePubkey"),
41199
41199
  publicKey("authorizedWithdrawer"),
@@ -41250,8 +41250,8 @@ Message: ${transactionMessage}.
41250
41250
  rootSlot = null;
41251
41251
  }
41252
41252
  return new _VoteAccount({
41253
- nodePubkey: new PublicKey3(va.nodePubkey),
41254
- authorizedWithdrawer: new PublicKey3(va.authorizedWithdrawer),
41253
+ nodePubkey: new PublicKey4(va.nodePubkey),
41254
+ authorizedWithdrawer: new PublicKey4(va.authorizedWithdrawer),
41255
41255
  commission: va.commission,
41256
41256
  votes: va.votes,
41257
41257
  rootSlot,
@@ -41268,7 +41268,7 @@ Message: ${transactionMessage}.
41268
41268
  }) {
41269
41269
  return {
41270
41270
  epoch,
41271
- authorizedVoter: new PublicKey3(authorizedVoter)
41271
+ authorizedVoter: new PublicKey4(authorizedVoter)
41272
41272
  };
41273
41273
  }
41274
41274
  function parsePriorVoters({
@@ -41277,7 +41277,7 @@ Message: ${transactionMessage}.
41277
41277
  targetEpoch
41278
41278
  }) {
41279
41279
  return {
41280
- authorizedPubkey: new PublicKey3(authorizedPubkey),
41280
+ authorizedPubkey: new PublicKey4(authorizedPubkey),
41281
41281
  epochOfLastAuthorizedSwitch,
41282
41282
  targetEpoch
41283
41283
  };
@@ -41379,7 +41379,7 @@ Message: ${transactionMessage}.
41379
41379
  exports.NonceAccount = NonceAccount;
41380
41380
  exports.PACKET_DATA_SIZE = PACKET_DATA_SIZE;
41381
41381
  exports.PUBLIC_KEY_LENGTH = PUBLIC_KEY_LENGTH;
41382
- exports.PublicKey = PublicKey3;
41382
+ exports.PublicKey = PublicKey4;
41383
41383
  exports.SIGNATURE_LENGTH_IN_BYTES = SIGNATURE_LENGTH_IN_BYTES;
41384
41384
  exports.SOLANA_SCHEMA = SOLANA_SCHEMA;
41385
41385
  exports.STAKE_CONFIG_ID = STAKE_CONFIG_ID;
@@ -41403,12 +41403,12 @@ Message: ${transactionMessage}.
41403
41403
  exports.StakeProgram = StakeProgram;
41404
41404
  exports.Struct = Struct;
41405
41405
  exports.SystemInstruction = SystemInstruction;
41406
- exports.SystemProgram = SystemProgram;
41407
- exports.Transaction = Transaction2;
41406
+ exports.SystemProgram = SystemProgram2;
41407
+ exports.Transaction = Transaction3;
41408
41408
  exports.TransactionExpiredBlockheightExceededError = TransactionExpiredBlockheightExceededError;
41409
41409
  exports.TransactionExpiredNonceInvalidError = TransactionExpiredNonceInvalidError;
41410
41410
  exports.TransactionExpiredTimeoutError = TransactionExpiredTimeoutError;
41411
- exports.TransactionInstruction = TransactionInstruction3;
41411
+ exports.TransactionInstruction = TransactionInstruction4;
41412
41412
  exports.TransactionMessage = TransactionMessage;
41413
41413
  exports.TransactionStatus = TransactionStatus;
41414
41414
  exports.VALIDATOR_INFO_KEY = VALIDATOR_INFO_KEY;
@@ -41643,6 +41643,7 @@ var CHAIN_NAMES = {
41643
41643
  56: "BNB Chain",
41644
41644
  137: "Polygon",
41645
41645
  8453: "Base",
41646
+ 42161: "Arbitrum",
41646
41647
  900: "Solana",
41647
41648
  1500: "Stellar",
41648
41649
  lightning: "Bitcoin Lightning"
@@ -41652,19 +41653,31 @@ var CHAIN_FAMILY = {
41652
41653
  56: "evm",
41653
41654
  137: "evm",
41654
41655
  8453: "evm",
41656
+ 42161: "evm",
41655
41657
  900: "solana",
41656
41658
  1500: "stellar",
41657
41659
  lightning: "lightning"
41658
41660
  };
41659
41661
  var SUPPORTED_SOURCES = [
41660
- { chainId: "1", chain: "Ethereum", tokens: ["USDC", "USDT"] },
41661
- { chainId: "56", chain: "BNB Chain", tokens: ["USDC", "USDT"] },
41662
- { chainId: "137", chain: "Polygon", tokens: ["USDC", "USDT"] },
41663
- { chainId: "900", chain: "Solana", tokens: ["USDC", "USDT"] },
41664
- { chainId: "8453", chain: "Base", tokens: ["USDC"] },
41662
+ { chainId: "1", chain: "Ethereum", tokens: ["USDC", "USDT", "ETH"] },
41663
+ { chainId: "56", chain: "BNB Chain", tokens: ["USDC", "USDT", "BNB"] },
41664
+ { chainId: "137", chain: "Polygon", tokens: ["USDC", "USDT", "POL"] },
41665
+ { chainId: "900", chain: "Solana", tokens: ["USDC", "USDT", "SOL"] },
41666
+ { chainId: "8453", chain: "Base", tokens: ["USDC", "ETH"] },
41667
+ { chainId: "42161", chain: "Arbitrum", tokens: ["USDC", "USDT", "ETH"] },
41665
41668
  { chainId: "1500", chain: "Stellar", tokens: ["USDC"] },
41666
41669
  { chainId: "lightning", chain: "Bitcoin Lightning", tokens: ["BTC"] }
41667
41670
  ];
41671
+ var NATIVE_COINS = Object.freeze({
41672
+ "1:ETH": { chainId: "1", symbol: "ETH", decimals: 18 },
41673
+ "8453:ETH": { chainId: "8453", symbol: "ETH", decimals: 18 },
41674
+ "42161:ETH": { chainId: "42161", symbol: "ETH", decimals: 18 },
41675
+ "56:BNB": { chainId: "56", symbol: "BNB", decimals: 18 },
41676
+ "137:POL": { chainId: "137", symbol: "POL", decimals: 18 },
41677
+ "900:SOL": { chainId: "900", symbol: "SOL", decimals: 9 }
41678
+ });
41679
+ var NATIVE_MAX_USD = 2e3;
41680
+ var NATIVE_MIN_USD_FALLBACK = Object.freeze({ "1:ETH": 1 });
41668
41681
  var DECIMALS = {
41669
41682
  "1:USDC": 6,
41670
41683
  "1:USDT": 6,
@@ -41674,10 +41687,20 @@ var DECIMALS = {
41674
41687
  "137:USDC": 6,
41675
41688
  "137:USDT": 6,
41676
41689
  "8453:USDC": 6,
41690
+ // Arbitrum One: native USDC and USDT0 are both 6-decimals.
41691
+ "42161:USDC": 6,
41692
+ "42161:USDT": 6,
41677
41693
  "900:USDC": 6,
41678
41694
  "900:USDT": 6,
41679
41695
  // Stellar classic assets carry 7 decimal places.
41680
- "1500:USDC": 7
41696
+ "1500:USDC": 7,
41697
+ // Native coins: wei (18) on every EVM chain, lamports (9) on Solana.
41698
+ "1:ETH": 18,
41699
+ "8453:ETH": 18,
41700
+ "42161:ETH": 18,
41701
+ "56:BNB": 18,
41702
+ "137:POL": 18,
41703
+ "900:SOL": 9
41681
41704
  };
41682
41705
  var AmountError = class extends Error {
41683
41706
  constructor(code, message) {
@@ -41779,6 +41802,74 @@ function isSupportedSource(chainId, tokenSymbol) {
41779
41802
  const sym = String(tokenSymbol || "").trim().toUpperCase();
41780
41803
  return SUPPORTED_SOURCES.some((s) => s.chainId === cid && s.tokens.includes(sym));
41781
41804
  }
41805
+ function isNativeSource(chainId, tokenSymbol) {
41806
+ return Object.prototype.hasOwnProperty.call(NATIVE_COINS, decimalsKey(chainId, tokenSymbol));
41807
+ }
41808
+ var NATIVE_TOKEN_ADDRESSES = /* @__PURE__ */ new Set([
41809
+ "",
41810
+ "0x0000000000000000000000000000000000000000",
41811
+ "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
41812
+ "native",
41813
+ "11111111111111111111111111111111"
41814
+ ]);
41815
+ function isNativeTokenAddress(tokenAddress) {
41816
+ if (tokenAddress === null || tokenAddress === void 0) return true;
41817
+ return NATIVE_TOKEN_ADDRESSES.has(String(tokenAddress).trim().toLowerCase());
41818
+ }
41819
+ function nativeMinUsdFor(chainId, tokenSymbol, quoteNativeMinUsd) {
41820
+ const cid = String(chainId).trim();
41821
+ const sym = String(tokenSymbol || "").trim().toUpperCase();
41822
+ const fromQuote = quoteNativeMinUsd?.[cid]?.[sym];
41823
+ const n = Number(fromQuote);
41824
+ if (fromQuote !== void 0 && fromQuote !== null && Number.isFinite(n) && n > 0) return n;
41825
+ return NATIVE_MIN_USD_FALLBACK[`${cid}:${sym}`] ?? null;
41826
+ }
41827
+ function nativeOfferFor({ chainId, tokenSymbol, supportedSources, nativeMinUsd, callerPaysUsd }) {
41828
+ const cid = String(chainId).trim();
41829
+ const sym = String(tokenSymbol || "").trim().toUpperCase();
41830
+ const label = `${sym} on ${chainName(cid)}`;
41831
+ const minUsd = nativeMinUsdFor(cid, sym, nativeMinUsd);
41832
+ if (!isNativeSource(cid, sym)) {
41833
+ return { ok: false, code: "NOT_NATIVE", reason: `${label} is not a native coin.`, minUsd: null };
41834
+ }
41835
+ const list = supportedSources && typeof supportedSources === "object" ? supportedSources[cid] : null;
41836
+ if (!Array.isArray(list) || !list.map((t) => String(t).toUpperCase()).includes(sym)) {
41837
+ return {
41838
+ ok: false,
41839
+ code: "NATIVE_NOT_OFFERED",
41840
+ reason: `${label} is not offered for this invoice. Pay with USDC or USDT instead.`,
41841
+ minUsd
41842
+ };
41843
+ }
41844
+ const usd = Number(callerPaysUsd);
41845
+ if (!Number.isFinite(usd) || usd <= 0) {
41846
+ return {
41847
+ ok: false,
41848
+ code: "NATIVE_AMOUNT_UNKNOWN",
41849
+ reason: `The quote carries no USD amount, so ${label} cannot be checked against the native limits. Pay with USDC or USDT instead.`,
41850
+ minUsd
41851
+ };
41852
+ }
41853
+ {
41854
+ if (usd > NATIVE_MAX_USD) {
41855
+ return {
41856
+ ok: false,
41857
+ code: "NATIVE_AMOUNT_TOO_HIGH",
41858
+ reason: `Native coin orders are limited to $${NATIVE_MAX_USD} per invoice; this one is $${usd}. Pay with USDC or USDT instead.`,
41859
+ minUsd
41860
+ };
41861
+ }
41862
+ if (minUsd !== null && usd < minUsd) {
41863
+ return {
41864
+ ok: false,
41865
+ code: "NATIVE_AMOUNT_TOO_LOW",
41866
+ reason: `${label} needs an invoice of at least $${minUsd}; this one is $${usd}. Pay with another coin.`,
41867
+ minUsd
41868
+ };
41869
+ }
41870
+ }
41871
+ return { ok: true, code: null, reason: null, minUsd };
41872
+ }
41782
41873
 
41783
41874
  // scripts/src/lib/utm.mjs
41784
41875
  function normalizeUtmSource(value) {
@@ -41853,6 +41944,9 @@ var CHAIN_ALIASES = {
41853
41944
  polygon: "137",
41854
41945
  matic: "137",
41855
41946
  base: "8453",
41947
+ arbitrum: "42161",
41948
+ arb: "42161",
41949
+ arbitrumone: "42161",
41856
41950
  solana: "900",
41857
41951
  sol: "900",
41858
41952
  stellar: "1500",
@@ -41862,34 +41956,69 @@ var CHAIN_ALIASES = {
41862
41956
  bitcoin: "lightning",
41863
41957
  btc: "lightning"
41864
41958
  };
41865
- var PICKER_OPTIONS = [
41866
- { token: "USDT", chain: "Solana", chainId: "900" },
41867
- { token: "USDT", chain: "BNB Chain", chainId: "56" },
41868
- { token: "USDT", chain: "Ethereum", chainId: "1" },
41869
- { token: "USDT", chain: "Polygon", chainId: "137" },
41870
- { token: "USDC", chain: "Solana", chainId: "900" },
41871
- { token: "USDC", chain: "BNB Chain", chainId: "56" },
41872
- { token: "USDC", chain: "Ethereum", chainId: "1" },
41873
- { token: "USDC", chain: "Polygon", chainId: "137" },
41874
- { token: "USDC", chain: "Base", chainId: "8453" },
41875
- { token: "USDC", chain: "Stellar", chainId: "1500" },
41876
- { token: "BTC", chain: "Lightning", chainId: "lightning" }
41877
- ].map((o, i) => ({
41878
- number: i + 1,
41959
+ var PRESET_CHAIN = {
41960
+ "900": "solana",
41961
+ "56": "bnb",
41962
+ "1": "ethereum",
41963
+ "137": "polygon",
41964
+ "8453": "base",
41965
+ "42161": "arbitrum",
41966
+ "1500": "stellar",
41967
+ lightning: "lightning"
41968
+ };
41969
+ var PRESET_SHORTCUTS = Object.freeze({
41970
+ bnb: "bnb-bnb",
41971
+ sol: "sol-solana",
41972
+ pol: "pol-polygon"
41973
+ });
41974
+ var PICKER_ROWS = [
41975
+ { group: "USDT", token: "USDT", chain: "Solana", chainId: "900" },
41976
+ { group: "USDT", token: "USDT", chain: "BNB Chain", chainId: "56" },
41977
+ { group: "USDT", token: "USDT", chain: "Ethereum", chainId: "1" },
41978
+ { group: "USDT", token: "USDT", chain: "Polygon", chainId: "137" },
41979
+ { group: "USDT", token: "USDT", chain: "Arbitrum", chainId: "42161" },
41980
+ { group: "USDC", token: "USDC", chain: "Solana", chainId: "900" },
41981
+ { group: "USDC", token: "USDC", chain: "BNB Chain", chainId: "56" },
41982
+ { group: "USDC", token: "USDC", chain: "Ethereum", chainId: "1" },
41983
+ { group: "USDC", token: "USDC", chain: "Polygon", chainId: "137" },
41984
+ { group: "USDC", token: "USDC", chain: "Base", chainId: "8453" },
41985
+ { group: "USDC", token: "USDC", chain: "Arbitrum", chainId: "42161" },
41986
+ { group: "USDC", token: "USDC", chain: "Stellar", chainId: "1500" },
41987
+ { group: "BTC", token: "BTC", chain: "Lightning", chainId: "lightning" },
41988
+ { group: "Native coins", token: "ETH", chain: "Base", chainId: "8453" },
41989
+ { group: "Native coins", token: "ETH", chain: "Ethereum", chainId: "1" },
41990
+ { group: "Native coins", token: "ETH", chain: "Arbitrum", chainId: "42161" },
41991
+ { group: "Native coins", token: "BNB", chain: "BNB Chain", chainId: "56" },
41992
+ { group: "Native coins", token: "SOL", chain: "Solana", chainId: "900" },
41993
+ { group: "Native coins", token: "POL", chain: "Polygon", chainId: "137" }
41994
+ ].map((o) => ({
41879
41995
  ...o,
41880
41996
  tokenSymbol: o.token,
41997
+ native: isNativeSource(o.chainId, o.token),
41998
+ // What a row says after its number. Native rows name the coin, since the
41999
+ // group heading does not.
42000
+ label: isNativeSource(o.chainId, o.token) ? `${o.token} on ${o.chain}` : o.chain,
41881
42001
  // The flag a user could have typed instead, echoed back so they learn it.
41882
- preset: `${o.token.toLowerCase()}-${{ "900": "solana", "56": "bnb", "1": "ethereum", "137": "polygon", "8453": "base", "1500": "stellar", lightning: "lightning" }[o.chainId]}`
42002
+ preset: `${o.token.toLowerCase()}-${PRESET_CHAIN[o.chainId]}`
41883
42003
  }));
41884
- function resolvePickerChoice(input) {
42004
+ function numbered(rows) {
42005
+ return rows.map((o, i) => ({ number: i + 1, ...o }));
42006
+ }
42007
+ var PICKER_OPTIONS = numbered(PICKER_ROWS);
42008
+ function pickerOptionsFor(isOffered = null) {
42009
+ return numbered(
42010
+ PICKER_ROWS.filter((o) => !o.native || typeof isOffered === "function" && isOffered(o.chainId, o.tokenSymbol))
42011
+ );
42012
+ }
42013
+ function resolvePickerChoice(input, options = PICKER_OPTIONS) {
41885
42014
  const raw = String(input ?? "").trim();
41886
42015
  if (!raw) throw new CliError("BAD_CHOICE", "Nothing entered. Type the number of a coin.");
41887
42016
  if (/^\d+$/.test(raw)) {
41888
- const option2 = PICKER_OPTIONS.find((o) => o.number === Number(raw));
42017
+ const option2 = options.find((o) => o.number === Number(raw));
41889
42018
  if (!option2) {
41890
42019
  throw new CliError(
41891
42020
  "BAD_CHOICE",
41892
- `${raw} is not on the list. Choose 1-${PICKER_OPTIONS.length}.`
42021
+ `${raw} is not on the list. Choose 1-${options.length}.`
41893
42022
  );
41894
42023
  }
41895
42024
  return { chainId: option2.chainId, tokenSymbol: option2.tokenSymbol, preset: option2.preset };
@@ -41910,16 +42039,23 @@ var CliError = class extends Error {
41910
42039
  function listPresets() {
41911
42040
  const out2 = [];
41912
42041
  for (const s of SUPPORTED_SOURCES) {
41913
- const chain = Object.entries(CHAIN_ALIASES).find(([, id]) => id === s.chainId)?.[0];
42042
+ const chain = PRESET_CHAIN[s.chainId];
41914
42043
  for (const token of s.tokens) out2.push(`${token.toLowerCase()}-${chain}`);
41915
42044
  }
41916
42045
  return out2;
41917
42046
  }
41918
42047
  function resolvePreset(preset) {
41919
- const raw = String(preset ?? "").trim().toLowerCase();
42048
+ let raw = String(preset ?? "").trim().toLowerCase();
41920
42049
  if (!raw) {
41921
42050
  throw new CliError("MISSING_PRESET", "A coin is required, e.g. --with usdt-solana");
41922
42051
  }
42052
+ if (PRESET_SHORTCUTS[raw]) raw = PRESET_SHORTCUTS[raw];
42053
+ if (raw === "eth") {
42054
+ throw new CliError(
42055
+ "BAD_PRESET",
42056
+ "ETH is on more than one chain. Use eth-ethereum, eth-base or eth-arbitrum."
42057
+ );
42058
+ }
41923
42059
  const idx = raw.indexOf("-");
41924
42060
  if (idx <= 0 || idx === raw.length - 1) {
41925
42061
  throw new CliError(
@@ -42194,7 +42330,8 @@ function parseCliArgs(argv) {
42194
42330
  };
42195
42331
  }
42196
42332
  var HELP = `rozo-checkout \u2014 pay a Coinbase Payment Link or a Bitrefill invoice
42197
- (USDC on Base) with BTC Lightning, or USDT/USDC on Solana, BNB Chain, Ethereum, Polygon, Base or Stellar.
42333
+ (USDC on Base) with BTC Lightning, USDT/USDC on Solana, BNB Chain, Ethereum, Polygon,
42334
+ Arbitrum, Base or Stellar, or a native coin: ETH (Ethereum, Base, Arbitrum), BNB, SOL, POL.
42198
42335
 
42199
42336
  USAGE
42200
42337
  npx @rozoai/checkout pay <coinbase-link> (pick a coin from a list)
@@ -42209,9 +42346,21 @@ USAGE
42209
42346
  COINS (--with)
42210
42347
  usdt-solana usdc-solana usdt-bnb usdc-bnb
42211
42348
  usdt-ethereum usdc-ethereum usdt-polygon usdc-polygon
42212
- usdc-base usdc-stellar btc-lightning
42349
+ usdt-arbitrum usdc-arbitrum usdc-base usdc-stellar
42350
+ btc-lightning
42351
+ native coins: eth-ethereum eth-base eth-arbitrum bnb-bnb (or bnb)
42352
+ sol-solana (or sol) pol-polygon (or pol)
42213
42353
  or give them raw: --chain 900 --token USDT
42214
42354
 
42355
+ NATIVE COINS
42356
+ Offered only when the invoice's quote lists the coin, and only for invoices
42357
+ up to $2,000 (native ETH on Ethereum: $1 minimum). The order is exact-out:
42358
+ send exactly the coin amount shown. Its price is locked only until the time
42359
+ shown (about an hour); after that do not send, start a new order. The coin
42360
+ amount includes an FX spread on top of the service fee, and your wallet also
42361
+ needs a little of the same coin for the network fee. On-chain BTC and Tron
42362
+ are not supported.
42363
+
42215
42364
  By default, pay just prints an address for you to pay from any wallet:
42216
42365
  no private key, no environment variable, no configuration.
42217
42366
 
@@ -42219,10 +42368,12 @@ OPTIONS
42219
42368
  --with <coin> which coin to pay with. Omit it on a terminal and you get a
42220
42369
  numbered list to choose from; scripts and agents must pass it.
42221
42370
  --send optional. Sign from a hot wallet instead of paying yourself.
42222
- The only option that needs a key. On Solana it uses your
42223
- existing ~/.config/solana/id.json; on EVM an encrypted JSON
42224
- keystore. A single payment may not exceed $1,100; there is
42225
- no override.
42371
+ The only option that needs a key. EVM and Solana coins only,
42372
+ native ETH, BNB, POL and SOL included (sent as a plain
42373
+ transfer of the exact amount, never after the price lock).
42374
+ On Solana it uses your existing ~/.config/solana/id.json; on
42375
+ EVM an encrypted JSON keystore. A single payment may not
42376
+ exceed $1,100; there is no override.
42226
42377
  --keyfile <p> with --send: the key to sign with. A solana-keygen keypair
42227
42378
  file, or an encrypted V3 keystore for EVM (passphrase is
42228
42379
  prompted, never passed as a flag).
@@ -42290,6 +42441,296 @@ paid until you confirm, and --send is required before anything is signed.
42290
42441
  SUPPORT
42291
42442
  Email hi@rozo.ai, X https://x.com/ROZOai, Discord https://discord.gg/EfWejgTbuU`;
42292
42443
 
42444
+ // scripts/src/lib/gas.mjs
42445
+ var EVM_FEE_COIN = Object.freeze({
42446
+ 1: { symbol: "ETH", network: "Ethereum" },
42447
+ 56: { symbol: "BNB", network: "BNB Chain" },
42448
+ 137: { symbol: "POL", network: "Polygon" },
42449
+ 8453: { symbol: "ETH", network: "Base" },
42450
+ 42161: { symbol: "ETH", network: "Arbitrum" }
42451
+ });
42452
+ var DEFAULT_GAS_BUFFER_PCT = 20;
42453
+ var MAX_GAS_BUFFER_PCT = 200;
42454
+ function gasBufferPct(env = process.env) {
42455
+ const raw = env?.ROZO_CHECKOUT_GAS_BUFFER_PCT;
42456
+ if (raw === void 0 || raw === "") return DEFAULT_GAS_BUFFER_PCT;
42457
+ const n = Number(raw);
42458
+ if (!Number.isInteger(n) || n < 0 || n > MAX_GAS_BUFFER_PCT) return DEFAULT_GAS_BUFFER_PCT;
42459
+ return n;
42460
+ }
42461
+ function formatAtomic(atomic, decimals) {
42462
+ const neg = atomic < 0n;
42463
+ const v = neg ? -atomic : atomic;
42464
+ const base = 10n ** BigInt(decimals);
42465
+ const whole = v / base;
42466
+ const frac = (v % base).toString().padStart(decimals, "0").replace(/0+$/, "");
42467
+ return `${neg ? "-" : ""}${whole}${frac ? `.${frac}` : ""}`;
42468
+ }
42469
+ function evmFeeRequirement({ gasEstimate, maxFeePerGas, gasPrice, bufferPct = DEFAULT_GAS_BUFFER_PCT }) {
42470
+ const perGas = typeof maxFeePerGas === "bigint" ? maxFeePerGas : typeof gasPrice === "bigint" ? gasPrice : null;
42471
+ if (typeof gasEstimate !== "bigint" || perGas === null) return null;
42472
+ const gasLimit = (gasEstimate * BigInt(100 + bufferPct) + 99n) / 100n;
42473
+ return { gasLimit, perGas, pricing: typeof maxFeePerGas === "bigint" ? "eip1559" : "legacy", fee: gasLimit * perGas };
42474
+ }
42475
+ function assessFee({ balance, required, decimals, symbol, network }) {
42476
+ const ok = required === null ? balance > 0n : balance >= required;
42477
+ const details = {
42478
+ network,
42479
+ feeCoin: symbol,
42480
+ balance: formatAtomic(balance, decimals),
42481
+ required: required === null ? null : formatAtomic(required, decimals),
42482
+ shortfall: required === null || ok ? null : formatAtomic(required - balance, decimals)
42483
+ };
42484
+ return { ok, details };
42485
+ }
42486
+ function insufficient(details, extra) {
42487
+ const need = details.required ? `about ${details.required} ${details.feeCoin}` : `some ${details.feeCoin}`;
42488
+ const forWhat = details.payment ? `for the payment of ${details.payment} ${details.feeCoin} plus the network fee` : "for the network fee";
42489
+ return new SkillError(
42490
+ "INSUFFICIENT_GAS",
42491
+ `This wallet holds ${details.balance} ${details.feeCoin} on ${details.network} but needs ${need} ${forWhat}${details.shortfall ? ` (short by ${details.shortfall} ${details.feeCoin})` : ""}. Nothing was signed. Add ${details.feeCoin} on ${details.network} to this wallet and re-run, or pay with a different coin.` + (extra ? ` ${extra}` : ""),
42492
+ details
42493
+ );
42494
+ }
42495
+ function unavailable(network, err) {
42496
+ return new SkillError(
42497
+ "GAS_CHECK_UNAVAILABLE",
42498
+ `Could not check the network fee on ${network}: ${redact(err?.shortMessage || err?.message || "unknown error")}. This is not evidence of a shortfall. Nothing was signed. Retry, pass --rpc <url>, or pay by hand from your wallet.`,
42499
+ { network }
42500
+ );
42501
+ }
42502
+ async function estimateFees(client) {
42503
+ try {
42504
+ return await client.estimateFeesPerGas();
42505
+ } catch (err) {
42506
+ if (err?.name !== "Eip1559FeesNotSupportedError") throw err;
42507
+ return client.estimateFeesPerGas({ type: "legacy" });
42508
+ }
42509
+ }
42510
+ var OP_STACK_GAS_PRICE_ORACLE = "0x420000000000000000000000000000000000000F";
42511
+ var OP_STACK_CHAIN_IDS = /* @__PURE__ */ new Set([8453]);
42512
+ async function evmGasPrecheck({
42513
+ client,
42514
+ chainId,
42515
+ from: from15,
42516
+ to,
42517
+ data,
42518
+ value = 0n,
42519
+ bufferPct = gasBufferPct(),
42520
+ estimateL1Fee: estimateL1Fee2 = null
42521
+ }) {
42522
+ const coin = EVM_FEE_COIN[Number(chainId)] ?? { symbol: "native coin", network: `chain ${chainId}` };
42523
+ let balance;
42524
+ try {
42525
+ balance = await client.getBalance({ address: from15 });
42526
+ } catch (err) {
42527
+ throw unavailable(coin.network, err);
42528
+ }
42529
+ let gasEstimate;
42530
+ let fees;
42531
+ try {
42532
+ gasEstimate = await client.estimateGas({ account: from15, to, data, value });
42533
+ fees = await estimateFees(client);
42534
+ } catch (err) {
42535
+ if (balance === 0n) {
42536
+ throw insufficient(
42537
+ assessFee({ balance, required: null, decimals: 18, symbol: coin.symbol, network: coin.network }).details
42538
+ );
42539
+ }
42540
+ throw unavailable(coin.network, err);
42541
+ }
42542
+ const req = evmFeeRequirement({
42543
+ gasEstimate,
42544
+ maxFeePerGas: fees?.maxFeePerGas,
42545
+ gasPrice: fees?.gasPrice,
42546
+ bufferPct
42547
+ });
42548
+ if (!req) throw unavailable(coin.network, new Error("the node returned no fee price"));
42549
+ let l1Fee = 0n;
42550
+ if (OP_STACK_CHAIN_IDS.has(Number(chainId))) {
42551
+ if (typeof estimateL1Fee2 !== "function") {
42552
+ throw unavailable(coin.network, new Error("no L1 data fee estimator for this OP-stack chain"));
42553
+ }
42554
+ try {
42555
+ l1Fee = (await estimateL1Fee2() * BigInt(100 + bufferPct) + 99n) / 100n;
42556
+ } catch (err) {
42557
+ throw unavailable(coin.network, err);
42558
+ }
42559
+ }
42560
+ const required = req.fee + l1Fee + value;
42561
+ const { ok, details } = assessFee({ balance, required, decimals: 18, symbol: coin.symbol, network: coin.network });
42562
+ const full = {
42563
+ ...details,
42564
+ payment: value > 0n ? formatAtomic(value, 18) : null,
42565
+ gasLimit: req.gasLimit.toString(),
42566
+ pricing: req.pricing,
42567
+ bufferPct,
42568
+ l1DataFee: OP_STACK_CHAIN_IDS.has(Number(chainId)) ? formatAtomic(l1Fee, 18) : null
42569
+ };
42570
+ if (!ok) throw insufficient(full);
42571
+ return full;
42572
+ }
42573
+ var LAMPORTS_DECIMALS = 9;
42574
+ async function solFeePrecheck({ connection, payer, message, value = 0n }) {
42575
+ const network = "Solana";
42576
+ let balance;
42577
+ let fee;
42578
+ let rentMin;
42579
+ try {
42580
+ balance = BigInt(await connection.getBalance(payer, "confirmed"));
42581
+ const res = await connection.getFeeForMessage(message, "confirmed");
42582
+ if (res?.value === null || res?.value === void 0) {
42583
+ throw new Error("the node returned no fee for this transaction (stale blockhash?)");
42584
+ }
42585
+ fee = BigInt(res.value);
42586
+ rentMin = BigInt(await connection.getMinimumBalanceForRentExemption(0));
42587
+ } catch (err) {
42588
+ if (balance === 0n) {
42589
+ throw insufficient(
42590
+ assessFee({ balance, required: null, decimals: LAMPORTS_DECIMALS, symbol: "SOL", network }).details
42591
+ );
42592
+ }
42593
+ throw unavailable(network, err);
42594
+ }
42595
+ const remaining = balance - fee - value;
42596
+ const required = remaining === 0n ? fee + value : fee + value + rentMin;
42597
+ const { ok, details } = assessFee({ balance, required, decimals: LAMPORTS_DECIMALS, symbol: "SOL", network });
42598
+ const full = {
42599
+ ...details,
42600
+ payment: value > 0n ? formatAtomic(value, LAMPORTS_DECIMALS) : null,
42601
+ fee: formatAtomic(fee, LAMPORTS_DECIMALS),
42602
+ rentExemptMinimum: formatAtomic(rentMin, LAMPORTS_DECIMALS)
42603
+ };
42604
+ if (!ok) {
42605
+ throw insufficient(
42606
+ full,
42607
+ balance >= fee + value ? "Solana also requires a wallet to keep a small minimum balance after paying the fee." : null
42608
+ );
42609
+ }
42610
+ return full;
42611
+ }
42612
+
42613
+ // scripts/src/lib/rpc.mjs
42614
+ var DEFAULT_RPC = Object.freeze({
42615
+ // eth.llamarpc.com and polygon-rpc.com stopped answering (checked
42616
+ // 2026-10-12: HTTP 525, and "API key disabled"); publicnode serves both.
42617
+ 1: "https://ethereum-rpc.publicnode.com",
42618
+ 56: "https://bsc-dataseed.binance.org",
42619
+ 137: "https://polygon-bor-rpc.publicnode.com",
42620
+ 8453: "https://mainnet.base.org",
42621
+ 42161: "https://arb1.arbitrum.io/rpc",
42622
+ 900: "https://api.mainnet-beta.solana.com"
42623
+ });
42624
+ function rpcFor(chainId, override, env = process.env) {
42625
+ if (override && override !== true) return String(override);
42626
+ const fromEnv = env?.[`ROZO_CHECKOUT_RPC_${chainId}`];
42627
+ if (fromEnv) return fromEnv;
42628
+ const fallback = DEFAULT_RPC[String(chainId)];
42629
+ if (!fallback) {
42630
+ throw new SkillError(
42631
+ "NO_RPC",
42632
+ `No RPC known for chain ${chainId}. Pass --rpc <url> or set ROZO_CHECKOUT_RPC_${chainId}.`
42633
+ );
42634
+ }
42635
+ return fallback;
42636
+ }
42637
+
42638
+ // scripts/src/lib/native.mjs
42639
+ var NATIVE_BALANCE_TIMEOUT_MS = 3e3;
42640
+ var EVM_HEADROOM_GAS = 100000n;
42641
+ var SOL_HEADROOM_LAMPORTS = 1000000n;
42642
+ function nativeDepositWarnings({ tokenSymbol, chainId }) {
42643
+ const coin = String(tokenSymbol || "").toUpperCase();
42644
+ return [
42645
+ `This is an exact-out ${coin} order: send exactly the amount shown, in one transfer. The coin price is locked only until the time shown; after that, do not send, start a new order.`,
42646
+ `The ${coin} amount includes an FX spread on top of the service fee.`,
42647
+ `Your wallet also needs some ${coin} on ${chainName(chainId)} for the network fee, on top of the amount shown.`,
42648
+ "Paying from an exchange: make sure the amount that ARRIVES is exactly the amount shown. Exchanges often subtract their withdrawal fee, and a short payment may need manual review."
42649
+ ];
42650
+ }
42651
+ function nativeCoinsForFamily(family, isOffered = null) {
42652
+ return Object.values(NATIVE_COINS).filter(
42653
+ (c2) => chainFamily(c2.chainId) === family && (typeof isOffered !== "function" || isOffered(c2.chainId, c2.symbol))
42654
+ );
42655
+ }
42656
+ async function rpcCall(fetchImpl, url, method, params, signal) {
42657
+ const res = await fetchImpl(url, {
42658
+ method: "POST",
42659
+ headers: { "content-type": "application/json", accept: "application/json" },
42660
+ body: JSON.stringify({ jsonrpc: "2.0", id: 1, method, params }),
42661
+ signal
42662
+ });
42663
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
42664
+ const json = await res.json();
42665
+ if (json?.error) throw new Error(String(json.error?.message ?? "rpc error"));
42666
+ return json?.result;
42667
+ }
42668
+ function hexToBigInt(value) {
42669
+ if (typeof value !== "string" || !/^0x[0-9a-fA-F]+$/.test(value)) {
42670
+ throw new Error("not a hex quantity");
42671
+ }
42672
+ return BigInt(value);
42673
+ }
42674
+ async function fetchNativeBalance({
42675
+ chainId,
42676
+ address,
42677
+ fetchImpl = globalThis.fetch,
42678
+ timeoutMs = NATIVE_BALANCE_TIMEOUT_MS,
42679
+ env = process.env
42680
+ }) {
42681
+ const coin = Object.values(NATIVE_COINS).find((c2) => c2.chainId === String(chainId));
42682
+ if (!coin) return { ok: false, chainId: String(chainId), reason: "not a native coin chain" };
42683
+ const base = { chainId: coin.chainId, tokenSymbol: coin.symbol, decimals: coin.decimals };
42684
+ let url;
42685
+ try {
42686
+ url = rpcFor(coin.chainId, null, env);
42687
+ } catch (err) {
42688
+ return { ...base, ok: false, reason: err.message };
42689
+ }
42690
+ const controller = new AbortController();
42691
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
42692
+ try {
42693
+ if (chainFamily(coin.chainId) === "solana") {
42694
+ const r = await rpcCall(fetchImpl, url, "getBalance", [address, { commitment: "confirmed" }], controller.signal);
42695
+ const lamports = r?.value;
42696
+ if (!Number.isSafeInteger(lamports) || lamports < 0) throw new Error("bad balance");
42697
+ return { ...base, ok: true, balanceAtomic: BigInt(lamports), headroomAtomic: SOL_HEADROOM_LAMPORTS };
42698
+ }
42699
+ const [bal, gasPrice] = await Promise.all([
42700
+ rpcCall(fetchImpl, url, "eth_getBalance", [address, "latest"], controller.signal),
42701
+ rpcCall(fetchImpl, url, "eth_gasPrice", [], controller.signal)
42702
+ ]);
42703
+ const balanceAtomic = hexToBigInt(bal);
42704
+ const headroomAtomic = hexToBigInt(gasPrice) * EVM_HEADROOM_GAS * 120n / 100n;
42705
+ return { ...base, ok: true, balanceAtomic, headroomAtomic };
42706
+ } catch (err) {
42707
+ return {
42708
+ ...base,
42709
+ ok: false,
42710
+ reason: err?.name === "AbortError" ? "balance check timed out" : "balance check unavailable"
42711
+ };
42712
+ } finally {
42713
+ clearTimeout(timer);
42714
+ }
42715
+ }
42716
+ async function fetchNativeBalances({ address, family, isOffered = null, ...rest }) {
42717
+ const coins = nativeCoinsForFamily(family, isOffered);
42718
+ return Promise.all(coins.map((c2) => fetchNativeBalance({ chainId: c2.chainId, address, ...rest })));
42719
+ }
42720
+ function assessNative({ balanceAtomic, headroomAtomic, amountAtomic = null }) {
42721
+ if (amountAtomic === null || amountAtomic === void 0) {
42722
+ if (balanceAtomic <= headroomAtomic) return { mark: "insufficient", provable: balanceAtomic === 0n };
42723
+ return { mark: "held", provable: false };
42724
+ }
42725
+ if (balanceAtomic < amountAtomic) return { mark: "insufficient", provable: true };
42726
+ if (balanceAtomic < amountAtomic + headroomAtomic) return { mark: "tight", provable: false };
42727
+ return { mark: "affordable", provable: false };
42728
+ }
42729
+ function formatNativeHeld(result) {
42730
+ if (!result?.ok) return null;
42731
+ return `${formatAtomic(result.balanceAtomic, result.decimals)} ${result.tokenSymbol}`;
42732
+ }
42733
+
42293
42734
  // scripts/src/lib/wallet-check.mjs
42294
42735
  var INTENT_API_BASE = process.env.ROZO_CHECKOUT_INTENT_API || "https://intentapi.rozo.ai";
42295
42736
  var BALANCE_TIMEOUT_MS = 3e3;
@@ -42366,13 +42807,28 @@ function parsePaymentOptions(json) {
42366
42807
  }
42367
42808
  return out2;
42368
42809
  }
42369
- function markPickerOptions(pickerOptions, { family = null, options = [] } = {}) {
42810
+ function markPickerOptions(pickerOptions, { family = null, options = [], native = [], ok = true } = {}) {
42370
42811
  const index2 = /* @__PURE__ */ new Map();
42371
42812
  for (const o of options) index2.set(`${o.chainId}:${o.tokenSymbol}`, o);
42813
+ const nativeIndex = /* @__PURE__ */ new Map();
42814
+ for (const n of native ?? []) if (n?.chainId) nativeIndex.set(String(n.chainId), n);
42372
42815
  const marked = pickerOptions.map((row) => {
42373
42816
  if (!family || !familyCoversChain(family, row.chainId)) {
42374
42817
  return { ...row, mark: "unchecked", balanceUsd: null, note: null };
42375
42818
  }
42819
+ if (isNativeSource(row.chainId, row.tokenSymbol)) {
42820
+ const n = nativeIndex.get(String(row.chainId));
42821
+ if (!n || !n.ok) return { ...row, mark: "unchecked", balanceUsd: null, note: n?.reason ?? null };
42822
+ const verdict = assessNative({ balanceAtomic: n.balanceAtomic, headroomAtomic: n.headroomAtomic });
42823
+ return {
42824
+ ...row,
42825
+ mark: verdict.mark,
42826
+ balanceUsd: null,
42827
+ held: formatNativeHeld(n),
42828
+ note: verdict.mark === "insufficient" ? "not enough to cover the network fee" : null
42829
+ };
42830
+ }
42831
+ if (ok === false) return { ...row, mark: "unchecked", balanceUsd: null, note: null };
42376
42832
  const hit = index2.get(`${row.chainId}:${row.tokenSymbol}`);
42377
42833
  if (!hit) {
42378
42834
  return { ...row, mark: "insufficient", balanceUsd: 0, note: "no balance found" };
@@ -42384,7 +42840,7 @@ function markPickerOptions(pickerOptions, { family = null, options = [] } = {})
42384
42840
  note: hit.disabledReason
42385
42841
  };
42386
42842
  });
42387
- const rank = { affordable: 0, unchecked: 1, insufficient: 2 };
42843
+ const rank = { affordable: 0, held: 1, unchecked: 2, insufficient: 3 };
42388
42844
  return marked.map((row, i) => ({ row, i })).sort((a, b) => rank[a.row.mark] - rank[b.row.mark] || a.i - b.i).map(({ row }) => row);
42389
42845
  }
42390
42846
  async function fetchWalletOptions({ address, usdRequired, timeoutMs = BALANCE_TIMEOUT_MS }) {
@@ -42563,6 +43019,8 @@ function createOrderRecordUnlocked(record) {
42563
43019
  amount: record.amount,
42564
43020
  amountUnit: record.amountUnit ?? null,
42565
43021
  expiresAt: record.expiresAt ?? null,
43022
+ // Native coin orders only: the price lock the backend reported at create.
43023
+ quoteExpiresAt: record.quoteExpiresAt ?? existing?.quoteExpiresAt ?? null,
42566
43024
  createdAt: existing?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
42567
43025
  updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
42568
43026
  confirmation: existing?.confirmation ?? null,
@@ -42584,7 +43042,7 @@ function depositDigest(source) {
42584
43042
  });
42585
43043
  return crypto2.createHash("sha256").update(canonical, "utf8").digest("hex");
42586
43044
  }
42587
- function recordConfirmation(rozoPaymentId, { source, invoiceAmount, tier }) {
43045
+ function recordConfirmation(rozoPaymentId, { source, invoiceAmount, tier, quoteExpiresAt = null }) {
42588
43046
  return withLock(() => {
42589
43047
  const state = readState(rozoPaymentId);
42590
43048
  if (!state) {
@@ -42597,7 +43055,10 @@ function recordConfirmation(rozoPaymentId, { source, invoiceAmount, tier }) {
42597
43055
  confirmedAt: (/* @__PURE__ */ new Date()).toISOString(),
42598
43056
  depositDigest: depositDigest(source),
42599
43057
  invoiceAmount: invoiceAmount ?? state.invoiceAmount ?? null,
42600
- tier: tier ?? null
43058
+ tier: tier ?? null,
43059
+ // The native price lock the human was shown. A send never goes out
43060
+ // after it, even if the backend later reports a later one.
43061
+ quoteExpiresAt: quoteExpiresAt ?? null
42601
43062
  }
42602
43063
  };
42603
43064
  writeAtomic(statePath(rozoPaymentId), next);
@@ -42629,6 +43090,7 @@ function claimSend(rozoPaymentId, intent, { skipCaps = false } = {}) {
42629
43090
  claimedAt: (/* @__PURE__ */ new Date()).toISOString(),
42630
43091
  chainId: intent.chainId,
42631
43092
  tokenSymbol: intent.tokenSymbol,
43093
+ native: Boolean(intent.native),
42632
43094
  from: intent.from,
42633
43095
  to: intent.to,
42634
43096
  amountAtomic: intent.amountAtomic,
@@ -42914,6 +43376,7 @@ var MARGINS_MS = {
42914
43376
  56: 10 * MINUTE,
42915
43377
  137: 10 * MINUTE,
42916
43378
  8453: 10 * MINUTE,
43379
+ 42161: 10 * MINUTE,
42917
43380
  900: 5 * MINUTE,
42918
43381
  1500: 10 * MINUTE,
42919
43382
  lightning: 10 * MINUTE
@@ -42931,8 +43394,10 @@ function lightningWatchMs(expiresAt, { now = Date.now(), fallbackMs = DEFAULT_WA
42931
43394
  }
42932
43395
  function settlementWatchSeconds(opts, deposit, now = Date.now()) {
42933
43396
  const fallbackMs = Number(opts.timeout ?? 900) * 1e3;
42934
- if (opts.timeoutExplicit || !deposit?.lnInvoice) return Math.round(fallbackMs / 1e3);
42935
- return Math.ceil(lightningWatchMs(deposit.expiresAt, { now, fallbackMs }) / 1e3);
43397
+ if (opts.timeoutExplicit) return Math.round(fallbackMs / 1e3);
43398
+ const until = deposit?.lnInvoice ? deposit.expiresAt : deposit?.quoteExpiresAt;
43399
+ if (!until) return Math.round(fallbackMs / 1e3);
43400
+ return Math.ceil(lightningWatchMs(until, { now, fallbackMs }) / 1e3);
42936
43401
  }
42937
43402
  function minutesRemaining(expiresAt, now = Date.now()) {
42938
43403
  const at = parseDeadline(expiresAt);
@@ -42986,13 +43451,16 @@ function checkExpiry({
42986
43451
  chainId,
42987
43452
  intentExpiresAt,
42988
43453
  coinbaseExpiry,
42989
- bolt11ExpiresAt = void 0
43454
+ bolt11ExpiresAt = void 0,
43455
+ quoteExpiresAt = void 0
42990
43456
  }) {
42991
43457
  const marginMs = marginFor(chainId);
42992
43458
  const intentMs = parseDeadline(intentExpiresAt);
42993
43459
  const coinbaseMs = parseDeadline(coinbaseExpiry);
42994
43460
  const bolt11Ms = bolt11ExpiresAt === void 0 ? void 0 : parseDeadline(bolt11ExpiresAt);
42995
- const deadlines = { intentMs, coinbaseMs, bolt11Ms: bolt11Ms ?? null };
43461
+ const native = quoteExpiresAt !== void 0;
43462
+ const quoteMs = native ? parseDeadline(quoteExpiresAt) : null;
43463
+ const deadlines = { intentMs, coinbaseMs, bolt11Ms: bolt11Ms ?? null, quoteMs };
42996
43464
  const base = {
42997
43465
  marginMs,
42998
43466
  effectiveDeadlineMs: null,
@@ -43016,7 +43484,16 @@ function checkExpiry({
43016
43484
  reason: "Coinbase preApprovalExpiry is missing or unparsable."
43017
43485
  };
43018
43486
  }
43019
- const effective = Math.min(intentMs, coinbaseMs);
43487
+ if (native && quoteMs === null) {
43488
+ return {
43489
+ ...base,
43490
+ ok: false,
43491
+ code: "EXPIRY_UNPARSABLE",
43492
+ reason: "This native coin order carries no price lock (quoteExpiresAt), so the coin amount cannot be trusted to be honoured. Refusing to treat it as payable."
43493
+ };
43494
+ }
43495
+ const effective = native ? Math.min(intentMs, coinbaseMs, quoteMs) : Math.min(intentMs, coinbaseMs);
43496
+ const lockBinds = native && quoteMs <= Math.min(intentMs, coinbaseMs);
43020
43497
  const msRemaining = effective - now;
43021
43498
  const msOfSlack = msRemaining - marginMs;
43022
43499
  const withDeadline = {
@@ -43029,16 +43506,16 @@ function checkExpiry({
43029
43506
  return {
43030
43507
  ...withDeadline,
43031
43508
  ok: false,
43032
- code: "EXPIRED",
43033
- reason: "The order or the Coinbase link has already expired."
43509
+ code: lockBinds ? "QUOTE_EXPIRED" : "EXPIRED",
43510
+ reason: lockBinds ? "The coin price for this order was locked until quoteExpiresAt, and that has passed. A payment now would be valued at the price when it arrives and may fall short. Do not send it; let the order expire unfunded and start a new one." : "The order or the Coinbase link has already expired."
43034
43511
  };
43035
43512
  }
43036
43513
  if (msOfSlack <= 0) {
43037
43514
  return {
43038
43515
  ...withDeadline,
43039
43516
  ok: false,
43040
- code: "EXPIRY_MARGIN",
43041
- reason: `Only ${Math.floor(msRemaining / 1e3)}s left before the earliest deadline; this chain needs a ${Math.floor(marginMs / 6e4)} min safety margin.`
43517
+ code: lockBinds ? "QUOTE_EXPIRY_MARGIN" : "EXPIRY_MARGIN",
43518
+ reason: `Only ${Math.floor(msRemaining / 1e3)}s left before the earliest deadline${lockBinds ? " (the coin price lock)" : ""}; this chain needs a ${Math.floor(marginMs / 6e4)} min safety margin.`
43042
43519
  };
43043
43520
  }
43044
43521
  if (bolt11ExpiresAt !== void 0) {
@@ -43062,6 +43539,12 @@ function checkExpiry({
43062
43539
  }
43063
43540
  return { ...withDeadline, ok: true, code: null, reason: null };
43064
43541
  }
43542
+ function priceLockFor({ native, payment = null, others = [] }) {
43543
+ if (!native) return void 0;
43544
+ const candidates = [payment?.quoteExpiresAt, payment?.source?.quoteExpiresAt, ...others].map(parseDeadline).filter((ms) => ms !== null);
43545
+ if (!candidates.length) return null;
43546
+ return new Date(Math.min(...candidates)).toISOString();
43547
+ }
43065
43548
 
43066
43549
  // scripts/src/lib/key-source.mjs
43067
43550
  import fs6 from "node:fs";
@@ -43248,7 +43731,7 @@ async function recoverPublicKey({ hash: hash3, signature }) {
43248
43731
  const { r, s, v, yParity } = signature;
43249
43732
  const yParityOrV2 = Number(yParity ?? v);
43250
43733
  const recoveryBit2 = toRecoveryBit(yParityOrV2);
43251
- return new secp256k13.Signature(hexToBigInt(r), hexToBigInt(s)).addRecoveryBit(recoveryBit2);
43734
+ return new secp256k13.Signature(hexToBigInt2(r), hexToBigInt2(s)).addRecoveryBit(recoveryBit2);
43252
43735
  }
43253
43736
  const signatureHex = isHex(signature) ? signature : toHex(signature);
43254
43737
  if (size(signatureHex) !== 65)
@@ -43661,7 +44144,7 @@ async function internal_estimateMaxPriorityFeePerGas(client, args) {
43661
44144
  const maxPriorityFeePerGasHex = await client.request({
43662
44145
  method: "eth_maxPriorityFeePerGas"
43663
44146
  });
43664
- return hexToBigInt(maxPriorityFeePerGasHex);
44147
+ return hexToBigInt2(maxPriorityFeePerGasHex);
43665
44148
  } catch {
43666
44149
  const [block, gasPrice] = await Promise.all([
43667
44150
  block_ ? Promise.resolve(block_) : getAction(client, getBlock, "getBlock")({}),
@@ -45588,7 +46071,7 @@ async function sendCalls(client, parameters) {
45588
46071
  chain,
45589
46072
  data: call2.data,
45590
46073
  to: call2.to,
45591
- value: call2.value ? hexToBigInt(call2.value) : void 0
46074
+ value: call2.value ? hexToBigInt2(call2.value) : void 0
45592
46075
  });
45593
46076
  results.push({ status: "fulfilled", value });
45594
46077
  } catch (reason) {
@@ -45675,8 +46158,8 @@ async function getCallsStatus(client, parameters) {
45675
46158
  chainId: chainId ? hexToNumber(chainId) : void 0,
45676
46159
  receipts: receipts?.map((receipt) => ({
45677
46160
  ...receipt,
45678
- blockNumber: hexToBigInt(receipt.blockNumber),
45679
- gasUsed: hexToBigInt(receipt.gasUsed),
46161
+ blockNumber: hexToBigInt2(receipt.blockNumber),
46162
+ gasUsed: hexToBigInt2(receipt.gasUsed),
45680
46163
  status: receiptStatuses[receipt.status]
45681
46164
  })) ?? [],
45682
46165
  statusCode,
@@ -51885,10 +52368,10 @@ async function simulateCalls(client, parameters) {
51885
52368
  const results = block_calls.slice(0, -1) ?? [];
51886
52369
  const ethPre = block_ethPre?.calls ?? [];
51887
52370
  const assetsPre = block_assetsPre?.calls ?? [];
51888
- const balancesPre = [...ethPre, ...assetsPre].map((call2) => call2.status === "success" ? hexToBigInt(call2.data) : null);
52371
+ const balancesPre = [...ethPre, ...assetsPre].map((call2) => call2.status === "success" ? hexToBigInt2(call2.data) : null);
51889
52372
  const ethPost = block_ethPost?.calls ?? [];
51890
52373
  const assetsPost = block_assetsPost?.calls ?? [];
51891
- const balancesPost = [...ethPost, ...assetsPost].map((call2) => call2.status === "success" ? hexToBigInt(call2.data) : null);
52374
+ const balancesPost = [...ethPost, ...assetsPost].map((call2) => call2.status === "success" ? hexToBigInt2(call2.data) : null);
51892
52375
  const decimals = (block_decimals?.calls ?? []).map((x) => x.status === "success" ? x.result : null);
51893
52376
  const symbols = (block_symbols?.calls ?? []).map((x) => x.status === "success" ? x.result : null);
51894
52377
  const tokenURI = (block_tokenURI?.calls ?? []).map((x) => x.status === "success" ? x.result : null);
@@ -52061,7 +52544,7 @@ function serializeSignature({ r, s, to = "hex", v, yParity }) {
52061
52544
  return v % 2n === 0n ? 1 : 0;
52062
52545
  throw new Error("Invalid `v` or `yParity` value");
52063
52546
  })();
52064
- const signature = `0x${new secp256k1.Signature(hexToBigInt(r), hexToBigInt(s)).toCompactHex()}${yParity_ === 0 ? "1b" : "1c"}`;
52547
+ const signature = `0x${new secp256k1.Signature(hexToBigInt2(r), hexToBigInt2(s)).toCompactHex()}${yParity_ === 0 ? "1b" : "1c"}`;
52065
52548
  if (to === "hex")
52066
52549
  return signature;
52067
52550
  return hexToBytes(signature);
@@ -52346,7 +52829,7 @@ function watchBlockNumber(client, { emitOnBegin = false, emitMissed = false, onB
52346
52829
  onData(data) {
52347
52830
  if (!active)
52348
52831
  return;
52349
- const blockNumber = hexToBigInt(data.result?.number);
52832
+ const blockNumber = hexToBigInt2(data.result?.number);
52350
52833
  emit2.onBlockNumber(blockNumber, prevBlockNumber);
52351
52834
  prevBlockNumber = blockNumber;
52352
52835
  },
@@ -54911,6 +55394,13 @@ function snapshotFromQuote(quote) {
54911
55394
 
54912
55395
  // scripts/src/lib/guards.mjs
54913
55396
  var UNPAID_STATUS = "payment_unpaid";
55397
+ var NATIVE_PROGRESS_STATUSES = /* @__PURE__ */ new Set([
55398
+ "payment_payin_completed",
55399
+ "payment_bridging",
55400
+ "payment_payout_started",
55401
+ "payment_payout_completed",
55402
+ "payment_completed"
55403
+ ]);
54914
55404
  function receiptSignal(source) {
54915
55405
  const raw = source?.amountReceived;
54916
55406
  if (raw === null || raw === void 0 || raw === "") {
@@ -55238,7 +55728,8 @@ function classifyStatus({
55238
55728
  if (!bitrefill && (routerStatus === "paid" || coinbase?.settled === true)) {
55239
55729
  return mk("settled", "Coinbase invoice settled by the funder wallet.", { terminal: true });
55240
55730
  }
55241
- if (moneyDetected && receipt && receipt.state === "underpaid") {
55731
+ const nativeAccepted = isNativeSource(source.chainId, source.tokenSymbol) && NATIVE_PROGRESS_STATUSES.has(payment?.status);
55732
+ if (moneyDetected && receipt && receipt.state === "underpaid" && !nativeAccepted) {
55242
55733
  return mk(
55243
55734
  "underpaid",
55244
55735
  "Less arrived than the order requires. Do NOT send a top-up to the same address \u2014 escalate.",
@@ -55379,6 +55870,24 @@ async function main(argv) {
55379
55870
  const quote = await quoteInvoice({ url: String(url) });
55380
55871
  const snapshot2 = snapshotFromQuote(quote);
55381
55872
  const payability = derivePayable(snapshot2, now);
55873
+ const nativeOffered = Object.values(NATIVE_COINS).map((c2) => ({
55874
+ chainId: c2.chainId,
55875
+ tokenSymbol: c2.symbol,
55876
+ chain: chainName(c2.chainId),
55877
+ offer: nativeOfferFor({
55878
+ chainId: c2.chainId,
55879
+ tokenSymbol: c2.symbol,
55880
+ supportedSources: quote?.supportedSources,
55881
+ nativeMinUsd: quote?.nativeMinUsd,
55882
+ callerPaysUsd: snapshot2.callerPays ?? snapshot2.original
55883
+ })
55884
+ })).filter((c2) => c2.offer.ok).map((c2) => ({ chainId: c2.chainId, tokenSymbol: c2.tokenSymbol, chain: c2.chain, minUsd: c2.offer.minUsd }));
55885
+ const nativeRequested = chosenSource && isNativeSource(chosenSource.chainId, chosenSource.tokenSymbol) ? nativeOfferFor({
55886
+ ...chosenSource,
55887
+ supportedSources: quote?.supportedSources,
55888
+ nativeMinUsd: quote?.nativeMinUsd,
55889
+ callerPaysUsd: snapshot2.callerPays ?? snapshot2.original
55890
+ }) : null;
55382
55891
  const payload = {
55383
55892
  success: payability.payable,
55384
55893
  step: "quote",
@@ -55397,6 +55906,11 @@ async function main(argv) {
55397
55906
  coinbaseExpiryIso: payability.expiryMs ? new Date(payability.expiryMs).toISOString() : null,
55398
55907
  chosenSource,
55399
55908
  supportedSources: SUPPORTED_SOURCES,
55909
+ // The router's own per-invoice list ({ chainId: [symbols] }), verbatim,
55910
+ // and the native coins it makes payable for this invoice.
55911
+ routerSupportedSources: quote?.supportedSources && typeof quote.supportedSources === "object" ? quote.supportedSources : null,
55912
+ nativeOffered,
55913
+ nativeNote: "Native coins are exact-out: the coin amount is fixed at order creation and its price is locked only until quoteExpiresAt. Up to $2,000 per invoice; native ETH on Ethereum needs $1.",
55400
55914
  quoteReceipt: quote?.quoteReceipt ?? null,
55401
55915
  quoteReceiptTtlSeconds: 60,
55402
55916
  quoteReceiptNote: "Short-lived (~60s). create-order.js takes its own fresh quote; do not carry this over.",
@@ -55407,6 +55921,12 @@ async function main(argv) {
55407
55921
  payload.error = { code: payability.code, message: payability.reason };
55408
55922
  emit(payload, EXIT_ERROR);
55409
55923
  }
55924
+ if (nativeRequested && !nativeRequested.ok) {
55925
+ payload.success = false;
55926
+ payload.nextStep = null;
55927
+ payload.error = { code: nativeRequested.code, message: nativeRequested.reason };
55928
+ emit(payload, EXIT_ERROR);
55929
+ }
55410
55930
  if (snapshot2.callerPays && snapshot2.original && normalizeDecimal(snapshot2.callerPays) !== normalizeDecimal(snapshot2.original)) {
55411
55931
  payload.warnings = [
55412
55932
  `callerPays (${snapshot2.callerPays}) differs from the invoice amount (${snapshot2.original}). This flow is supposed to charge the full invoice \u2014 do not proceed until that is explained.`
@@ -55458,6 +55978,28 @@ async function main2(argv) {
55458
55978
  const quote = await quoteInvoice({ url: String(url) });
55459
55979
  const snapshot2 = snapshotFromQuote(quote);
55460
55980
  const quoteReceipt = quote?.quoteReceipt ?? null;
55981
+ const native = isNativeSource(chainId, tokenSymbol);
55982
+ if (native) {
55983
+ const offer = nativeOfferFor({
55984
+ chainId,
55985
+ tokenSymbol,
55986
+ supportedSources: quote?.supportedSources,
55987
+ nativeMinUsd: quote?.nativeMinUsd,
55988
+ callerPaysUsd: snapshot2.callerPays ?? snapshot2.original
55989
+ });
55990
+ if (!offer.ok) {
55991
+ emit(
55992
+ {
55993
+ success: false,
55994
+ step: "native-offer",
55995
+ error: { code: offer.code, message: offer.reason },
55996
+ linkId: snapshot2.linkId ?? parsedLinkId,
55997
+ guidance: "Nothing was created. Choose USDC or USDT, or another coin the quote lists."
55998
+ },
55999
+ EXIT_ERROR
56000
+ );
56001
+ }
56002
+ }
55461
56003
  const created = await createInvoice({
55462
56004
  url: String(url),
55463
56005
  source: requested,
@@ -55544,6 +56086,17 @@ async function main2(argv) {
55544
56086
  }
55545
56087
  const lightning = String(source.chainId) === "lightning";
55546
56088
  const bolt11 = source.lnInvoice ?? payment?.lnInvoice ?? null;
56089
+ let prior = null;
56090
+ try {
56091
+ prior = native ? readState(rozoPaymentId) : null;
56092
+ } catch {
56093
+ prior = null;
56094
+ }
56095
+ const quoteExpiresAt = priceLockFor({
56096
+ native,
56097
+ payment,
56098
+ others: [created?.quoteExpiresAt, prior?.quoteExpiresAt, prior?.confirmation?.quoteExpiresAt]
56099
+ });
55547
56100
  const expiry = checkExpiry({
55548
56101
  now: Date.now(),
55549
56102
  chainId: source.chainId ?? chainId,
@@ -55552,7 +56105,8 @@ async function main2(argv) {
55552
56105
  // For Lightning the BOLT11's own validity is an extra gate. We only have a
55553
56106
  // separate expiry if the backend exposes one; otherwise the intent expiry
55554
56107
  // governs and we still require the 10-minute floor via the margin.
55555
- ...lightning ? { bolt11ExpiresAt: payment?.expiresAt } : {}
56108
+ ...lightning ? { bolt11ExpiresAt: payment?.expiresAt } : {},
56109
+ ...native ? { quoteExpiresAt } : {}
55556
56110
  });
55557
56111
  if (!expiry.ok) {
55558
56112
  emit(
@@ -55562,7 +56116,7 @@ async function main2(argv) {
55562
56116
  error: { code: expiry.code, message: expiry.reason, details: expiry },
55563
56117
  linkId: created.linkId ?? parsedLinkId,
55564
56118
  rozoPaymentId,
55565
- guidance: "Not enough time remains to fund, bridge and settle safely. Ask the merchant for a fresh link and start over. Do not fund this order."
56119
+ guidance: String(expiry.code).startsWith("QUOTE_") ? "The coin price lock for this order has run out, or is about to. Do not fund it. An unfunded order costs nothing; once it has expired, run pay again for a fresh price." : "Not enough time remains to fund, bridge and settle safely. Ask the merchant for a fresh link and start over. Do not fund this order."
55566
56120
  },
55567
56121
  EXIT_ERROR
55568
56122
  );
@@ -55617,14 +56171,20 @@ async function main2(argv) {
55617
56171
  receiverMemo: source.receiverMemo ?? null,
55618
56172
  amount: source.amount,
55619
56173
  amountUnit: source.amountUnit ?? null,
55620
- expiresAt: payment?.expiresAt ?? null
56174
+ expiresAt: payment?.expiresAt ?? null,
56175
+ ...native ? { quoteExpiresAt } : {}
55621
56176
  });
55622
56177
  const usd = created.original ?? snapshot2.original;
55623
56178
  const family = chainFamily(source.chainId);
55624
56179
  const tier = confirmTier(usd);
55625
56180
  const depositInfo = guard.deposit;
55626
56181
  if (confirmed) {
55627
- recordConfirmation(rozoPaymentId, { source, invoiceAmount: usd, tier });
56182
+ recordConfirmation(rozoPaymentId, {
56183
+ source,
56184
+ invoiceAmount: usd,
56185
+ tier,
56186
+ ...native ? { quoteExpiresAt } : {}
56187
+ });
55628
56188
  }
55629
56189
  const memoRequirement = lightning ? "Lightning invoices carry their own routing data; there is no separate memo." : source.receiverMemo ? "This deposit REQUIRES the memo/tag below. Sending without it will very likely lose the funds." : family === "stellar" ? "A Stellar deposit always requires a memo." : "This deposit does not use a memo. Leave the memo field empty.";
55630
56190
  emit({
@@ -55667,7 +56227,12 @@ async function main2(argv) {
55667
56227
  lnInvoice: bolt11 || null,
55668
56228
  payTo: depositInfo.payTo,
55669
56229
  expiresAt: payment?.expiresAt ?? null,
55670
- expiresIn: formatRemaining(expiry.msRemaining)
56230
+ expiresIn: formatRemaining(expiry.msRemaining),
56231
+ // Native coins are exact-out like Lightning: this exact coin amount,
56232
+ // at a price locked only until quoteExpiresAt.
56233
+ native,
56234
+ exactOut: native || lightning,
56235
+ quoteExpiresAt: native ? quoteExpiresAt : null
55671
56236
  } : null,
55672
56237
  depositWithheld: !confirmed,
55673
56238
  // Safe for prose / chat.
@@ -55680,11 +56245,16 @@ async function main2(argv) {
55680
56245
  receiverMemoMasked: maskMemo(source.receiverMemo),
55681
56246
  hasMemo: Boolean(source.receiverMemo),
55682
56247
  memoType: source.receiverMemo ? STELLAR_MEMO_TYPE : null,
55683
- memoRequirement
56248
+ memoRequirement,
56249
+ native,
56250
+ priceLockedUntil: native ? quoteExpiresAt : null,
56251
+ // The bare decimal amount (not secret), for balance comparisons.
56252
+ coinAmount: isSatsUnit(source.amountUnit) ? null : String(source.amount ?? "")
55684
56253
  },
55685
56254
  expiry: {
55686
56255
  intentExpiresAt: payment?.expiresAt ?? null,
55687
56256
  coinbaseExpiry: snapshot2?.coinbase?.preApprovalExpiry ?? null,
56257
+ quoteExpiresAt: native ? quoteExpiresAt : null,
55688
56258
  effectiveDeadlineIso: new Date(expiry.effectiveDeadlineMs).toISOString(),
55689
56259
  // A duration, not just a timestamp: this is what a payer actually needs.
55690
56260
  expiresIn: formatRemaining(expiry.msRemaining),
@@ -55700,7 +56270,8 @@ async function main2(argv) {
55700
56270
  "Wrong token, wrong network, or wrong amount is usually unrecoverable.",
55701
56271
  memoRequirement,
55702
56272
  "Send exactly once. A second send to the same one-time address is not guaranteed to be credited.",
55703
- "The deposit amount can exceed the invoice: it includes the bridge and network fees."
56273
+ "The deposit amount can exceed the invoice: it includes the bridge and network fees.",
56274
+ ...native ? nativeDepositWarnings({ tokenSymbol: source.tokenSymbol, chainId: source.chainId }) : []
55704
56275
  ]
55705
56276
  },
55706
56277
  blacklist: {
@@ -55910,6 +56481,12 @@ async function main3(argv) {
55910
56481
  supported: SUPPORTED_SOURCES
55911
56482
  });
55912
56483
  }
56484
+ if (isNativeSource(chainId, tokenSymbol)) {
56485
+ throw new SkillError(
56486
+ "NATIVE_NOT_AVAILABLE",
56487
+ `${tokenSymbol} on ${chainName(chainId)} is a native coin, and native coins are not available for Bitrefill invoices. Pay with USDC, USDT or BTC over Lightning.`
56488
+ );
56489
+ }
55913
56490
  const requested = { chainId, tokenSymbol };
55914
56491
  const confirmed = Boolean(args.confirm);
55915
56492
  const email = contactEmailFromArgs(args);
@@ -56380,7 +56957,7 @@ function localSendFor(id, read = readState) {
56380
56957
  if (!send || !send.status) return null;
56381
56958
  return { status: send.status, txHash: publicHash(send.txHash ?? null), claimedAt: send.claimedAt ?? null };
56382
56959
  }
56383
- function sendWindowFor({ provider, chainId, payment, status, bitrefillExpiry, now = Date.now() }) {
56960
+ function sendWindowFor({ provider, chainId, payment, status, bitrefillExpiry, quoteExpiresAt, now = Date.now() }) {
56384
56961
  if (provider === "bitrefill") {
56385
56962
  const deadline = bitrefillExpiry ?? null;
56386
56963
  const expiry2 = checkExpiry({
@@ -56400,7 +56977,9 @@ function sendWindowFor({ provider, chainId, payment, status, bitrefillExpiry, no
56400
56977
  now,
56401
56978
  chainId,
56402
56979
  intentExpiresAt: payment?.expiresAt ?? status?.rozoPayment?.expiresAt,
56403
- coinbaseExpiry: status?.coinbase?.preApprovalExpiry
56980
+ coinbaseExpiry: status?.coinbase?.preApprovalExpiry,
56981
+ // Native orders: the price lock is a deadline too (undefined otherwise).
56982
+ ...quoteExpiresAt !== void 0 ? { quoteExpiresAt } : {}
56404
56983
  });
56405
56984
  return expiry.ok ? { ok: true, code: null, minutesOfSlack: Math.floor(expiry.msOfSlack / 6e4), deadlineMs: expiry.effectiveDeadlineMs } : { ok: false, code: expiry.code, reason: expiry.reason };
56406
56985
  }
@@ -56454,6 +57033,18 @@ async function snapshot({ rozoPaymentId, linkId, provider: explicitProvider }) {
56454
57033
  provider
56455
57034
  });
56456
57035
  const source = payment?.source || status?.rozoPayment?.source || {};
57036
+ const native = isNativeSource(source.chainId, source.tokenSymbol);
57037
+ let localState = null;
57038
+ try {
57039
+ localState = id && isRozoPaymentId(id) ? readState(id) : null;
57040
+ } catch {
57041
+ localState = null;
57042
+ }
57043
+ const quoteExpiresAt = priceLockFor({
57044
+ native,
57045
+ payment: payment || status?.rozoPayment || null,
57046
+ others: [localState?.confirmation?.quoteExpiresAt, localState?.quoteExpiresAt]
57047
+ });
56457
57048
  let bitrefillExpiry = null;
56458
57049
  let state = verdict.state;
56459
57050
  let terminal = verdict.terminal;
@@ -56513,10 +57104,17 @@ async function snapshot({ rozoPaymentId, linkId, provider: explicitProvider }) {
56513
57104
  const iso = provider === "bitrefill" ? bitrefillExpiry : payment?.expiresAt ?? status?.rozoPayment?.expiresAt ?? null;
56514
57105
  if (!iso) return { expiresAt: null, expiresIn: null, msRemaining: null };
56515
57106
  const ms = Date.parse(iso) - Date.now();
57107
+ const lockMs = quoteExpiresAt ? Date.parse(quoteExpiresAt) - Date.now() : NaN;
56516
57108
  return {
56517
57109
  expiresAt: iso,
56518
57110
  expiresIn: formatRemaining(ms),
56519
- msRemaining: Number.isFinite(ms) ? ms : null
57111
+ msRemaining: Number.isFinite(ms) ? ms : null,
57112
+ // Native orders: the order stays open after the price lock, but a
57113
+ // payment after it is valued at the arrival price. Pay before this.
57114
+ ...native ? {
57115
+ quoteExpiresAt: quoteExpiresAt ?? null,
57116
+ priceLockExpiresIn: Number.isFinite(lockMs) ? formatRemaining(lockMs) : null
57117
+ } : {}
56520
57118
  };
56521
57119
  })(),
56522
57120
  payout: {
@@ -56524,7 +57122,7 @@ async function snapshot({ rozoPaymentId, linkId, provider: explicitProvider }) {
56524
57122
  confirmedAt: payment?.destination?.confirmedAt ?? status?.rozoPayment?.destination?.confirmedAt ?? null
56525
57123
  },
56526
57124
  localSend: localSendFor(id),
56527
- sendWindow: state === "awaiting_deposit" ? sendWindowFor({ provider, chainId: source.chainId, payment, status, bitrefillExpiry }) : null,
57125
+ sendWindow: state === "awaiting_deposit" ? sendWindowFor({ provider, chainId: source.chainId, payment, status, bitrefillExpiry, quoteExpiresAt }) : null,
56528
57126
  errors: [statusError, paymentError].filter(Boolean)
56529
57127
  };
56530
57128
  }
@@ -56553,6 +57151,9 @@ function watchTimeoutMs(timeoutArg, result, now = Date.now()) {
56553
57151
  if (result?.payin?.chain === chainName("lightning")) {
56554
57152
  return lightningWatchMs(result?.expiry?.expiresAt, { now, fallbackMs: DEFAULT_WATCH_MS });
56555
57153
  }
57154
+ if (result?.expiry?.quoteExpiresAt) {
57155
+ return lightningWatchMs(result.expiry.quoteExpiresAt, { now, fallbackMs: DEFAULT_WATCH_MS });
57156
+ }
56556
57157
  return DEFAULT_WATCH_MS;
56557
57158
  }
56558
57159
  async function main4(argv) {
@@ -56779,11 +57380,14 @@ async function main6(argv) {
56779
57380
  EXIT_ERROR
56780
57381
  );
56781
57382
  }
57383
+ const native = isNativeSource(source.chainId, source.tokenSymbol);
57384
+ const quoteExpiresAt = priceLockFor({ native, payment, others: [snap.expiry?.quoteExpiresAt] });
56782
57385
  const finalWindow = checkExpiry({
56783
57386
  now: Date.now(),
56784
57387
  chainId: source.chainId,
56785
57388
  intentExpiresAt: payment?.expiresAt ?? snap.sendWindow?.deadlineMs,
56786
- coinbaseExpiry: snap.sendWindow?.deadlineMs
57389
+ coinbaseExpiry: snap.sendWindow?.deadlineMs,
57390
+ ...native ? { quoteExpiresAt } : {}
56787
57391
  });
56788
57392
  if (!finalWindow.ok) {
56789
57393
  emit(
@@ -56824,7 +57428,7 @@ async function main6(argv) {
56824
57428
  }
56825
57429
  }
56826
57430
  const expiresAt = payment?.expiresAt ?? snap.expiry?.expiresAt ?? null;
56827
- const msRemaining = expiresAt ? Date.parse(expiresAt) - Date.now() : NaN;
57431
+ const msRemaining = Number.isFinite(finalWindow.effectiveDeadlineMs) ? finalWindow.effectiveDeadlineMs - Date.now() : NaN;
56828
57432
  const expiresIn = Number.isFinite(msRemaining) ? formatRemaining(msRemaining) : null;
56829
57433
  const paymentLink = payment?.paymentLink ?? localPaymentLink(id);
56830
57434
  const bolt11 = source.lnInvoice ?? payment?.lnInvoice ?? null;
@@ -56856,7 +57460,10 @@ async function main6(argv) {
56856
57460
  lnInvoice: bolt11 || null,
56857
57461
  payTo: guard.deposit.payTo,
56858
57462
  expiresAt,
56859
- expiresIn
57463
+ expiresIn,
57464
+ native,
57465
+ exactOut: native || lightning,
57466
+ quoteExpiresAt: native ? quoteExpiresAt : null
56860
57467
  } : null,
56861
57468
  depositWithheld: !confirmed,
56862
57469
  display: {
@@ -56867,9 +57474,16 @@ async function main6(argv) {
56867
57474
  payToMasked: maskAddress2(guard.deposit.payTo),
56868
57475
  receiverMemoMasked: maskMemo(source.receiverMemo),
56869
57476
  hasMemo: Boolean(source.receiverMemo),
56870
- memoType: source.receiverMemo ? STELLAR_MEMO_TYPE : null
57477
+ memoType: source.receiverMemo ? STELLAR_MEMO_TYPE : null,
57478
+ native,
57479
+ priceLockedUntil: native ? quoteExpiresAt : null
57480
+ },
57481
+ expiry: {
57482
+ expiresAt,
57483
+ expiresIn,
57484
+ ...native ? { quoteExpiresAt } : {},
57485
+ minutesOfSlack: snap.sendWindow?.minutesOfSlack ?? null
56871
57486
  },
56872
- expiry: { expiresAt, expiresIn, minutesOfSlack: snap.sendWindow?.minutesOfSlack ?? null },
56873
57487
  note: confirmed ? "Send exactly once, exactly this amount, on this chain. Then: rozo-checkout status <id> --watch" : "Deposit address withheld. Confirm the chain, token and amount with the payer, then re-run with --confirm, or open paymentLink."
56874
57488
  });
56875
57489
  }
@@ -56934,6 +57548,14 @@ function assertBitrefillLive(state, payment) {
56934
57548
  if (!expiry.ok) throw new SkillError(expiry.code, expiry.reason, expiry);
56935
57549
  return expiry;
56936
57550
  }
57551
+ function sendPriceLock(payment, state) {
57552
+ const source = payment?.source || {};
57553
+ return priceLockFor({
57554
+ native: isNativeSource(source.chainId, source.tokenSymbol),
57555
+ payment,
57556
+ others: [state?.confirmation?.quoteExpiresAt, state?.quoteExpiresAt]
57557
+ });
57558
+ }
56937
57559
  async function preflight({
56938
57560
  rozoPaymentId,
56939
57561
  expectFamily,
@@ -57022,14 +57644,19 @@ async function preflight({
57022
57644
  let statusNow = null;
57023
57645
  let expiry;
57024
57646
  if (state.provider === "bitrefill") {
57647
+ if (isNativeSource(source.chainId, source.tokenSymbol)) {
57648
+ throw new SkillError("NATIVE_NOT_AVAILABLE", "Native coins are not available for Bitrefill invoices.");
57649
+ }
57025
57650
  expiry = assertBitrefillLive(state, payment);
57026
57651
  } else {
57027
57652
  statusNow = await invoiceStatus({ linkId: state.linkId });
57653
+ const quoteExpiresAt = sendPriceLock(payment, state);
57028
57654
  expiry = checkExpiry({
57029
57655
  now: Date.now(),
57030
57656
  chainId: source.chainId,
57031
57657
  intentExpiresAt: payment?.expiresAt,
57032
- coinbaseExpiry: statusNow?.coinbase?.preApprovalExpiry
57658
+ coinbaseExpiry: statusNow?.coinbase?.preApprovalExpiry,
57659
+ ...quoteExpiresAt !== void 0 ? { quoteExpiresAt } : {}
57033
57660
  });
57034
57661
  if (!expiry.ok) throw new SkillError(expiry.code, expiry.reason, expiry);
57035
57662
  const payable = checkPayable(statusNow, Date.now());
@@ -57050,11 +57677,22 @@ async function preflight({
57050
57677
  blacklist,
57051
57678
  amountAtomic: deposit.amountAtomic,
57052
57679
  deposit,
57053
- statusNow
57680
+ statusNow,
57681
+ quoteExpiresAt: sendPriceLock(payment, state)
57054
57682
  };
57055
57683
  }
57056
- async function finalPayabilityCheck({ linkId, chainId, intentExpiresAt, state = null, rozoPaymentId = null }) {
57684
+ async function finalPayabilityCheck({
57685
+ linkId,
57686
+ chainId,
57687
+ intentExpiresAt,
57688
+ quoteExpiresAt = void 0,
57689
+ state = null,
57690
+ rozoPaymentId = null
57691
+ }) {
57057
57692
  if (state?.provider === "bitrefill") {
57693
+ if (isNativeSource(state?.source?.chainId, state?.source?.tokenSymbol)) {
57694
+ throw new SkillError("NATIVE_NOT_AVAILABLE", "Native coins are not available for Bitrefill invoices.");
57695
+ }
57058
57696
  const id = rozoPaymentId ?? state.rozoPaymentId;
57059
57697
  const payment = await getPayment(id);
57060
57698
  const guard = reuseGuard({ payment, requested: state.source });
@@ -57071,7 +57709,9 @@ async function finalPayabilityCheck({ linkId, chainId, intentExpiresAt, state =
57071
57709
  now: Date.now(),
57072
57710
  chainId,
57073
57711
  intentExpiresAt,
57074
- coinbaseExpiry: statusNow?.coinbase?.preApprovalExpiry
57712
+ coinbaseExpiry: statusNow?.coinbase?.preApprovalExpiry,
57713
+ // Native orders: the price lock, re-checked as the very last gate too.
57714
+ ...quoteExpiresAt !== void 0 ? { quoteExpiresAt } : {}
57075
57715
  });
57076
57716
  if (!expiry.ok) throw new SkillError(expiry.code, expiry.reason, expiry);
57077
57717
  return { statusNow, payable, expiry };
@@ -57116,165 +57756,146 @@ function broadcastOutcome({ receiptStatus, executionError = null, receiptSeen =
57116
57756
  };
57117
57757
  }
57118
57758
 
57119
- // scripts/src/lib/gas.mjs
57120
- var EVM_FEE_COIN = Object.freeze({
57121
- 1: { symbol: "ETH", network: "Ethereum" },
57122
- 56: { symbol: "BNB", network: "BNB Chain" },
57123
- 137: { symbol: "POL", network: "Polygon" },
57124
- 8453: { symbol: "ETH", network: "Base" }
57125
- });
57126
- var DEFAULT_GAS_BUFFER_PCT = 20;
57127
- var MAX_GAS_BUFFER_PCT = 200;
57128
- function gasBufferPct(env = process.env) {
57129
- const raw = env?.ROZO_CHECKOUT_GAS_BUFFER_PCT;
57130
- if (raw === void 0 || raw === "") return DEFAULT_GAS_BUFFER_PCT;
57131
- const n = Number(raw);
57132
- if (!Number.isInteger(n) || n < 0 || n > MAX_GAS_BUFFER_PCT) return DEFAULT_GAS_BUFFER_PCT;
57133
- return n;
57134
- }
57135
- function formatAtomic(atomic, decimals) {
57136
- const neg = atomic < 0n;
57137
- const v = neg ? -atomic : atomic;
57138
- const base = 10n ** BigInt(decimals);
57139
- const whole = v / base;
57140
- const frac = (v % base).toString().padStart(decimals, "0").replace(/0+$/, "");
57141
- return `${neg ? "-" : ""}${whole}${frac ? `.${frac}` : ""}`;
57142
- }
57143
- function evmFeeRequirement({ gasEstimate, maxFeePerGas, gasPrice, bufferPct = DEFAULT_GAS_BUFFER_PCT }) {
57144
- const perGas = typeof maxFeePerGas === "bigint" ? maxFeePerGas : typeof gasPrice === "bigint" ? gasPrice : null;
57145
- if (typeof gasEstimate !== "bigint" || perGas === null) return null;
57146
- const gasLimit = (gasEstimate * BigInt(100 + bufferPct) + 99n) / 100n;
57147
- return { gasLimit, perGas, pricing: typeof maxFeePerGas === "bigint" ? "eip1559" : "legacy", fee: gasLimit * perGas };
57148
- }
57149
- function assessFee({ balance, required, decimals, symbol, network }) {
57150
- const ok = required === null ? balance > 0n : balance >= required;
57151
- const details = {
57152
- network,
57153
- feeCoin: symbol,
57154
- balance: formatAtomic(balance, decimals),
57155
- required: required === null ? null : formatAtomic(required, decimals),
57156
- shortfall: required === null || ok ? null : formatAtomic(required - balance, decimals)
57157
- };
57158
- return { ok, details };
57159
- }
57160
- function insufficient(details, extra) {
57161
- const need = details.required ? `about ${details.required} ${details.feeCoin}` : `some ${details.feeCoin}`;
57162
- return new SkillError(
57163
- "INSUFFICIENT_GAS",
57164
- `This wallet holds ${details.balance} ${details.feeCoin} on ${details.network} but needs ${need} for the network fee${details.shortfall ? ` (short by ${details.shortfall} ${details.feeCoin})` : ""}. Nothing was signed. Add ${details.feeCoin} on ${details.network} to this wallet and re-run, or pay with a different coin.` + (extra ? ` ${extra}` : ""),
57165
- details
57166
- );
57167
- }
57168
- function unavailable(network, err) {
57169
- return new SkillError(
57170
- "GAS_CHECK_UNAVAILABLE",
57171
- `Could not check the network fee on ${network}: ${redact(err?.shortMessage || err?.message || "unknown error")}. This is not evidence of a shortfall. Nothing was signed. Retry, pass --rpc <url>, or pay by hand from your wallet.`,
57172
- { network }
57173
- );
57759
+ // scripts/src/lib/native-send.mjs
57760
+ var import_web3 = __toESM(require_index_cjs(), 1);
57761
+ var MEMO_PROGRAM_ID = new import_web3.PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr");
57762
+ var EVM_ADDRESS_RE2 = /^0x[0-9a-fA-F]{40}$/;
57763
+ function assertNativeTokenAddress(tokenAddress) {
57764
+ if (!isNativeTokenAddress(tokenAddress)) {
57765
+ throw new SkillError(
57766
+ "NATIVE_TOKEN_ADDRESS_UNEXPECTED",
57767
+ "This native coin order names a token contract or mint, which a native payment never uses. Refusing to guess which asset to send."
57768
+ );
57769
+ }
57174
57770
  }
57175
- async function estimateFees(client) {
57176
- try {
57177
- return await client.estimateFeesPerGas();
57178
- } catch (err) {
57179
- if (err?.name !== "Eip1559FeesNotSupportedError") throw err;
57180
- return client.estimateFeesPerGas({ type: "legacy" });
57771
+ function assertPositive(amountAtomic) {
57772
+ if (typeof amountAtomic !== "bigint" || amountAtomic <= 0n) {
57773
+ throw new SkillError("DEPOSIT_INCOMPLETE", "The order carries no positive native amount.");
57181
57774
  }
57182
57775
  }
57183
- var OP_STACK_GAS_PRICE_ORACLE = "0x420000000000000000000000000000000000000F";
57184
- var OP_STACK_CHAIN_IDS = /* @__PURE__ */ new Set([8453]);
57185
- async function evmGasPrecheck({
57776
+ async function prepareEvmNativeSend({
57186
57777
  client,
57187
57778
  chainId,
57188
57779
  from: from15,
57189
57780
  to,
57190
- data,
57191
- value = 0n,
57192
- bufferPct = gasBufferPct(),
57781
+ amountAtomic,
57782
+ tokenAddress,
57783
+ tokenSymbol,
57193
57784
  estimateL1Fee: estimateL1Fee2 = null
57194
57785
  }) {
57195
- const coin = EVM_FEE_COIN[Number(chainId)] ?? { symbol: "native coin", network: `chain ${chainId}` };
57786
+ assertNativeTokenAddress(tokenAddress);
57787
+ assertPositive(amountAtomic);
57788
+ if (!EVM_ADDRESS_RE2.test(String(to ?? ""))) {
57789
+ throw new SkillError("BAD_DEPOSIT_ADDRESS", "The deposit address is not a valid EVM address.");
57790
+ }
57196
57791
  let balance;
57197
57792
  try {
57198
57793
  balance = await client.getBalance({ address: from15 });
57199
57794
  } catch (err) {
57200
- throw unavailable(coin.network, err);
57795
+ throw new SkillError(
57796
+ "GAS_CHECK_UNAVAILABLE",
57797
+ `Could not read the ${tokenSymbol} balance: ${redact(err?.shortMessage || err?.message || "unknown error")}. This is not evidence of a shortfall. Nothing was signed.`
57798
+ );
57201
57799
  }
57202
- let gasEstimate;
57203
- let fees;
57204
- try {
57205
- gasEstimate = await client.estimateGas({ account: from15, to, data, value });
57206
- fees = await estimateFees(client);
57207
- } catch (err) {
57208
- if (balance === 0n) {
57209
- throw insufficient(
57210
- assessFee({ balance, required: null, decimals: 18, symbol: coin.symbol, network: coin.network }).details
57211
- );
57212
- }
57213
- throw unavailable(coin.network, err);
57800
+ if (balance < amountAtomic) {
57801
+ throw new SkillError(
57802
+ "INSUFFICIENT_BALANCE",
57803
+ `This wallet holds ${formatAtomic(balance, 18)} ${tokenSymbol}; the order needs exactly ${formatAtomic(amountAtomic, 18)} ${tokenSymbol} plus the network fee. Nothing was signed.`
57804
+ );
57214
57805
  }
57215
- const req = evmFeeRequirement({
57216
- gasEstimate,
57217
- maxFeePerGas: fees?.maxFeePerGas,
57218
- gasPrice: fees?.gasPrice,
57219
- bufferPct
57806
+ const networkFee = await evmGasPrecheck({
57807
+ client,
57808
+ chainId,
57809
+ from: from15,
57810
+ to,
57811
+ data: void 0,
57812
+ value: amountAtomic,
57813
+ estimateL1Fee: estimateL1Fee2
57220
57814
  });
57221
- if (!req) throw unavailable(coin.network, new Error("the node returned no fee price"));
57222
- let l1Fee = 0n;
57223
- if (OP_STACK_CHAIN_IDS.has(Number(chainId))) {
57224
- if (typeof estimateL1Fee2 !== "function") {
57225
- throw unavailable(coin.network, new Error("no L1 data fee estimator for this OP-stack chain"));
57226
- }
57227
- try {
57228
- l1Fee = (await estimateL1Fee2() * BigInt(100 + bufferPct) + 99n) / 100n;
57229
- } catch (err) {
57230
- throw unavailable(coin.network, err);
57231
- }
57815
+ return { request: { to, value: amountAtomic }, balance, networkFee };
57816
+ }
57817
+ function assertPreparedNativeRequest(prepared, { to, value }) {
57818
+ const gotTo = String(prepared?.to ?? "").toLowerCase();
57819
+ const data = prepared?.data;
57820
+ if (gotTo !== String(to).toLowerCase()) {
57821
+ throw new SkillError("PREPARED_TX_MISMATCH", "The prepared transaction is not addressed to the deposit address.");
57232
57822
  }
57233
- const required = req.fee + l1Fee + value;
57234
- const { ok, details } = assessFee({ balance, required, decimals: 18, symbol: coin.symbol, network: coin.network });
57235
- const full = {
57236
- ...details,
57237
- gasLimit: req.gasLimit.toString(),
57238
- pricing: req.pricing,
57239
- bufferPct,
57240
- l1DataFee: OP_STACK_CHAIN_IDS.has(Number(chainId)) ? formatAtomic(l1Fee, 18) : null
57241
- };
57242
- if (!ok) throw insufficient(full);
57243
- return full;
57823
+ if (prepared?.value !== value) {
57824
+ throw new SkillError("PREPARED_TX_MISMATCH", "The prepared transaction does not carry the exact order amount.");
57825
+ }
57826
+ if (data !== void 0 && data !== null && data !== "0x" && data !== "") {
57827
+ throw new SkillError("PREPARED_TX_MISMATCH", "A native payment must not carry calldata.");
57828
+ }
57829
+ return true;
57244
57830
  }
57245
- var LAMPORTS_DECIMALS = 9;
57246
- async function solFeePrecheck({ connection, payer, message }) {
57247
- const network = "Solana";
57248
- let balance;
57249
- let fee;
57831
+ async function prepareSolNativeSend({
57832
+ connection,
57833
+ payer,
57834
+ recipientAddress,
57835
+ amountAtomic,
57836
+ memo = null,
57837
+ tokenAddress
57838
+ }) {
57839
+ assertNativeTokenAddress(tokenAddress);
57840
+ assertPositive(amountAtomic);
57841
+ let recipient;
57842
+ try {
57843
+ recipient = new import_web3.PublicKey(recipientAddress);
57844
+ } catch {
57845
+ throw new SkillError("BAD_DEPOSIT_ADDRESS", "The deposit address is not a valid Solana address.");
57846
+ }
57847
+ let info;
57250
57848
  let rentMin;
57849
+ let balance;
57251
57850
  try {
57252
- balance = BigInt(await connection.getBalance(payer, "confirmed"));
57253
- const res = await connection.getFeeForMessage(message, "confirmed");
57254
- if (res?.value === null || res?.value === void 0) {
57255
- throw new Error("the node returned no fee for this transaction (stale blockhash?)");
57256
- }
57257
- fee = BigInt(res.value);
57851
+ info = await connection.getAccountInfo(recipient, "confirmed");
57258
57852
  rentMin = BigInt(await connection.getMinimumBalanceForRentExemption(0));
57853
+ balance = BigInt(await connection.getBalance(payer, "confirmed"));
57259
57854
  } catch (err) {
57260
- if (balance === 0n) {
57261
- throw insufficient(
57262
- assessFee({ balance, required: null, decimals: LAMPORTS_DECIMALS, symbol: "SOL", network }).details
57263
- );
57264
- }
57265
- throw unavailable(network, err);
57855
+ throw new SkillError(
57856
+ "RPC_READ_FAILED",
57857
+ `Could not read the Solana accounts: ${redact(err?.message || "unknown error")}. Nothing was signed.`
57858
+ );
57266
57859
  }
57267
- const remaining = balance - fee;
57268
- const required = remaining === 0n ? fee : fee + rentMin;
57269
- const { ok, details } = assessFee({ balance, required, decimals: LAMPORTS_DECIMALS, symbol: "SOL", network });
57270
- const full = { ...details, fee: formatAtomic(fee, LAMPORTS_DECIMALS), rentExemptMinimum: formatAtomic(rentMin, LAMPORTS_DECIMALS) };
57271
- if (!ok) {
57272
- throw insufficient(
57273
- full,
57274
- balance >= fee ? "Solana also requires a wallet to keep a small minimum balance after paying the fee." : null
57860
+ if (info && (info.executable || !info.owner?.equals?.(import_web3.SystemProgram.programId))) {
57861
+ throw new SkillError(
57862
+ "DEPOSIT_ACCOUNT_NOT_WALLET",
57863
+ "The deposit address is not a plain Solana wallet (it is a token account or a program). Refusing to send SOL to it."
57275
57864
  );
57276
57865
  }
57277
- return full;
57866
+ if (!info && amountAtomic < rentMin) {
57867
+ throw new SkillError(
57868
+ "DEPOSIT_BELOW_RENT",
57869
+ `The deposit address does not exist yet and ${formatAtomic(amountAtomic, 9)} SOL is below the ${formatAtomic(rentMin, 9)} SOL needed to open it. Pay this order another way.`
57870
+ );
57871
+ }
57872
+ if (balance < amountAtomic) {
57873
+ throw new SkillError(
57874
+ "INSUFFICIENT_BALANCE",
57875
+ `This wallet holds ${formatAtomic(balance, 9)} SOL; the order needs exactly ${formatAtomic(amountAtomic, 9)} SOL plus the network fee. Nothing was signed.`
57876
+ );
57877
+ }
57878
+ const tx = new import_web3.Transaction();
57879
+ tx.add(import_web3.SystemProgram.transfer({ fromPubkey: payer, toPubkey: recipient, lamports: amountAtomic }));
57880
+ if (memo) {
57881
+ tx.add(
57882
+ new import_web3.TransactionInstruction({
57883
+ keys: [],
57884
+ programId: MEMO_PROGRAM_ID,
57885
+ data: Buffer.from(String(memo), "utf8")
57886
+ })
57887
+ );
57888
+ }
57889
+ const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
57890
+ tx.recentBlockhash = blockhash;
57891
+ tx.feePayer = payer;
57892
+ const networkFee = await solFeePrecheck({
57893
+ connection,
57894
+ payer,
57895
+ message: tx.compileMessage(),
57896
+ value: amountAtomic
57897
+ });
57898
+ return { tx, recipient, blockhash, lastValidBlockHeight, networkFee, recipientExists: Boolean(info) };
57278
57899
  }
57279
57900
 
57280
57901
  // node_modules/viem/_esm/op-stack/contracts.js
@@ -57566,30 +58187,15 @@ var ERC20_TRANSFER_ABI = [
57566
58187
  outputs: [{ name: "", type: "uint8" }]
57567
58188
  }
57568
58189
  ];
57569
- var DEFAULT_RPC = {
57570
- 1: "https://eth.llamarpc.com",
57571
- 56: "https://bsc-dataseed.binance.org",
57572
- 137: "https://polygon-rpc.com",
57573
- 8453: "https://mainnet.base.org"
57574
- };
57575
- function rpcFor(chainId, override) {
57576
- if (override && override !== true) return String(override);
57577
- const env = process.env[`ROZO_CHECKOUT_RPC_${chainId}`];
57578
- if (env) return env;
57579
- const fallback = DEFAULT_RPC[String(chainId)];
57580
- if (!fallback) {
57581
- throw new SkillError(
57582
- "NO_RPC",
57583
- `No RPC known for chain ${chainId}. Pass --rpc <url> or set ROZO_CHECKOUT_RPC_${chainId}.`
57584
- );
57585
- }
57586
- return fallback;
57587
- }
57588
58190
  function chainDef(chainId, rpcUrl) {
57589
58191
  return defineChain({
57590
58192
  id: Number(chainId),
57591
58193
  name: chainName(chainId),
57592
- nativeCurrency: { name: "Native", symbol: "NATIVE", decimals: 18 },
58194
+ nativeCurrency: {
58195
+ name: EVM_FEE_COIN[Number(chainId)]?.symbol ?? "Native",
58196
+ symbol: EVM_FEE_COIN[Number(chainId)]?.symbol ?? "NATIVE",
58197
+ decimals: 18
58198
+ },
57593
58199
  rpcUrls: { default: { http: [rpcUrl] } }
57594
58200
  });
57595
58201
  }
@@ -57608,7 +58214,7 @@ async function main7(argv) {
57608
58214
  const sender = account.address;
57609
58215
  const keySource = loaded.label;
57610
58216
  const dryRun = Boolean(args["dry-run"]);
57611
- const { source, state, expiry, amountAtomic, payment } = await preflight({
58217
+ const { source, state, expiry, amountAtomic, payment, quoteExpiresAt } = await preflight({
57612
58218
  rozoPaymentId,
57613
58219
  expectFamily: "evm",
57614
58220
  senderAddress: sender,
@@ -57616,8 +58222,9 @@ async function main7(argv) {
57616
58222
  dryRun
57617
58223
  });
57618
58224
  const chainId = Number(source.chainId);
58225
+ const native = isNativeSource(source.chainId, source.tokenSymbol);
57619
58226
  const tokenAddress = source.tokenAddress;
57620
- if (!tokenAddress || !/^0x[0-9a-fA-F]{40}$/.test(tokenAddress)) {
58227
+ if (!native && (!tokenAddress || !/^0x[0-9a-fA-F]{40}$/.test(tokenAddress))) {
57621
58228
  throw new SkillError("NO_TOKEN_ADDRESS", "The order did not carry a usable ERC-20 address.");
57622
58229
  }
57623
58230
  const to = source.receiverAddress;
@@ -57639,57 +58246,75 @@ async function main7(argv) {
57639
58246
  `RPC reports chain ${rpcChainId} but this order settles on ${chainId}. Refusing to sign.`
57640
58247
  );
57641
58248
  }
57642
- let onChainDecimals;
57643
- try {
57644
- onChainDecimals = Number(
57645
- await pub.readContract({ address: tokenAddress, abi: ERC20_TRANSFER_ABI, functionName: "decimals" })
57646
- );
57647
- } catch (err) {
57648
- throw new SkillError("TOKEN_READ_FAILED", `Could not read token decimals: ${redact(err?.message)}`);
57649
- }
57650
- const expectedDecimals = decimalsFor(source.chainId, source.tokenSymbol);
57651
- if (onChainDecimals !== expectedDecimals) {
57652
- throw new SkillError(
57653
- "DECIMALS_MISMATCH",
57654
- `Token reports ${onChainDecimals} decimals but ${source.tokenSymbol} on ${chainName(chainId)} is expected to have ${expectedDecimals}. Refusing to sign an amount that could be off by orders of magnitude.`
57655
- );
57656
- }
57657
- let balance;
57658
- try {
57659
- balance = await pub.readContract({
57660
- address: tokenAddress,
58249
+ const l1FeeFor = (tx) => OP_STACK_CHAIN_IDS.has(chainId) ? () => estimateL1Fee(pub, {
58250
+ account: sender,
58251
+ ...tx,
58252
+ chain,
58253
+ gasPriceOracleAddress: OP_STACK_GAS_PRICE_ORACLE
58254
+ }) : null;
58255
+ let txRequest;
58256
+ let networkFee;
58257
+ if (native) {
58258
+ const prepared = await prepareEvmNativeSend({
58259
+ client: pub,
58260
+ chainId,
58261
+ from: sender,
58262
+ to,
58263
+ amountAtomic,
58264
+ tokenAddress,
58265
+ tokenSymbol: source.tokenSymbol,
58266
+ estimateL1Fee: l1FeeFor({ to, value: amountAtomic })
58267
+ });
58268
+ txRequest = prepared.request;
58269
+ networkFee = prepared.networkFee;
58270
+ } else {
58271
+ let onChainDecimals;
58272
+ try {
58273
+ onChainDecimals = Number(
58274
+ await pub.readContract({ address: tokenAddress, abi: ERC20_TRANSFER_ABI, functionName: "decimals" })
58275
+ );
58276
+ } catch (err) {
58277
+ throw new SkillError("TOKEN_READ_FAILED", `Could not read token decimals: ${redact(err?.message)}`);
58278
+ }
58279
+ const expectedDecimals = decimalsFor(source.chainId, source.tokenSymbol);
58280
+ if (onChainDecimals !== expectedDecimals) {
58281
+ throw new SkillError(
58282
+ "DECIMALS_MISMATCH",
58283
+ `Token reports ${onChainDecimals} decimals but ${source.tokenSymbol} on ${chainName(chainId)} is expected to have ${expectedDecimals}. Refusing to sign an amount that could be off by orders of magnitude.`
58284
+ );
58285
+ }
58286
+ let balance;
58287
+ try {
58288
+ balance = await pub.readContract({
58289
+ address: tokenAddress,
58290
+ abi: ERC20_TRANSFER_ABI,
58291
+ functionName: "balanceOf",
58292
+ args: [sender]
58293
+ });
58294
+ } catch (err) {
58295
+ throw new SkillError("TOKEN_READ_FAILED", `Could not read balance: ${redact(err?.message)}`);
58296
+ }
58297
+ if (balance < amountAtomic) {
58298
+ throw new SkillError(
58299
+ "INSUFFICIENT_BALANCE",
58300
+ `Sender holds ${balance} atomic units of ${source.tokenSymbol} on ${chainName(chainId)}; ${amountAtomic} are required.`
58301
+ );
58302
+ }
58303
+ const data = encodeFunctionData({
57661
58304
  abi: ERC20_TRANSFER_ABI,
57662
- functionName: "balanceOf",
57663
- args: [sender]
58305
+ functionName: "transfer",
58306
+ args: [to, amountAtomic]
57664
58307
  });
57665
- } catch (err) {
57666
- throw new SkillError("TOKEN_READ_FAILED", `Could not read balance: ${redact(err?.message)}`);
57667
- }
57668
- if (balance < amountAtomic) {
57669
- throw new SkillError(
57670
- "INSUFFICIENT_BALANCE",
57671
- `Sender holds ${balance} atomic units of ${source.tokenSymbol} on ${chainName(chainId)}; ${amountAtomic} are required.`
57672
- );
57673
- }
57674
- const data = encodeFunctionData({
57675
- abi: ERC20_TRANSFER_ABI,
57676
- functionName: "transfer",
57677
- args: [to, amountAtomic]
57678
- });
57679
- const networkFee = await evmGasPrecheck({
57680
- client: pub,
57681
- chainId,
57682
- from: sender,
57683
- to: tokenAddress,
57684
- data,
57685
- estimateL1Fee: OP_STACK_CHAIN_IDS.has(chainId) ? () => estimateL1Fee(pub, {
57686
- account: sender,
58308
+ networkFee = await evmGasPrecheck({
58309
+ client: pub,
58310
+ chainId,
58311
+ from: sender,
57687
58312
  to: tokenAddress,
57688
58313
  data,
57689
- chain,
57690
- gasPriceOracleAddress: OP_STACK_GAS_PRICE_ORACLE
57691
- }) : null
57692
- });
58314
+ estimateL1Fee: l1FeeFor({ to: tokenAddress, data })
58315
+ });
58316
+ txRequest = { to: tokenAddress, data, value: 0n };
58317
+ }
57693
58318
  if (dryRun) {
57694
58319
  emit({
57695
58320
  success: true,
@@ -57700,6 +58325,9 @@ async function main7(argv) {
57700
58325
  chainId,
57701
58326
  chain: chainName(chainId),
57702
58327
  tokenSymbol: source.tokenSymbol,
58328
+ native,
58329
+ kind: native ? "native value transfer" : "ERC-20 transfer",
58330
+ priceLockedUntil: native ? quoteExpiresAt : null,
57703
58331
  amountAtomic: amountAtomic.toString(),
57704
58332
  amount: source.amount,
57705
58333
  toMasked: maskAddress2(to),
@@ -57715,11 +58343,8 @@ async function main7(argv) {
57715
58343
  });
57716
58344
  }
57717
58345
  const wallet = createWalletClient({ account, chain, transport: http(rpcUrl) });
57718
- const request2 = await wallet.prepareTransactionRequest({
57719
- to: tokenAddress,
57720
- data,
57721
- value: 0n
57722
- });
58346
+ const request2 = await wallet.prepareTransactionRequest(txRequest);
58347
+ if (native) assertPreparedNativeRequest(request2, { to, value: amountAtomic });
57723
58348
  const serialized = await wallet.signTransaction(request2);
57724
58349
  const expectedTxHash = keccak256(serialized);
57725
58350
  const nonceBefore = Number(request2.nonce);
@@ -57727,6 +58352,7 @@ async function main7(argv) {
57727
58352
  linkId: state.linkId,
57728
58353
  chainId: source.chainId,
57729
58354
  intentExpiresAt: payment?.expiresAt,
58355
+ quoteExpiresAt,
57730
58356
  state,
57731
58357
  rozoPaymentId
57732
58358
  });
@@ -57735,6 +58361,7 @@ async function main7(argv) {
57735
58361
  {
57736
58362
  chainId: String(chainId),
57737
58363
  tokenSymbol: source.tokenSymbol,
58364
+ native,
57738
58365
  from: sender,
57739
58366
  to,
57740
58367
  amountAtomic: amountAtomic.toString(),
@@ -57841,18 +58468,18 @@ async function run7(argv = process.argv.slice(2)) {
57841
58468
  }
57842
58469
 
57843
58470
  // scripts/src/send-sol.mjs
57844
- var import_web32 = __toESM(require_index_cjs(), 1);
58471
+ var import_web33 = __toESM(require_index_cjs(), 1);
57845
58472
 
57846
58473
  // scripts/src/spl-lite.mjs
57847
- var import_web3 = __toESM(require_index_cjs(), 1);
57848
- var TOKEN_PROGRAM_ID = new import_web3.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
57849
- var ASSOCIATED_TOKEN_PROGRAM_ID = new import_web3.PublicKey(
58474
+ var import_web32 = __toESM(require_index_cjs(), 1);
58475
+ var TOKEN_PROGRAM_ID = new import_web32.PublicKey("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA");
58476
+ var ASSOCIATED_TOKEN_PROGRAM_ID = new import_web32.PublicKey(
57850
58477
  "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"
57851
58478
  );
57852
58479
  var TOKEN_ACCOUNT_LEN = 165;
57853
58480
  var MINT_LEN = 82;
57854
58481
  async function getAssociatedTokenAddress(mint, owner) {
57855
- const [address] = import_web3.PublicKey.findProgramAddressSync(
58482
+ const [address] = import_web32.PublicKey.findProgramAddressSync(
57856
58483
  [owner.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()],
57857
58484
  ASSOCIATED_TOKEN_PROGRAM_ID
57858
58485
  );
@@ -57873,8 +58500,8 @@ async function getAccount(connection, address) {
57873
58500
  const data = await fetchOwnedAccount(connection, address, TOKEN_ACCOUNT_LEN, "Token account");
57874
58501
  return {
57875
58502
  address,
57876
- mint: new import_web3.PublicKey(data.subarray(0, 32)),
57877
- owner: new import_web3.PublicKey(data.subarray(32, 64)),
58503
+ mint: new import_web32.PublicKey(data.subarray(0, 32)),
58504
+ owner: new import_web32.PublicKey(data.subarray(32, 64)),
57878
58505
  amount: data.readBigUInt64LE(64)
57879
58506
  };
57880
58507
  }
@@ -57891,7 +58518,7 @@ function createTransferCheckedInstruction(source, mint, destination, owner, amou
57891
58518
  data.writeUInt8(12, 0);
57892
58519
  data.writeBigUInt64LE(BigInt(amount), 1);
57893
58520
  data.writeUInt8(decimals, 9);
57894
- return new import_web3.TransactionInstruction({
58521
+ return new import_web32.TransactionInstruction({
57895
58522
  programId: TOKEN_PROGRAM_ID,
57896
58523
  keys: [
57897
58524
  { pubkey: source, isSigner: false, isWritable: true },
@@ -57904,7 +58531,6 @@ function createTransferCheckedInstruction(source, mint, destination, owner, amou
57904
58531
  }
57905
58532
 
57906
58533
  // scripts/src/send-sol.mjs
57907
- var MEMO_PROGRAM_ID = new import_web32.PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr");
57908
58534
  var MAINNET_GENESIS = "5eykt4UsFv8P8NJdTREpY1vzqKqZKvdpKuc147dw2N9d";
57909
58535
  var B58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
57910
58536
  async function main8(argv) {
@@ -57919,19 +58545,19 @@ async function main8(argv) {
57919
58545
  });
57920
58546
  const loaded = await loadKeySource(plan, { family: "solana", askPassphrase: promptPassphrase });
57921
58547
  const secret = loaded.secretKey;
57922
- const keypair = secret.length === 64 ? import_web32.Keypair.fromSecretKey(secret) : import_web32.Keypair.fromSeed(secret);
58548
+ const keypair = secret.length === 64 ? import_web33.Keypair.fromSecretKey(secret) : import_web33.Keypair.fromSeed(secret);
57923
58549
  const sender = keypair.publicKey.toBase58();
57924
58550
  const keySource = loaded.label;
57925
58551
  const dryRun = Boolean(args["dry-run"]);
57926
- const { source, state, expiry, amountAtomic, payment } = await preflight({
58552
+ const { source, state, expiry, amountAtomic, payment, quoteExpiresAt } = await preflight({
57927
58553
  rozoPaymentId,
57928
58554
  expectFamily: "solana",
57929
58555
  senderAddress: sender,
57930
58556
  send: Boolean(args.send),
57931
58557
  dryRun
57932
58558
  });
57933
- const rpcUrl = args.rpc && args.rpc !== true && String(args.rpc) || process.env.ROZO_CHECKOUT_RPC_900 || "https://api.mainnet-beta.solana.com";
57934
- const connection = new import_web32.Connection(rpcUrl, "confirmed");
58559
+ const rpcUrl = rpcFor("900", args.rpc);
58560
+ const connection = new import_web33.Connection(rpcUrl, "confirmed");
57935
58561
  let genesis;
57936
58562
  try {
57937
58563
  genesis = await connection.getGenesisHash();
@@ -57944,94 +58570,111 @@ async function main8(argv) {
57944
58570
  "The configured Solana RPC is not mainnet-beta. Refusing to sign."
57945
58571
  );
57946
58572
  }
57947
- let mint;
57948
- try {
57949
- mint = new import_web32.PublicKey(source.tokenAddress);
57950
- } catch {
57951
- throw new SkillError("NO_TOKEN_ADDRESS", "The order did not carry a usable SPL mint address.");
57952
- }
57953
- let recipient;
57954
- try {
57955
- recipient = new import_web32.PublicKey(source.receiverAddress);
57956
- } catch {
57957
- throw new SkillError("BAD_DEPOSIT_ADDRESS", "The deposit address is not a valid Solana address.");
57958
- }
57959
- const mintInfo = await getMint(connection, mint);
57960
- const expectedDecimals = decimalsFor(source.chainId, source.tokenSymbol);
57961
- if (mintInfo.decimals !== expectedDecimals) {
57962
- throw new SkillError(
57963
- "DECIMALS_MISMATCH",
57964
- `Mint reports ${mintInfo.decimals} decimals, expected ${expectedDecimals} for ${source.tokenSymbol} on Solana. Refusing to sign.`
57965
- );
57966
- }
57967
- const fromAta = await getAssociatedTokenAddress(mint, keypair.publicKey);
57968
- let fromAccount;
57969
- try {
57970
- fromAccount = await getAccount(connection, fromAta);
57971
- } catch {
57972
- throw new SkillError(
57973
- "NO_TOKEN_ACCOUNT",
57974
- `The sender has no ${source.tokenSymbol} token account on Solana.`
57975
- );
57976
- }
57977
- if (fromAccount.amount < amountAtomic) {
57978
- throw new SkillError(
57979
- "INSUFFICIENT_BALANCE",
57980
- `Sender holds ${fromAccount.amount} atomic units; ${amountAtomic} are required.`
57981
- );
57982
- }
57983
- let toAta;
58573
+ const native = isNativeSource(source.chainId, source.tokenSymbol);
58574
+ let tx;
58575
+ let blockhash;
58576
+ let lastValidBlockHeight;
58577
+ let networkFee;
57984
58578
  let toIsTokenAccount = false;
57985
- try {
57986
- const acc = await getAccount(connection, recipient);
57987
- if (acc.mint.toBase58() !== mint.toBase58()) {
58579
+ if (native) {
58580
+ const prepared = await prepareSolNativeSend({
58581
+ connection,
58582
+ payer: keypair.publicKey,
58583
+ recipientAddress: source.receiverAddress,
58584
+ amountAtomic,
58585
+ memo: source.receiverMemo ?? null,
58586
+ tokenAddress: source.tokenAddress
58587
+ });
58588
+ ({ tx, blockhash, lastValidBlockHeight, networkFee } = prepared);
58589
+ } else {
58590
+ let mint;
58591
+ try {
58592
+ mint = new import_web33.PublicKey(source.tokenAddress);
58593
+ } catch {
58594
+ throw new SkillError("NO_TOKEN_ADDRESS", "The order did not carry a usable SPL mint address.");
58595
+ }
58596
+ let recipient;
58597
+ try {
58598
+ recipient = new import_web33.PublicKey(source.receiverAddress);
58599
+ } catch {
58600
+ throw new SkillError("BAD_DEPOSIT_ADDRESS", "The deposit address is not a valid Solana address.");
58601
+ }
58602
+ const mintInfo = await getMint(connection, mint);
58603
+ const expectedDecimals = decimalsFor(source.chainId, source.tokenSymbol);
58604
+ if (mintInfo.decimals !== expectedDecimals) {
57988
58605
  throw new SkillError(
57989
- "DEPOSIT_ACCOUNT_MISMATCH",
57990
- "The deposit token account is for a different mint. Refusing to send."
58606
+ "DECIMALS_MISMATCH",
58607
+ `Mint reports ${mintInfo.decimals} decimals, expected ${expectedDecimals} for ${source.tokenSymbol} on Solana. Refusing to sign.`
57991
58608
  );
57992
58609
  }
57993
- toAta = recipient;
57994
- toIsTokenAccount = true;
57995
- } catch (err) {
57996
- if (err instanceof SkillError) throw err;
57997
- toAta = await getAssociatedTokenAddress(mint, recipient);
58610
+ const fromAta = await getAssociatedTokenAddress(mint, keypair.publicKey);
58611
+ let fromAccount;
57998
58612
  try {
57999
- await getAccount(connection, toAta);
58613
+ fromAccount = await getAccount(connection, fromAta);
58000
58614
  } catch {
58001
58615
  throw new SkillError(
58002
- "DEPOSIT_ACCOUNT_MISSING",
58003
- "The deposit address has no token account for this mint. Refusing to create one on its behalf \u2014 re-run create-order.js for fresh instructions."
58616
+ "NO_TOKEN_ACCOUNT",
58617
+ `The sender has no ${source.tokenSymbol} token account on Solana.`
58004
58618
  );
58005
58619
  }
58006
- }
58007
- const tx = new import_web32.Transaction();
58008
- tx.add(
58009
- createTransferCheckedInstruction(
58010
- fromAta,
58011
- mint,
58012
- toAta,
58013
- keypair.publicKey,
58014
- amountAtomic,
58015
- mintInfo.decimals
58016
- )
58017
- );
58018
- if (source.receiverMemo) {
58620
+ if (fromAccount.amount < amountAtomic) {
58621
+ throw new SkillError(
58622
+ "INSUFFICIENT_BALANCE",
58623
+ `Sender holds ${fromAccount.amount} atomic units; ${amountAtomic} are required.`
58624
+ );
58625
+ }
58626
+ let toAta;
58627
+ try {
58628
+ const acc = await getAccount(connection, recipient);
58629
+ if (acc.mint.toBase58() !== mint.toBase58()) {
58630
+ throw new SkillError(
58631
+ "DEPOSIT_ACCOUNT_MISMATCH",
58632
+ "The deposit token account is for a different mint. Refusing to send."
58633
+ );
58634
+ }
58635
+ toAta = recipient;
58636
+ toIsTokenAccount = true;
58637
+ } catch (err) {
58638
+ if (err instanceof SkillError) throw err;
58639
+ toAta = await getAssociatedTokenAddress(mint, recipient);
58640
+ try {
58641
+ await getAccount(connection, toAta);
58642
+ } catch {
58643
+ throw new SkillError(
58644
+ "DEPOSIT_ACCOUNT_MISSING",
58645
+ "The deposit address has no token account for this mint. Refusing to create one on its behalf \u2014 re-run create-order.js for fresh instructions."
58646
+ );
58647
+ }
58648
+ }
58649
+ tx = new import_web33.Transaction();
58019
58650
  tx.add(
58020
- new import_web32.TransactionInstruction({
58021
- keys: [],
58022
- programId: MEMO_PROGRAM_ID,
58023
- data: Buffer.from(String(source.receiverMemo), "utf8")
58024
- })
58651
+ createTransferCheckedInstruction(
58652
+ fromAta,
58653
+ mint,
58654
+ toAta,
58655
+ keypair.publicKey,
58656
+ amountAtomic,
58657
+ mintInfo.decimals
58658
+ )
58025
58659
  );
58660
+ if (source.receiverMemo) {
58661
+ tx.add(
58662
+ new import_web33.TransactionInstruction({
58663
+ keys: [],
58664
+ programId: MEMO_PROGRAM_ID,
58665
+ data: Buffer.from(String(source.receiverMemo), "utf8")
58666
+ })
58667
+ );
58668
+ }
58669
+ ({ blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed"));
58670
+ tx.recentBlockhash = blockhash;
58671
+ tx.feePayer = keypair.publicKey;
58672
+ networkFee = await solFeePrecheck({
58673
+ connection,
58674
+ payer: keypair.publicKey,
58675
+ message: tx.compileMessage()
58676
+ });
58026
58677
  }
58027
- const { blockhash, lastValidBlockHeight } = await connection.getLatestBlockhash("confirmed");
58028
- tx.recentBlockhash = blockhash;
58029
- tx.feePayer = keypair.publicKey;
58030
- const networkFee = await solFeePrecheck({
58031
- connection,
58032
- payer: keypair.publicKey,
58033
- message: tx.compileMessage()
58034
- });
58035
58678
  if (dryRun) {
58036
58679
  emit({
58037
58680
  success: true,
@@ -58041,6 +58684,9 @@ async function main8(argv) {
58041
58684
  wouldSend: {
58042
58685
  chain: chainName(900),
58043
58686
  tokenSymbol: source.tokenSymbol,
58687
+ native,
58688
+ kind: native ? "native SOL transfer" : "SPL transfer",
58689
+ priceLockedUntil: native ? quoteExpiresAt : null,
58044
58690
  amountAtomic: amountAtomic.toString(),
58045
58691
  amount: source.amount,
58046
58692
  toMasked: maskAddress2(source.receiverAddress),
@@ -58063,6 +58709,7 @@ async function main8(argv) {
58063
58709
  linkId: state.linkId,
58064
58710
  chainId: source.chainId,
58065
58711
  intentExpiresAt: payment?.expiresAt,
58712
+ quoteExpiresAt,
58066
58713
  state,
58067
58714
  rozoPaymentId
58068
58715
  });
@@ -58071,6 +58718,7 @@ async function main8(argv) {
58071
58718
  {
58072
58719
  chainId: "900",
58073
58720
  tokenSymbol: source.tokenSymbol,
58721
+ native,
58074
58722
  from: sender,
58075
58723
  to: source.receiverAddress,
58076
58724
  amountAtomic: amountAtomic.toString(),
@@ -59073,45 +59721,59 @@ async function askPayerAddress(saved) {
59073
59721
  const family = vetPayerAddress(address);
59074
59722
  return family ? { address, family } : null;
59075
59723
  }
59076
- async function pickSource({ invoiceUsd, saved, fresh }) {
59724
+ async function pickSource({ invoiceUsd, saved, fresh, isOffered }) {
59077
59725
  const payer = await askPayerAddress(fresh ? null : saved);
59078
- let marked = PICKER_OPTIONS.map((o) => ({ ...o, mark: "unchecked", balanceUsd: null }));
59726
+ const options = pickerOptionsFor(isOffered);
59727
+ let marked = options.map((o) => ({ ...o, mark: "unchecked", balanceUsd: null }));
59079
59728
  let checked = null;
59080
59729
  if (payer) {
59081
59730
  out(dim(" Checking balances\u2026"));
59082
- const result = await fetchWalletOptions({ address: payer.address, usdRequired: invoiceUsd });
59083
- if (result.ok) {
59084
- marked = markPickerOptions(PICKER_OPTIONS, result);
59731
+ const [result, native] = await Promise.all([
59732
+ fetchWalletOptions({ address: payer.address, usdRequired: invoiceUsd }),
59733
+ payer.family === "evm" || payer.family === "solana" ? fetchNativeBalances({ address: payer.address, family: payer.family, isOffered }) : Promise.resolve([])
59734
+ ]);
59735
+ if (result.ok || native.some((n) => n.ok)) {
59736
+ marked = markPickerOptions(options, { ...result, family: payer.family, native });
59085
59737
  checked = result;
59086
- } else {
59087
- out(` ${yellow(`Could not check balances (${result.reason}). Showing all coins.`)}`);
59738
+ }
59739
+ if (!result.ok) {
59740
+ out(` ${yellow(`Could not check stablecoin balances (${result.reason}).`)}`);
59088
59741
  }
59089
59742
  }
59090
59743
  out();
59091
59744
  out(` ${bold("Which coin do you want to pay with?")}`);
59092
- const savedPreset = fresh ? null : saved?.lastPreset ?? null;
59745
+ const remembered = fresh ? null : saved?.lastPreset ?? null;
59746
+ const savedPreset = options.some((o) => o.preset === remembered) ? remembered : null;
59093
59747
  let group = null;
59094
59748
  for (const o of marked) {
59095
- if (o.token !== group) {
59096
- group = o.token;
59749
+ const heading = o.group ?? o.token;
59750
+ if (heading !== group) {
59751
+ group = heading;
59097
59752
  out();
59098
- out(` ${dim(o.token)}`);
59753
+ out(` ${dim(heading)}`);
59754
+ if (heading === "Native coins") {
59755
+ out(` ${dim("exact amount and price set when the order is created; price locked about 1 hour")}`);
59756
+ }
59099
59757
  }
59100
- const badge = o.mark === "affordable" ? green(`\u2713 $${Number(o.balanceUsd ?? 0).toFixed(2)} available`) : o.mark === "insufficient" ? dim("\u2717 insufficient") : dim("\u2014 not checked");
59758
+ const badge = o.mark === "affordable" ? green(`\u2713 $${Number(o.balanceUsd ?? 0).toFixed(2)} available`) : o.mark === "held" ? green(`\u2713 ${o.held} held`) + dim(" (plus gas needed)") : o.mark === "insufficient" ? dim(o.note ? `\u2717 ${o.note}` : "\u2717 insufficient") : dim("\u2014 not checked");
59101
59759
  const star = savedPreset === o.preset ? bold(" (last used)") : "";
59102
- out(` ${String(o.number).padStart(2)}. ${o.chain.padEnd(12)} ${badge}${star}`);
59760
+ out(` ${String(o.number).padStart(2)}. ${(o.label ?? o.chain).padEnd(18)} ${badge}${star}`);
59103
59761
  }
59104
59762
  out();
59105
59763
  const defaultChoice = savedPreset ? ` [Enter for ${savedPreset}]` : "";
59106
59764
  for (let attempt = 0; attempt < 3; attempt++) {
59107
- const answer = String(await ask(` Number 1-${PICKER_OPTIONS.length}${defaultChoice}: `)).trim();
59765
+ const answer = String(await ask(` Number 1-${options.length}${defaultChoice}: `)).trim();
59108
59766
  const raw = answer || savedPreset;
59109
59767
  if (!raw) {
59110
59768
  out(` ${yellow("Type the number of a coin.")}`);
59111
59769
  continue;
59112
59770
  }
59113
59771
  try {
59114
- const choice = resolvePickerChoice(raw);
59772
+ const choice = resolvePickerChoice(raw, options);
59773
+ if (isNativeSource(choice.chainId, choice.tokenSymbol) && typeof isOffered === "function" && !isOffered(choice.chainId, choice.tokenSymbol)) {
59774
+ out(` ${yellow(`${choice.tokenSymbol} on ${chainName(choice.chainId)} is not offered for this invoice. Choose another coin.`)}`);
59775
+ continue;
59776
+ }
59115
59777
  if (checked && isProvablyShort(choice, checked)) {
59116
59778
  out(` ${yellow("That wallet appears not to hold enough for this invoice.")}`);
59117
59779
  out(` ${dim("You can still choose it \u2014 you may be paying from a different wallet.")}`);
@@ -59155,6 +59817,10 @@ async function cmdQuote(opts) {
59155
59817
  out(` Invoice ${bold(`${payload.invoice?.amount} ${payload.invoice?.fiat?.currency ?? "USD"}`)}`);
59156
59818
  out(` You pay ${payload.callerPays} ${dim("(no discount on this route)")}`);
59157
59819
  out(` Expires ${payload.coinbaseExpiryIso ?? "unknown"}`);
59820
+ const natives = (payload.nativeOffered ?? []).map((n) => presetFor(n.chainId, n.tokenSymbol)).filter(Boolean);
59821
+ if (natives.length) {
59822
+ out(` Native ${natives.join(", ")} ${dim("(exact-out; price locked about 1 hour)")}`);
59823
+ }
59158
59824
  out();
59159
59825
  out(dim(" Next: rozo-checkout pay <link> --with usdt-solana"));
59160
59826
  out();
@@ -59182,6 +59848,9 @@ async function cmdStatus(opts) {
59182
59848
  if (payload.expiry?.expiresIn && !payload.terminal) {
59183
59849
  out(` Expires in ${payload.expiry.expiresIn}`);
59184
59850
  }
59851
+ if (payload.expiry?.priceLockExpiresIn && !payload.terminal && payload.state === "awaiting_deposit") {
59852
+ out(` Price locked for ${payload.expiry.priceLockExpiresIn} ${dim("(native coin: do not send after this)")}`);
59853
+ }
59185
59854
  if (payload.payin?.txHash) out(` Pay-in ${payload.payin.txHash}`);
59186
59855
  if (payload.guidance) out(` ${payload.escalate ? red(payload.guidance) : dim(payload.guidance)}`);
59187
59856
  printMoneyWarning(payload);
@@ -59240,7 +59909,11 @@ async function cmdResume(opts) {
59240
59909
  if (payload.display?.hasMemo) {
59241
59910
  out(` Memo ${payload.display.receiverMemoMasked} ${dim(`(${payload.display.memoType})`)}`);
59242
59911
  }
59243
- if (payload.expiry?.expiresIn) out(` Expires in ${bold(payload.expiry.expiresIn)}`);
59912
+ if (payload.display?.native) {
59913
+ if (payload.expiry?.expiresIn) out(` Price locked for ${bold(payload.expiry.expiresIn)} more ${dim("(do not send after that)")}`);
59914
+ } else if (payload.expiry?.expiresIn) {
59915
+ out(` Expires in ${bold(payload.expiry.expiresIn)}`);
59916
+ }
59244
59917
  if (payload.paymentLink) out(` Pay page ${payload.paymentLink}`);
59245
59918
  out();
59246
59919
  }
@@ -59307,6 +59980,7 @@ async function cmdPay(opts) {
59307
59980
  let chosenPreset = null;
59308
59981
  let payer = null;
59309
59982
  let invoiceUsd = null;
59983
+ let isOffered = null;
59310
59984
  if (opts.bitrefill) {
59311
59985
  invoiceUsd = Number(opts.bitrefill.amount);
59312
59986
  } else if (!opts.source || opts.payer) {
@@ -59318,6 +59992,8 @@ async function cmdPay(opts) {
59318
59992
  return q.exitCode;
59319
59993
  }
59320
59994
  invoiceUsd = Number(q.payload.invoice?.amount);
59995
+ const offered = new Set((q.payload.nativeOffered ?? []).map((n) => `${n.chainId}:${n.tokenSymbol}`));
59996
+ isOffered = (chainId2, tokenSymbol2) => offered.has(`${chainId2}:${String(tokenSymbol2).toUpperCase()}`);
59321
59997
  }
59322
59998
  if (!opts.source) {
59323
59999
  if (!process.stdin.isTTY || opts.json) {
@@ -59326,7 +60002,7 @@ async function cmdPay(opts) {
59326
60002
  "No coin specified. Pass --with (e.g. --with usdt-solana), or run this on a terminal to choose from a list. There is no default."
59327
60003
  );
59328
60004
  }
59329
- const picked = await pickSource({ invoiceUsd, saved, fresh: opts.fresh });
60005
+ const picked = await pickSource({ invoiceUsd, saved, fresh: opts.fresh, isOffered });
59330
60006
  opts.source = { chainId: picked.chainId, tokenSymbol: picked.tokenSymbol };
59331
60007
  chosenPreset = picked.preset;
59332
60008
  payer = picked.payer;
@@ -59336,27 +60012,42 @@ async function cmdPay(opts) {
59336
60012
  throw new CliError("BAD_PAYER_ADDRESS", "That is not a recognisable EVM, Solana or Stellar address.");
59337
60013
  }
59338
60014
  assertNotBlacklisted([{ address: opts.payer, family, role: "wallet address" }], loadBlacklist());
59339
- const result = await fetchWalletOptions({ address: opts.payer, usdRequired: invoiceUsd });
59340
- if (isProvablyShort(opts.source, result)) {
59341
- throw new SkillErrorLike(
59342
- "INSUFFICIENT_BALANCE",
59343
- `${opts.payer.slice(0, 6)}\u2026${opts.payer.slice(-4)} does not appear to hold enough ${opts.source.tokenSymbol} for a $${invoiceUsd} invoice. Choose another coin, or omit --payer to proceed anyway from a different wallet.`
59344
- );
59345
- }
59346
- if (!result.ok && !opts.json) {
59347
- out(` ${yellow(`Could not check balances (${result.reason}). Continuing.`)}`);
59348
- } else if (result.ok && !opts.json) {
59349
- const hit = (result.options ?? []).find(
59350
- (o) => o.chainId === String(opts.source.chainId) && o.tokenSymbol === String(opts.source.tokenSymbol).toUpperCase()
59351
- );
60015
+ if (isNativeSource(opts.source.chainId, opts.source.tokenSymbol)) {
60016
+ const n = await fetchNativeBalance({ chainId: opts.source.chainId, address: opts.payer });
59352
60017
  const short = `${opts.payer.slice(0, 6)}\u2026${opts.payer.slice(-4)}`;
59353
- if (hit?.balanceUsd != null) {
59354
- out(` ${dim(`Payer ${short} holds about $${hit.balanceUsd} of ${opts.source.tokenSymbol} \u2014 enough for this invoice.`)}`);
59355
- } else {
59356
- out(` ${dim(`Payer ${short}: balance not reported for this coin, so it was not verified.`)}`);
60018
+ if (n.ok && n.balanceAtomic === 0n) {
60019
+ throw new SkillErrorLike(
60020
+ "INSUFFICIENT_BALANCE",
60021
+ `${short} holds no ${opts.source.tokenSymbol} on ${chainName(opts.source.chainId)}. Choose another coin, or omit --payer to proceed anyway from a different wallet.`
60022
+ );
60023
+ }
60024
+ if (!opts.json) {
60025
+ out(` ${dim(n.ok ? `Payer ${short} holds ${formatNativeHeld(n)}; checked against the exact amount once the order is priced.` : `Payer ${short}: ${opts.source.tokenSymbol} balance not checked (${n.reason}).`)}`);
60026
+ }
60027
+ payer = { address: opts.payer, family };
60028
+ } else {
60029
+ const result = await fetchWalletOptions({ address: opts.payer, usdRequired: invoiceUsd });
60030
+ if (isProvablyShort(opts.source, result)) {
60031
+ throw new SkillErrorLike(
60032
+ "INSUFFICIENT_BALANCE",
60033
+ `${opts.payer.slice(0, 6)}\u2026${opts.payer.slice(-4)} does not appear to hold enough ${opts.source.tokenSymbol} for a $${invoiceUsd} invoice. Choose another coin, or omit --payer to proceed anyway from a different wallet.`
60034
+ );
60035
+ }
60036
+ if (!result.ok && !opts.json) {
60037
+ out(` ${yellow(`Could not check balances (${result.reason}). Continuing.`)}`);
60038
+ } else if (result.ok && !opts.json) {
60039
+ const hit = (result.options ?? []).find(
60040
+ (o) => o.chainId === String(opts.source.chainId) && o.tokenSymbol === String(opts.source.tokenSymbol).toUpperCase()
60041
+ );
60042
+ const short = `${opts.payer.slice(0, 6)}\u2026${opts.payer.slice(-4)}`;
60043
+ if (hit?.balanceUsd != null) {
60044
+ out(` ${dim(`Payer ${short} holds about $${hit.balanceUsd} of ${opts.source.tokenSymbol} \u2014 enough for this invoice.`)}`);
60045
+ } else {
60046
+ out(` ${dim(`Payer ${short}: balance not reported for this coin, so it was not verified.`)}`);
60047
+ }
59357
60048
  }
60049
+ payer = { address: opts.payer, family };
59358
60050
  }
59359
- payer = { address: opts.payer, family };
59360
60051
  }
59361
60052
  const { chainId, tokenSymbol } = opts.source;
59362
60053
  const createFlow = opts.bitrefill ? run3 : run2;
@@ -59420,8 +60111,14 @@ async function cmdPay(opts) {
59420
60111
  out(` Memo ${p.display.receiverMemoMasked} ${dim(`(${p.display.memoType})`)}`);
59421
60112
  }
59422
60113
  const deadline = formatDeadline(p.expiry?.effectiveDeadlineIso);
59423
- out(` Expires ${bold(deadline ?? `in ${p.expiry?.expiresIn ?? "?"}`)}`);
59424
- out(` ${dim("After that this order cannot be used and a new one must be created.")}`);
60114
+ if (p.display?.native) {
60115
+ out(` Price ${bold(`locked ${deadline ?? `for ${p.expiry?.expiresIn ?? "?"}`}`)}`);
60116
+ out(` ${dim("Send exactly this amount before then. After that, do not send it: start a new order.")}`);
60117
+ out(` ${dim("The coin amount includes an FX spread on top of the service fee.")}`);
60118
+ } else {
60119
+ out(` Expires ${bold(deadline ?? `in ${p.expiry?.expiresIn ?? "?"}`)}`);
60120
+ out(` ${dim("After that this order cannot be used and a new one must be created.")}`);
60121
+ }
59425
60122
  out(
59426
60123
  p.reused ? ` ${dim(`Reusing existing unpaid order ${p.rozoPaymentId} \u2014 nothing new was created.`)}` : ` ${dim(`Order created: ${p.rozoPaymentId}`)}`
59427
60124
  );
@@ -59438,6 +60135,39 @@ async function cmdPay(opts) {
59438
60135
  for (const w of p.confirmation?.warnings ?? []) out(dim(` \xB7 ${w}`));
59439
60136
  out();
59440
60137
  }
60138
+ if (payer && p.display?.native && p.display?.coinAmount) {
60139
+ const n = await fetchNativeBalance({ chainId, address: payer.address });
60140
+ if (n.ok) {
60141
+ let amountAtomic = null;
60142
+ try {
60143
+ amountAtomic = toAtomic(p.display.coinAmount, decimalsFor(chainId, tokenSymbol));
60144
+ } catch {
60145
+ amountAtomic = null;
60146
+ }
60147
+ if (amountAtomic !== null) {
60148
+ const verdict = assessNative({ balanceAtomic: n.balanceAtomic, headroomAtomic: n.headroomAtomic, amountAtomic });
60149
+ const short = `${payer.address.slice(0, 6)}\u2026${payer.address.slice(-4)}`;
60150
+ const need = `${p.display.coinAmount} ${tokenSymbol} plus about ${formatAtomic(n.headroomAtomic, n.decimals)} ${tokenSymbol} for gas`;
60151
+ if (verdict.mark === "insufficient" && opts.payer && !chosenPreset) {
60152
+ const payload = formatFailure({
60153
+ code: "INSUFFICIENT_BALANCE",
60154
+ message: `${short} holds ${formatNativeHeld(n)}; this order needs ${need}. Nothing was sent. The unfunded order simply expires. Choose another coin, or omit --payer to pay from a different wallet.`
60155
+ });
60156
+ if (opts.json) printJson(payload);
60157
+ else printError(payload);
60158
+ return EXIT_ERROR;
60159
+ }
60160
+ if (!opts.json) {
60161
+ if (verdict.mark === "affordable") {
60162
+ out(` ${dim(`Payer ${short} holds ${formatNativeHeld(n)}: enough for ${need}.`)}`);
60163
+ } else {
60164
+ out(` ${yellow(`Payer ${short} holds ${formatNativeHeld(n)}, but this order needs ${need}.`)}`);
60165
+ }
60166
+ out();
60167
+ }
60168
+ }
60169
+ }
60170
+ }
59441
60171
  if (!opts.yes) {
59442
60172
  if (!process.stdin.isTTY) {
59443
60173
  const payload = formatFailure({
@@ -59578,7 +60308,13 @@ function printDeposit(deposit, opts) {
59578
60308
  ` Memo ${bold(deposit.receiverMemo)} ${red(`(required, ${deposit.receiverMemoType})`)}`
59579
60309
  );
59580
60310
  }
59581
- if (deposit.expiresIn) out(` Expires in ${bold(deposit.expiresIn)}`);
60311
+ if (deposit.native) {
60312
+ if (deposit.expiresIn) out(` Price locked for ${bold(deposit.expiresIn)} more`);
60313
+ const lock = formatDeadline(deposit.quoteExpiresAt);
60314
+ if (lock) out(` ${dim(`(${lock})`)}`);
60315
+ } else if (deposit.expiresIn) {
60316
+ out(` Expires in ${bold(deposit.expiresIn)}`);
60317
+ }
59582
60318
  }
59583
60319
  out();
59584
60320
  const unit = isSatsUnit(deposit.amountUnit) ? "sats" : deposit.tokenSymbol;
@@ -59586,6 +60322,11 @@ function printDeposit(deposit, opts) {
59586
60322
  out(
59587
60323
  ` Make sure the wallet you pay from holds at least ${bold(`${deposit.amount} ${unit}`)} ${where}.`
59588
60324
  );
60325
+ if (deposit.native) {
60326
+ out(dim(` Plus a little ${deposit.tokenSymbol} for the network fee. The amount that arrives must be`));
60327
+ out(dim(" exactly the amount above: from an exchange, check its withdrawal fee is not taken from it."));
60328
+ out(dim(" After the price lock ends, do not send: start a new order."));
60329
+ }
59589
60330
  out(dim(" Copy the address from this block; do not retype it."));
59590
60331
  out(dim(" Send it exactly once."));
59591
60332
  out();