@exodus/solana-lib 2.4.0 → 3.0.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@exodus/solana-lib",
3
- "version": "2.4.0",
3
+ "version": "3.0.0",
4
4
  "description": "Exodus internal Solana low-level library",
5
5
  "main": "src/index.js",
6
6
  "files": [
@@ -23,8 +23,8 @@
23
23
  "@exodus/currency": "^2.3.2",
24
24
  "@exodus/key-utils": "^3.1.0",
25
25
  "@exodus/models": "^10.1.0",
26
+ "@exodus/project-serum-serum": "0.13.64-exodus.0",
26
27
  "@exodus/solana-web3.js": "^1.63.1-exodus.3",
27
- "@project-serum/serum": "0.13.64",
28
28
  "bn.js": "^4.11.0",
29
29
  "borsh": "^0.7.0",
30
30
  "bs58": "^4.0.1",
@@ -40,5 +40,5 @@
40
40
  "@solana/web3.js": "^1.90.0",
41
41
  "bip39": "^2.6.0"
42
42
  },
43
- "gitHead": "02a052ff417b0c4d0379edf866b6a984ca6a4830"
43
+ "gitHead": "30fdc2a936b6776866467baf926c899e9a236beb"
44
44
  }
@@ -1,7 +1,7 @@
1
1
  import { createUnsignedTx } from './create-unsigned-tx'
2
2
  import { signUnsignedTx } from './sign-unsigned-tx'
3
3
 
4
- export function createAndSignTx(input, privateKey) {
4
+ export async function createAndSignTx(input, privateKey) {
5
5
  const unsignedTx = createUnsignedTx(input)
6
6
  return signUnsignedTx(unsignedTx, privateKey)
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import { ASSOCIATED_TOKEN_PROGRAM_ID, TOKEN_PROGRAM_ID } from '../helpers/spl-token'
2
- import { MARKETS, TokenInstructions } from '@project-serum/serum'
2
+ import { MARKETS, TokenInstructions } from '@exodus/project-serum-serum'
3
3
  import * as BufferLayout from '@exodus/buffer-layout'
4
4
 
5
5
  import { SystemInstruction, SystemProgram } from './../vendor'
@@ -1,9 +1,10 @@
1
1
  import assert from 'minimalistic-assert'
2
+ import * as nacl from 'tweetnacl'
3
+ import bs58 from 'bs58'
2
4
 
3
5
  import { prepareForSigning } from './prepare-for-signing'
4
6
  import { getKeyPairFromPrivateKey } from '../keypair'
5
- import { Account } from '../vendor'
6
- import { AsyncSignerAccount } from './async-account'
7
+ import { PublicKey } from '../vendor'
7
8
  import { extractTransaction, isVersionedTransaction } from './common'
8
9
 
9
10
  /**
@@ -17,49 +18,60 @@ export async function signUnsignedTxWithSigner(unsignedTx, signer) {
17
18
 
18
19
  const tx = prepareForSigning(unsignedTx)
19
20
 
20
- const account = new AsyncSignerAccount(signer)
21
- await account.updatePublicKey()
22
- await _signTx({ tx, account })
21
+ await _signTx({ tx, signer })
23
22
 
24
23
  return extractTransaction({ tx })
25
24
  }
26
25
 
27
- export function signUnsignedTx(unsignedTx, privateKey) {
26
+ export async function signUnsignedTx(unsignedTx, privateKey) {
28
27
  assert(privateKey, 'Please provide a secretKey')
29
28
 
30
29
  const tx = prepareForSigning(unsignedTx)
31
30
 
32
- const { secretKey } = getKeyPairFromPrivateKey(privateKey)
33
- const account = new Account(secretKey)
34
- _signTx({ tx, account })
31
+ const { secretKey, publicKey } = getKeyPairFromPrivateKey(privateKey)
32
+ const signer = {
33
+ getPublicKey: () => publicKey,
34
+ sign: ({ data }) => nacl.sign.detached(data, secretKey),
35
+ }
36
+ await _signTx({ tx, signer })
35
37
 
36
38
  return extractTransaction({ tx })
37
39
  }
38
40
 
39
41
  // Signs plain tx.
40
- const _signTx = ({ tx, account }) => {
42
+ const _signTx = async ({ tx, signer }) => {
43
+ const publicKey = new PublicKey(bs58.encode(Buffer.from(await signer.getPublicKey())))
44
+
41
45
  if (isVersionedTransaction(tx)) {
42
46
  // VersionedTransaction
43
- return tx.sign([account])
47
+ return _signVersionedTransaction({ tx, signer, publicKey })
44
48
  }
45
-
46
49
  // Legacy Transactions
47
50
 
48
51
  // Some transactions that we construct internally are technically not complete.
49
52
  // They don't contain the empty signature slot for the public key.
50
- const foundEmptySignatureSlot = tx.signatures.find(({ publicKey }) =>
51
- publicKey.equals(account.publicKey)
53
+ const foundEmptySignatureSlot = tx.signatures.find(({ publicKey: _publicKey }) =>
54
+ _publicKey.equals(publicKey)
52
55
  )
53
56
  if (!foundEmptySignatureSlot) {
54
57
  // We could use `setSigners` but maybe this is more robust?
55
58
  tx.signatures.push({
56
- publicKey: account.publicKey,
59
+ publicKey,
57
60
  signature: null,
58
61
  })
59
62
  }
60
63
 
61
- // We need to use `partialSign()` here because legacy `sign()` will
62
- // delete all existing signatures which isn't great if we're
63
- // signing a transaction that already has signatures.
64
- return tx.partialSign(account)
64
+ return _signLegacyTransaction({ tx, signer, publicKey })
65
+ }
66
+
67
+ const _signVersionedTransaction = async ({ tx, signer, publicKey }) => {
68
+ const messageData = tx.message.serialize()
69
+ const signature = await signer.sign({ data: messageData })
70
+ tx.addSignature(publicKey, signature)
71
+ }
72
+
73
+ const _signLegacyTransaction = async ({ tx, signer, publicKey }) => {
74
+ const messageData = tx.compileMessage().serialize()
75
+ const signature = await signer.sign({ data: messageData })
76
+ tx.addSignature(publicKey, signature)
65
77
  }
@@ -21,8 +21,6 @@ import * as shortvec from './utils/shortvec-encoding'
21
21
  const DEFAULT_SIGNATURE = Buffer.alloc(64).fill(0)
22
22
  const SIGNATURE_LENGTH = 64
23
23
 
24
- const isAsyncAccount = (signer) => signer.sign && signer.publicKey && signer.updatePublicKey
25
-
26
24
  /**
27
25
  * Account metadata used to define instructions
28
26
  *
@@ -436,21 +434,6 @@ export class Transaction {
436
434
  })
437
435
 
438
436
  const signData = message.serialize()
439
-
440
- const isAsyncSign = signers.some(isAsyncAccount)
441
- if (isAsyncSign) {
442
- return Promise.all(
443
- signers.map(async (signer) => ({
444
- signature: isAsyncAccount(signer)
445
- ? await signer.sign(signData) // Promise
446
- : nacl.sign.detached(signData, signer.secretKey),
447
- publicKey: signer.publicKey,
448
- }))
449
- ).then((signatures) =>
450
- signatures.forEach(({ publicKey, signature }) => this.addSignature(publicKey, signature))
451
- )
452
- }
453
-
454
437
  signers.forEach((signer) => {
455
438
  const signature = nacl.sign.detached(signData, signer.secretKey)
456
439
  this.addSignature(signer.publicKey, signature)
@@ -1,38 +0,0 @@
1
- import { PublicKey } from '../vendor/publickey'
2
-
3
- export class AsyncSignerAccount {
4
- #publicKey
5
- #asyncSigner
6
-
7
- /**
8
- * Create a new AsyncSignerAccount object
9
- *
10
- * @param asyncSigner A signer object: `{ sign, getPublicKey }`
11
- */
12
- constructor(asyncSigner) {
13
- if (!asyncSigner) throw new Error('please provide a signer object to async signer')
14
-
15
- this.#asyncSigner = asyncSigner
16
- this.updatePublicKey().catch((err) =>
17
- console.error('error getting public key from signer', err)
18
- )
19
- }
20
-
21
- get publicKey() {
22
- if (!this.#publicKey) throw new Error('public key not yet available in async signer')
23
- return this.#publicKey
24
- }
25
-
26
- get secretKey() {
27
- throw new Error('secret key not available from async signer')
28
- }
29
-
30
- sign = async (signData) => this.#asyncSigner.sign({ data: signData })
31
-
32
- updatePublicKey = async () => {
33
- if (!this.#publicKey) {
34
- const publicKey = await this.#asyncSigner.getPublicKey()
35
- this.#publicKey = new PublicKey(publicKey)
36
- }
37
- }
38
- }