@exodus/solana-lib 2.3.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.3.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,7 +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
- "@project-serum/serum": "0.13.64",
26
+ "@exodus/project-serum-serum": "0.13.64-exodus.0",
27
+ "@exodus/solana-web3.js": "^1.63.1-exodus.3",
27
28
  "bn.js": "^4.11.0",
28
29
  "borsh": "^0.7.0",
29
30
  "bs58": "^4.0.1",
@@ -39,5 +40,5 @@
39
40
  "@solana/web3.js": "^1.90.0",
40
41
  "bip39": "^2.6.0"
41
42
  },
42
- "gitHead": "5be11b271fd14c54f4fe8dd04b146361100e2a4d"
43
+ "gitHead": "30fdc2a936b6776866467baf926c899e9a236beb"
43
44
  }
package/src/index.js CHANGED
@@ -2,6 +2,7 @@ export * from './constants'
2
2
  export * from './encode'
3
3
  export * from './keypair'
4
4
  export * from './tx'
5
+ export * from './msg'
5
6
  export * from './fee-data'
6
7
  export {
7
8
  TransactionInstruction,
@@ -0,0 +1,2 @@
1
+ export { signMessage } from './sign-message-deprecated'
2
+ export { signMessageNew } from './sign-message'
@@ -0,0 +1,20 @@
1
+ import assert from 'assert'
2
+ import nacl from 'tweetnacl'
3
+ import bs58 from 'bs58'
4
+
5
+ import { isTransactionMessage } from './validation'
6
+ import { getKeyPairFromPrivateKey } from '../keypair'
7
+
8
+ /**
9
+ * @deprecated please use messageSigner
10
+ */
11
+ export function signMessage({ message, privateKey }) {
12
+ const { secretKey } = getKeyPairFromPrivateKey(privateKey)
13
+ const messageBuffer = bs58.decode(message)
14
+ assert(
15
+ !isTransactionMessage(messageBuffer),
16
+ 'attempted to sign transaction using message signing'
17
+ )
18
+ const signature = nacl.sign.detached(messageBuffer, secretKey)
19
+ return bs58.encode(signature)
20
+ }
@@ -0,0 +1,19 @@
1
+ import assert from 'minimalistic-assert'
2
+ import * as nacl from 'tweetnacl'
3
+
4
+ import { isTransactionMessage } from './validation'
5
+
6
+ export const signMessageNew = async ({ privateKey, message }) => {
7
+ const { rawMessage } = message
8
+ assert(Buffer.isBuffer(rawMessage), `rawMessage must be buffer`)
9
+ assert(
10
+ !isTransactionMessage(rawMessage),
11
+ `malicious message signing request, was a transaction message`
12
+ )
13
+ assert(
14
+ Buffer.isBuffer(privateKey) || privateKey instanceof Uint8Array,
15
+ `privateKey is not a Buffer or Uint8Array`
16
+ )
17
+
18
+ return Buffer.from(nacl.sign.detached(rawMessage, privateKey))
19
+ }
@@ -1,10 +1,10 @@
1
- import assert from 'assert'
2
- import nacl from 'tweetnacl'
3
- import bs58 from 'bs58'
4
-
5
- import { Message } from '../vendor/message'
6
- import { getKeyPairFromPrivateKey } from '../keypair'
1
+ import { Message } from '@exodus/solana-web3.js'
7
2
 
3
+ /**
4
+ * Checks if its contains a legacy message.
5
+ * @param {Uint8Array} data
6
+ * @returns {boolean}
7
+ */
8
8
  function isLegacyMessage(data) {
9
9
  try {
10
10
  const message = Message.from(data)
@@ -15,6 +15,11 @@ function isLegacyMessage(data) {
15
15
  }
16
16
  }
17
17
 
18
+ /**
19
+ * Checks if its contains a versioned message.
20
+ * @param {Uint8Array} data
21
+ * @returns {boolean}
22
+ */
18
23
  function isVersionedMessage(data) {
19
24
  if (data.length > 1) {
20
25
  // We deploy a heuristic to detect transaction messages.
@@ -27,18 +32,12 @@ function isVersionedMessage(data) {
27
32
  return false
28
33
  }
29
34
 
35
+ /**
36
+ * Check whether a message contains a transaction message.
37
+ * @param {Uint8Array} data
38
+ * @returns {boolean}
39
+ */
30
40
  export function isTransactionMessage(data) {
31
41
  const messageBuffer = Buffer.from(data)
32
42
  return isLegacyMessage(messageBuffer) || isVersionedMessage(messageBuffer)
33
43
  }
34
-
35
- export default function signMessage({ message, privateKey }) {
36
- const { secretKey } = getKeyPairFromPrivateKey(privateKey)
37
- const messageBuffer = bs58.decode(message)
38
- assert(
39
- !isTransactionMessage(messageBuffer),
40
- 'attempted to sign transaction using message signing'
41
- )
42
- const signature = nacl.sign.detached(messageBuffer, secretKey)
43
- return bs58.encode(signature)
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'
package/src/tx/index.js CHANGED
@@ -8,4 +8,3 @@ export * from './build-raw-transaction'
8
8
  export * from './sign-hardware'
9
9
  export * from './prepare-for-signing'
10
10
  export { transactionToBase58 } from './common'
11
- export { default as signMessage } from './sign-message'
@@ -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
- }