Skip to content

Invalid Signature #27

@Cyrano71

Description

@Cyrano71

Hi,

I have studied the code you use to create a signature :

https://github.com/etherdelta/bots/blob/master/js/service.js

 const sign = (msgToSignIn, privateKeyIn) => {
      const prefixMessage = (msgIn) => {
        let msg = msgIn;
        msg = new Buffer(msg.slice(2), 'hex');
        msg = Buffer.concat([
          new Buffer(`\x19Ethereum Signed Message:\n${msg.length.toString()}`),
          msg]);
        msg = self.web3.sha3(`0x${msg.toString('hex')}`, { encoding: 'hex' });
        msg = new Buffer(msg.slice(2), 'hex');
        return `0x${msg.toString('hex')}`;
      };
      const privateKey = privateKeyIn.substring(0, 2) === '0x' ?
        privateKeyIn.substring(2, privateKeyIn.length) : privateKeyIn;
      const msgToSign = prefixMessage(msgToSignIn);
      try {
        const sig = ethUtil.ecsign(
          new Buffer(msgToSign.slice(2), 'hex'),
          new Buffer(privateKey, 'hex'));
        const r = `0x${sig.r.toString('hex')}`;
        const s = `0x${sig.s.toString('hex')}`;
        const v = sig.v;
        const result = { r, s, v, msg: msgToSign };
        return result;
      } catch (err) {
        throw new Error(err);
      }
    };

With that I have modified the function CreateOrder in the c# Bot, because the signature mechanism didn't work :

internal Order CreateOrder(OrderType orderType, BigInteger expires, BigInteger price, BigInteger amount)
        {
            if (Config.PrivateKey.Length != 64)
                throw new Exception("WARNING: user_wallet_private_key must be a hexadecimal string of 64 characters long");

            var uc = new UnitConversion();

            var amountBigNum = amount;
            var amountBaseBigNum = (amount * price) / uc.ToWei(1);
            var tokenGet = orderType == OrderType.Buy ? Config.Token : ZeroToken;
            var tokenGive = orderType == OrderType.Sell ? Config.Token : ZeroToken;
            var amountGet = orderType == OrderType.Buy ? amountBigNum : amountBaseBigNum;
            var amountGive = orderType == OrderType.Sell ? amountBigNum : amountBaseBigNum;
            var orderNonce = new Random().Next();

            var contractAddr = Web3.ToChecksumAddress(Config.AddressEtherDelta);
            tokenGet = Web3.ToChecksumAddress(tokenGet);
            tokenGive = Web3.ToChecksumAddress(tokenGive);
            var user = Web3.ToChecksumAddress(Config.User);

            /*
            * First Step : Hash the order
            */
            var plainData = new object[]
                            {
                                contractAddr,
                                tokenGet,
                                amountGet,
                                tokenGive,
                                amountGive,
                                expires,
                                orderNonce
                            };


            var prms = new[] {
                new Parameter("address",1),
                new Parameter("address",1),
                new Parameter("uint256",1),
                new Parameter("address",1),
                new Parameter("uint256",1),
                new Parameter("uint256",1),
                new Parameter("uint256",1)
            };

            var pe = new ParametersEncoder();
            var data = pe.EncodeParameters(prms, plainData);

            var ms = new MessageSigner();
            var messageHashBytes = ms.Hash(data);

            /*
             * Second step : create the ethSignaturePrefixx
             */
            var ethSignaturePrefixByteArray = Encoding.ASCII.GetBytes($"\u0019Ethereum Signed Message:\n{messageHashBytes.Length}");

            /*
             * Third Step : add the ethPrefix to the hashBytes and hash again
             */       
            int length = ethSignaturePrefixByteArray.Length + messageHashBytes.Length;
            byte[] sum = new byte[length];

            ethSignaturePrefixByteArray.CopyTo(sum, 0);
            messageHashBytes.CopyTo(sum, ethSignaturePrefixByteArray.Length);

            var signatureBase = ms.Hash(sum);

            /*
             * Fourth Step : Sign the message
             * I have created a custom function CreateStringSignature2
             * CreateStringSignature2 is the same function that CreateStringSignature in Nethereum
             * the only difference is that CreateStringSignature2 is public
            */
            var key = new EthECKey(Config.PrivateKey.HexToByteArray(), true);
            var signature = CreateStringSignature2(key.SignAndCalculateV(signatureBase));
            var ethEcdsa = MessageSigner.ExtractEcdsaSignature(signature);

            /*
             * Fifth Step : Create the order
             */
            var order = new Order
            {
                AmountGet = new HexBigInteger(amountGet),
                AmountGive = new HexBigInteger(amountGive),
                TokenGet = tokenGet,
                TokenGive = tokenGive,
                ContractAddr = contractAddr,
                Expires = expires,
                Nonce = orderNonce,
                User = user,
                V = ethEcdsa.V,
                R = ethEcdsa.R.ToHex(true),
                S = ethEcdsa.S.ToHex(true)
            };

            /*
             * Checking Signature
             */

            /*
             * First Step : Create a Fake WebSocket Message
             */
            var message = new Message
            {
                Event = "message",
                Data = new
                {
                    amountGive = order.AmountGive.Value,
                    tokenGive = order.TokenGive,
                    amountGet = order.AmountGet.Value,
                    tokenGet = order.TokenGet,
                    contractAddr = Config.AddressEtherDelta,
                    expires = order.Expires,
                    nonce = order.Nonce,
                    user = order.User,
                    v = order.V,
                    r = order.R,
                    s = order.S,
                }
            }.ToString();

            /*
             * Second Step : Hash the message
             */
            Message messageParsed = Message.ParseMessage(message);

            var orderChecking = (JObject)messageParsed.Data;

            plainData = new object[]
                            {
                                Web3.ToChecksumAddress(orderChecking["contractAddr"].ToString()),
                                Web3.ToChecksumAddress(orderChecking["tokenGet"].ToString()),
                                new BigInteger((decimal)orderChecking["amountGet"]),
                                Web3.ToChecksumAddress(orderChecking["tokenGive"].ToString()),
                                new BigInteger((decimal)orderChecking["amountGive"]),
                                new BigInteger((decimal)orderChecking["expires"]),
                                new BigInteger((decimal)orderChecking["nonce"]),
                            };


            prms = new[] {
                                 new Parameter("address",1),
                                 new Parameter("address",1),
                                 new Parameter("uint256",1),
                                 new Parameter("address",1),
                                 new Parameter("uint256",1),
                                 new Parameter("uint256",1),
                                 new Parameter("uint256",1)
                             };

            pe = new ParametersEncoder();
            data = pe.EncodeParameters(prms, plainData);

            messageHashBytes = ms.Hash(data);

            /*
             * Third step : create the ethSignaturePrefix
            */
            ethSignaturePrefixByteArray = Encoding.ASCII.GetBytes($"\u0019Ethereum Signed Message:\n{messageHashBytes.Length}");

            /*
            * Fourth Step : add the ethPrefix to the hashBytes and hash again
            */
            length = ethSignaturePrefixByteArray.Length + messageHashBytes.Length;
            sum = new byte[length];

            ethSignaturePrefixByteArray.CopyTo(sum, 0);
            messageHashBytes.CopyTo(sum, ethSignaturePrefixByteArray.Length);

            signatureBase = ms.Hash(sum);

            /*
             * Retreive the public key and compare
             */
            string publicKey = ms.EcRecover(signatureBase, signature);

            if (publicKey.ToLower() != Config.User.ToLower())
                throw new Exception("WARNING: incorect signature");

            return order;
        }

At the end of the function I check if the publickey that I have retreived from the signature matchs my public key and it works. But as soon as I send the message via the websocket I have a error :

Did not place order because available volume too low.

This error means for me that my signature is not correct.

If I remove the prefix I have still a error
I don't understand why. Can you help me ?
Thanks
Jehan

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions