solana-web3.js: `rpc.sendTransaction().send()` doesn't make logical sense.

I’m not sure if this is bug or a feature request. Essentially it feels like a DX bug.

Overview

From Stephen’s refactor of Andy’s code:

const signature = await rpc
  .sendTransaction(encodedTX, { encoding: "base64" })
  .send();

According to the function name sendTransaction(), the transaction has already been sent. It shouldn’t be necessary or even possible to send() a transaction that was previously sent. On the surface, reading the function names, this looks like an attempt to double spend.

Possible Solutions

On the surface - if sendTransaction() doesn’t actually send the transaction - an immediate fix would be to rename the function to createTransaction:

const signature = await rpc
  .createTransaction(encodedTX, { encoding: "base64" })
  .send();

However the code for sendTransaction() says:

Submits a signed transaction to the cluster for processing.

and

The returned signature is the first signature in the transaction

Which seems to imply that the subsequent send() in Stephen’s code isn’t necessary.

About this issue

  • Original URL
  • State: closed
  • Created 9 months ago
  • Comments: 16 (6 by maintainers)

Most upvoted comments

I think .send() reads better and makes the most sense for 99% of the RPC methods. It’s only awkward for sendTransaction due to the double “send” which is confusing. However, that’s a pattern we’re already identifying with the RPC method that requests an airdrop. Following the same naming convention here would make the API more predictable.

// Reading from the cluster.
rpc.getAccountInfo().send();
rpc.isBlockhashValid().send();

// Writing to the cluster.
rpc.requestAirdrop().send();
rpc.requestTransaction().send(); // "requestSendTransaction" if it's not clear enough.

What do you think?

True re: many users using high level wrappers. But even people wanting to interact with RPC methods directly should see a logical API - with ‘send’ have a consistent definition between:

  • create an objects that asks the RPC to do process a transaction with a given configuration
  • actually get the blockchain to run that transaction

I hope this issue doesn’t seem nitpicky - my main concern is to:

  • avoid user confusion.

    “You always need to exec()” is better than “You always need to send(), and sendTransaction() doesn’t send().”

  • make the API stable by avoiding changes after such a major refactor.

Personally I think if we fixate on sendTransaction it sounds a bit strange, but for every over method it makes sense, so I’m inclined to leave it as send(). send() makes more sense to me than any other alternative keyword for sending a payload across an HTTP transport.

Taking some inspiration from Postman, I think it is a valid way to describe what the API is doing.

Gotcha! exec does make sense in the context of transactions, but I’m not sure about some of the other RPC methods. The vast majority are getXYZ with very few actually changing state. Both run and exec feel a bit too active to me for most of the calls, but that’s maybe a bit nitpicky! Technically we could have multiple aliases for this function FWIW, but I think that’d just make things more confusing.

const block = await rpc.getBlock(430).run()
const block = await rpc.getBlock(430).exec()

Sorry @mcintyre94 I wrote my comment at the time as you were writing yours - I don’t want you to think I ignored you!

I’ve since read your point about

sendTransaction comes directly from the RPC method being used, and that’s consistent for all methods.

Understood the function name needs to match the RPC name.

And I’m not sure there’s a better name than send() that doesn’t clash with any of the RPC method names.

.run() or .exec()?

In context.

const signature = await rpc
  .sendTransaction(encodedTX, { encoding: "base64" })
  .run();

or

const signature = await rpc
  .sendTransaction(encodedTX, { encoding: "base64" })
  .exec();

Maybe exec() feels a little nicer, since in common parlance transactions are executed more than they are ran (or sent). Eg "The broker executed the trade at the best available price.”

WDYT? 🤔