Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invalid Signature #27

Open
Cyrano71 opened this issue Jul 6, 2018 · 1 comment
Open

Invalid Signature #27

Cyrano71 opened this issue Jul 6, 2018 · 1 comment

Comments

@Cyrano71
Copy link

Cyrano71 commented Jul 6, 2018

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

@GoldRat
Copy link

GoldRat commented Dec 9, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants