Zondax / ledger-stacks

Apache License 2.0
17 stars 7 forks source link

Multisig token trasnfer with ledger #156

Open wangsai-silence opened 4 months ago

wangsai-silence commented 4 months ago

Hello. I had a problem during signing tx with ledger.

The core codes are like:

        let tx = params.tx

        let txOrigin = cloneDeep(tx)
        txOrigin.auth = intoInitialSighashAuth(txOrigin.auth)
        let id = txOrigin.txid()

       // create ledger connection inside
        await this.withTransport(async tp => {
            let stx = new Stacks(tp)

           // verify first signature and get new sigHash
            let { nextSigHash, pubKey } = nextVerification(id, AuthType.Standard, params.fee, params.nonce, PubKeyEncoding.Compressed, tx.auth.spendingCondition.fields[0].contents)
          // public key as expected
            console.log('pk1', publicKeyToString(pubKey))

            let signature1 = tx.auth.spendingCondition.fields[0].contents.data
            let content = Buffer.concat([
                Buffer.from(tx.serialize()),
                Buffer.from(nextSigHash, 'hex'),
                Buffer.from(Uint8Array.from([PubKeyEncoding.Compressed])),
                Buffer.from(signature1, 'hex')
            ])

            let resp = await stx.sign(params.path, content)

            if (resp.returnCode !== LedgerError.NoErrors) {
                throw new Error(resp.errorMessage)
            }

            let signature = createMessageSignature(Buffer.from(resp.signatureVRS).toString('hex'))
            tx.auth.spendingCondition.fields.push(createTransactionAuthField(PubKeyEncoding.Compressed, signature))

            let { pubKey: pk2 } = nextVerification(nextSigHash, AuthType.Standard, params.fee, params.nonce, PubKeyEncoding.Compressed, signature)
            // got wrong public key when signing contract call transaction
            console.log('pk2', publicKeyToString(pk2))
        })

I used a external key pair and a key pair from ledger to create a 2-2 multisig address. After signed by external key, I tried to use ledger to sign the tx. It will sucess if the tx is STXTokenTransfer, and will failed if the tx is ContractCall

contract call(transfer token) raw tx after first sign

80800000000401a03247752536624ab5c0e1618278a5d2ad0a0d0800000000000000020000000000000190000000010201416ae170ea90837175b68251de8aa8df83e310cfc1356123763d9be293df362576fbdfea827b09d436eb1294dd72f46dd956beec82b9145bec704bab8de3cb0700020302000000010102154edd2adc7eafc16b2b8dfced1aeeb465e06cdeae1a60718ab27d203015cc8697ccc610d70bedc09f7f0e66756e6769626c652d746f6b656e0c636c61726974792d636f696e010000000000000064021a60718ab27d203015cc8697ccc610d70bedc09f7f0e66756e6769626c652d746f6b656e087472616e7366657200000004010000000000000000000000000000006405154edd2adc7eafc16b2b8dfced1aeeb465e06cdeae051a6bc6d849b4cf56cfeeef215913f08829ff2a2a3909

:link: zboto Link

neithanmo commented 2 weeks ago

@jbencin can this be closed thanks to your changes in #152 ?

jbencin commented 2 weeks ago

It's possible that my PR fixes this, as there were general issues with signing multisig transactions after the first signer. But if there is some bug with the Ledger handling multisig for STXTokenTransfer differently from ContractCall, then my PR wouldn't have fixed that

I have not personally tested the new code with anything other than an STXTokenTransfer. I think it may have been used by others to stack STX from multisig accounts, so I'll ask around

fess-v commented 2 weeks ago

Hey @neithanmo @jbencin we've been testing it through Asigna and it was completely fine https://ledger-stacks.dev.asigna.io/ you can try it out here + asigna extension from the store, connect ledger, and use the extension to connect to any Stacks app, easy to check and verify smart contract calls