Skip to content

Thoughts for a generic service #1

@juanfranblanco

Description

@juanfranblanco

@Enigmatic331
These are some thoughts for a generic service, with some small refactoring of your implementation.

The main idea is to:

  1. Have a generic interface that all Delegated signed functions have to adhere.
    Parameter attributes cannot be put here (or create a base class) as we don't know how many extra parameters we will have. Another option will be to use a struct matching the message if using Solidity V2 in future versions, which will be far much easier when doing mappings
public interface IDelegatedSignedFunction
    {
        string Owner { get; set; }
        BigInteger Fee { get; set; }
        BigInteger DelegatedNonce { get; set; }
        byte[] Sig { get; set; }
        string FeeAccount { get; set; }
    }

Then a generic service can be put in place as follows.

  public partial class SignedTransferFunction : SignedTransferFunctionBase { }

    [Function("signedTransfer", "bool")]
    public class SignedTransferFunctionBase : FunctionMessage
    {
        [Parameter("address", "tokenOwner", 1)]
        public virtual string Owner { get; set; }
        [Parameter("address", "to", 2)]
        public virtual string To { get; set; }
        [Parameter("uint256", "tokens", 3)]
        public virtual BigInteger Tokens { get; set; }
        [Parameter("uint256", "fee", 4)]
        public virtual BigInteger Fee { get; set; }
        [Parameter("uint256", "nonce", 5)]
        public virtual BigInteger DelegatedNonce { get; set; }
        [Parameter("bytes", "sig", 6)]
        public virtual byte[] Sig { get; set; }
        [Parameter("address", "feeAccount", 7)]
        public virtual string FeeAccount { get; set; }
    }

    //my custom partial implementing IDelegatedSignedFunction
    public partial class SignedTransferFunction : SignedTransferFunctionBase, IDelegatedSignedFunction
    {
       
    }


    public partial class TransferFunction : TransferFunctionBase { }

    [Function("transfer", "bool")]
    public class TransferFunctionBase : FunctionMessage
    {
        [Parameter("address", "_to", 1)]
        public virtual string To { get; set; }
        [Parameter("uint256", "_value", 2)]
        public virtual BigInteger Value { get; set; }
    }



    public interface IDelegatedSignedFunction
    {
        string Owner { get; set; }
        BigInteger Fee { get; set; }
        BigInteger DelegatedNonce { get; set; }
        byte[] Sig { get; set; }
        string FeeAccount { get; set; }
    }


    public class TokenDelegatedSignerService : DelegatedSignerService<TransferFunction, SignedTransferFunction>
    {
        public override SignedTransferFunction MapDelegatedFunctionToSignedFunction(TransferFunction delegatedFunction,
            SignedTransferFunction delegatedSignedFunction)
        {
            delegatedSignedFunction.To = delegatedFunction.To;
            delegatedSignedFunction.Tokens = delegatedFunction.Value;
            return delegatedSignedFunction;
        }

        public override TransferFunction MapSignedFunctionToDelegatedSignedFunction(TransferFunction delegatedFunction,
            SignedTransferFunction delegatedSignedFunction)
        {
            delegatedFunction.To = delegatedSignedFunction.To;
            delegatedFunction.Value = delegatedSignedFunction.Tokens;
            return delegatedFunction;
        }
    }

    public abstract class DelegatedSignerService<TDelegatedFunction, TDelegatedSignedFunction> where TDelegatedFunction: FunctionMessage, new()
        where TDelegatedSignedFunction: FunctionMessage, IDelegatedSignedFunction, new()
    {
        public string ContractAddress { get; set; }

        public string GetDelegatedFunctionSignature()
        {
            return ABITypedRegistry.GetFunctionABI<TDelegatedFunction>().Sha3Signature;
        }

        public string GetHashToSign(TDelegatedFunction delegatedFunction, string owner, BigInteger nonce, BigInteger fee)
        {
            var abiEncode = new ABIEncode();
            return Sha3Keccack.Current.CalculateHashFromHex(
                GetDelegatedFunctionSignature(),  
                abiEncode.GetABIEncodedPacked("address", ContractAddress).ToHex(),
                abiEncode.GetABIEncodedPacked("address", owner).ToHex(),
                delegatedFunction.GetParamsEncodedPacked().ToHex(),
                abiEncode.GetABIEncodedPacked("uint256", nonce).ToHex(),
                abiEncode.GetABIEncodedPacked("uint256", fee).ToHex()
            );
        }

        public byte[] GetSignature(TDelegatedFunction delegatedFunction, BigInteger delegatedNonce, BigInteger fee, string privateKey)
        {
            var ethEcKey = new EthECKey(privateKey);

            var messageSigner = new Nethereum.Signer.EthereumMessageSigner();
            return messageSigner.Sign(GetHashToSign(delegatedFunction, ethEcKey.GetPublicAddress(), delegatedNonce, fee).HexToByteArray(), ethEcKey).HexToByteArray();
        }

        public TDelegatedSignedFunction GetSignedRequest(TDelegatedFunction delegatedFunction, BigInteger delegatedNonce, BigInteger fee, string feeAccount,
            string privateKey)
        {
            var signedFunction = new TDelegatedSignedFunction();
            signedFunction = MapDelegatedFunctionToSignedFunction(delegatedFunction, signedFunction);
            signedFunction.Fee = fee;
            signedFunction.DelegatedNonce = delegatedNonce;
            signedFunction.FeeAccount = feeAccount;
            signedFunction.Sig = GetSignature(delegatedFunction, delegatedNonce, fee, privateKey);
            return signedFunction;
        }

        public TDelegatedSignedFunction GetSignedRequest(TDelegatedSignedFunction delegatedSignedFunctionToBeSigned,
            string privateKey)
        {
            var delegatedFunction =
                MapSignedFunctionToDelegatedSignedFunction(new TDelegatedFunction(), delegatedSignedFunctionToBeSigned);
            delegatedSignedFunctionToBeSigned.Sig = GetSignature(delegatedFunction, delegatedSignedFunctionToBeSigned.DelegatedNonce, delegatedSignedFunctionToBeSigned.Fee, privateKey);
            return delegatedSignedFunctionToBeSigned;
        }

        public abstract TDelegatedSignedFunction MapDelegatedFunctionToSignedFunction(
            TDelegatedFunction delegatedFunction, TDelegatedSignedFunction delegatedSignedFunction);

        public abstract TDelegatedFunction MapSignedFunctionToDelegatedSignedFunction(
            TDelegatedFunction delegatedFunction, TDelegatedSignedFunction delegatedSignedFunction);

    }

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions