abstract-signer.js 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.VoidSigner = exports.AbstractSigner = void 0;
  4. /**
  5. * Generally the [[Wallet]] and [[JsonRpcSigner]] and their sub-classes
  6. * are sufficent for most developers, but this is provided to
  7. * fascilitate more complex Signers.
  8. *
  9. * @_section: api/providers/abstract-signer: Subclassing Signer [abstract-signer]
  10. */
  11. const index_js_1 = require("../address/index.js");
  12. const index_js_2 = require("../transaction/index.js");
  13. const index_js_3 = require("../utils/index.js");
  14. const provider_js_1 = require("./provider.js");
  15. function checkProvider(signer, operation) {
  16. if (signer.provider) {
  17. return signer.provider;
  18. }
  19. (0, index_js_3.assert)(false, "missing provider", "UNSUPPORTED_OPERATION", { operation });
  20. }
  21. async function populate(signer, tx) {
  22. let pop = (0, provider_js_1.copyRequest)(tx);
  23. if (pop.to != null) {
  24. pop.to = (0, index_js_1.resolveAddress)(pop.to, signer);
  25. }
  26. if (pop.from != null) {
  27. const from = pop.from;
  28. pop.from = Promise.all([
  29. signer.getAddress(),
  30. (0, index_js_1.resolveAddress)(from, signer)
  31. ]).then(([address, from]) => {
  32. (0, index_js_3.assertArgument)(address.toLowerCase() === from.toLowerCase(), "transaction from mismatch", "tx.from", from);
  33. return address;
  34. });
  35. }
  36. else {
  37. pop.from = signer.getAddress();
  38. }
  39. return await (0, index_js_3.resolveProperties)(pop);
  40. }
  41. /**
  42. * An **AbstractSigner** includes most of teh functionality required
  43. * to get a [[Signer]] working as expected, but requires a few
  44. * Signer-specific methods be overridden.
  45. *
  46. */
  47. class AbstractSigner {
  48. /**
  49. * The provider this signer is connected to.
  50. */
  51. provider;
  52. /**
  53. * Creates a new Signer connected to %%provider%%.
  54. */
  55. constructor(provider) {
  56. (0, index_js_3.defineProperties)(this, { provider: (provider || null) });
  57. }
  58. async getNonce(blockTag) {
  59. return checkProvider(this, "getTransactionCount").getTransactionCount(await this.getAddress(), blockTag);
  60. }
  61. async populateCall(tx) {
  62. const pop = await populate(this, tx);
  63. return pop;
  64. }
  65. async populateTransaction(tx) {
  66. const provider = checkProvider(this, "populateTransaction");
  67. const pop = await populate(this, tx);
  68. if (pop.nonce == null) {
  69. pop.nonce = await this.getNonce("pending");
  70. }
  71. if (pop.gasLimit == null) {
  72. pop.gasLimit = await this.estimateGas(pop);
  73. }
  74. // Populate the chain ID
  75. const network = await (this.provider).getNetwork();
  76. if (pop.chainId != null) {
  77. const chainId = (0, index_js_3.getBigInt)(pop.chainId);
  78. (0, index_js_3.assertArgument)(chainId === network.chainId, "transaction chainId mismatch", "tx.chainId", tx.chainId);
  79. }
  80. else {
  81. pop.chainId = network.chainId;
  82. }
  83. // Do not allow mixing pre-eip-1559 and eip-1559 properties
  84. const hasEip1559 = (pop.maxFeePerGas != null || pop.maxPriorityFeePerGas != null);
  85. if (pop.gasPrice != null && (pop.type === 2 || hasEip1559)) {
  86. (0, index_js_3.assertArgument)(false, "eip-1559 transaction do not support gasPrice", "tx", tx);
  87. }
  88. else if ((pop.type === 0 || pop.type === 1) && hasEip1559) {
  89. (0, index_js_3.assertArgument)(false, "pre-eip-1559 transaction do not support maxFeePerGas/maxPriorityFeePerGas", "tx", tx);
  90. }
  91. if ((pop.type === 2 || pop.type == null) && (pop.maxFeePerGas != null && pop.maxPriorityFeePerGas != null)) {
  92. // Fully-formed EIP-1559 transaction (skip getFeeData)
  93. pop.type = 2;
  94. }
  95. else if (pop.type === 0 || pop.type === 1) {
  96. // Explicit Legacy or EIP-2930 transaction
  97. // We need to get fee data to determine things
  98. const feeData = await provider.getFeeData();
  99. (0, index_js_3.assert)(feeData.gasPrice != null, "network does not support gasPrice", "UNSUPPORTED_OPERATION", {
  100. operation: "getGasPrice"
  101. });
  102. // Populate missing gasPrice
  103. if (pop.gasPrice == null) {
  104. pop.gasPrice = feeData.gasPrice;
  105. }
  106. }
  107. else {
  108. // We need to get fee data to determine things
  109. const feeData = await provider.getFeeData();
  110. if (pop.type == null) {
  111. // We need to auto-detect the intended type of this transaction...
  112. if (feeData.maxFeePerGas != null && feeData.maxPriorityFeePerGas != null) {
  113. // The network supports EIP-1559!
  114. // Upgrade transaction from null to eip-1559
  115. pop.type = 2;
  116. if (pop.gasPrice != null) {
  117. // Using legacy gasPrice property on an eip-1559 network,
  118. // so use gasPrice as both fee properties
  119. const gasPrice = pop.gasPrice;
  120. delete pop.gasPrice;
  121. pop.maxFeePerGas = gasPrice;
  122. pop.maxPriorityFeePerGas = gasPrice;
  123. }
  124. else {
  125. // Populate missing fee data
  126. if (pop.maxFeePerGas == null) {
  127. pop.maxFeePerGas = feeData.maxFeePerGas;
  128. }
  129. if (pop.maxPriorityFeePerGas == null) {
  130. pop.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
  131. }
  132. }
  133. }
  134. else if (feeData.gasPrice != null) {
  135. // Network doesn't support EIP-1559...
  136. // ...but they are trying to use EIP-1559 properties
  137. (0, index_js_3.assert)(!hasEip1559, "network does not support EIP-1559", "UNSUPPORTED_OPERATION", {
  138. operation: "populateTransaction"
  139. });
  140. // Populate missing fee data
  141. if (pop.gasPrice == null) {
  142. pop.gasPrice = feeData.gasPrice;
  143. }
  144. // Explicitly set untyped transaction to legacy
  145. // @TODO: Maybe this shold allow type 1?
  146. pop.type = 0;
  147. }
  148. else {
  149. // getFeeData has failed us.
  150. (0, index_js_3.assert)(false, "failed to get consistent fee data", "UNSUPPORTED_OPERATION", {
  151. operation: "signer.getFeeData"
  152. });
  153. }
  154. }
  155. else if (pop.type === 2 || pop.type === 3) {
  156. // Explicitly using EIP-1559 or EIP-4844
  157. // Populate missing fee data
  158. if (pop.maxFeePerGas == null) {
  159. pop.maxFeePerGas = feeData.maxFeePerGas;
  160. }
  161. if (pop.maxPriorityFeePerGas == null) {
  162. pop.maxPriorityFeePerGas = feeData.maxPriorityFeePerGas;
  163. }
  164. }
  165. }
  166. //@TOOD: Don't await all over the place; save them up for
  167. // the end for better batching
  168. return await (0, index_js_3.resolveProperties)(pop);
  169. }
  170. async estimateGas(tx) {
  171. return checkProvider(this, "estimateGas").estimateGas(await this.populateCall(tx));
  172. }
  173. async call(tx) {
  174. return checkProvider(this, "call").call(await this.populateCall(tx));
  175. }
  176. async resolveName(name) {
  177. const provider = checkProvider(this, "resolveName");
  178. return await provider.resolveName(name);
  179. }
  180. async sendTransaction(tx) {
  181. const provider = checkProvider(this, "sendTransaction");
  182. const pop = await this.populateTransaction(tx);
  183. delete pop.from;
  184. const txObj = index_js_2.Transaction.from(pop);
  185. return await provider.broadcastTransaction(await this.signTransaction(txObj));
  186. }
  187. }
  188. exports.AbstractSigner = AbstractSigner;
  189. /**
  190. * A **VoidSigner** is a class deisgned to allow an address to be used
  191. * in any API which accepts a Signer, but for which there are no
  192. * credentials available to perform any actual signing.
  193. *
  194. * This for example allow impersonating an account for the purpose of
  195. * static calls or estimating gas, but does not allow sending transactions.
  196. */
  197. class VoidSigner extends AbstractSigner {
  198. /**
  199. * The signer address.
  200. */
  201. address;
  202. /**
  203. * Creates a new **VoidSigner** with %%address%% attached to
  204. * %%provider%%.
  205. */
  206. constructor(address, provider) {
  207. super(provider);
  208. (0, index_js_3.defineProperties)(this, { address });
  209. }
  210. async getAddress() { return this.address; }
  211. connect(provider) {
  212. return new VoidSigner(this.address, provider);
  213. }
  214. #throwUnsupported(suffix, operation) {
  215. (0, index_js_3.assert)(false, `VoidSigner cannot sign ${suffix}`, "UNSUPPORTED_OPERATION", { operation });
  216. }
  217. async signTransaction(tx) {
  218. this.#throwUnsupported("transactions", "signTransaction");
  219. }
  220. async signMessage(message) {
  221. this.#throwUnsupported("messages", "signMessage");
  222. }
  223. async signTypedData(domain, types, value) {
  224. this.#throwUnsupported("typed-data", "signTypedData");
  225. }
  226. }
  227. exports.VoidSigner = VoidSigner;
  228. //# sourceMappingURL=abstract-signer.js.map