All Downloads are FREE. Search and download functionalities are using the official Maven repository.

estonlabs.cxtl.exchanges.hyperliquid.api.v0.util.HyperliquidSigner Maven / Gradle / Ivy

There is a newer version: 1.4.14
Show newest version
package estonlabs.cxtl.exchanges.hyperliquid.api.v0.util;

import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.msgpack.jackson.dataformat.MessagePackFactory;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.Hash;
import org.web3j.crypto.Sign;
import org.web3j.crypto.StructuredDataEncoder;
import org.web3j.utils.Numeric;

import com.fasterxml.jackson.databind.ObjectMapper;

public class HyperliquidSigner {

    public static HyperliquidSignature signL1Action(String privateKey, Object action, String activePool, long nonce, boolean isMainnet) throws Exception {

        Credentials wallet = Credentials.create(privateKey);
        
        byte[] hash = actionHash(action, activePool, nonce);

        Map phantomAgent = constructPhantomAgent(hash, isMainnet);
        ObjectMapper mapper = new ObjectMapper();
        Map data = new HashMap<>();
        data.put("domain", Map.of("chainId", 1337, "name", "Exchange", "verifyingContract",
                "0x0000000000000000000000000000000000000000", "version", "1"));
        data.put("types", Map.of("Agent",
                List.of(Map.of("name", "source", "type", "string"), Map.of("name", "connectionId", "type", "bytes32")),
                "EIP712Domain",
                List.of(Map.of("name", "name", "type", "string"), Map.of("name", "version", "type", "string"),
                        Map.of("name", "chainId", "type", "uint256"),
                        Map.of("name", "verifyingContract", "type", "address"))));
        data.put("primaryType", "Agent");
        data.put("message", phantomAgent);

        String json = mapper.writeValueAsString(data);
        return signInner(wallet, json);
    }


    private static Map constructPhantomAgent(byte[] hash, boolean isMainnet) {
        Map phantomAgent = new HashMap<>();
        phantomAgent.put("source", isMainnet ? "a" : "b");
        phantomAgent.put("connectionId", Numeric.toHexString(hash));
        return phantomAgent;
    }

    private static HyperliquidSignature signInner(Credentials wallet, String jsonData) throws Exception {
        StructuredDataEncoder dataEncoder = new StructuredDataEncoder(jsonData);
        byte[] structuredData = dataEncoder.hashStructuredData();
        Sign.SignatureData signature = Sign.signMessage(structuredData, wallet.getEcKeyPair(), false); 
        String r = Numeric.toHexString(signature.getR());
        String s = Numeric.toHexString(signature.getS());
        int v = signature.getV()[0];

        Map signatureMap = new HashMap<>();
        signatureMap.put("r", r);
        signatureMap.put("s", s);
        signatureMap.put("v", v);
        
        return new HyperliquidSignature(r, s, v);

    }

    private static byte[] addressToBytes(String address) {
        return new BigInteger(address.startsWith("0x") ? address.substring(2) : address, 16).toByteArray();
    }

    private static byte[] actionHash(Object action, String vaultAddress, long nonce) throws Exception {

        ObjectMapper mapper = new ObjectMapper(new MessagePackFactory());
        byte[] data = mapper.writeValueAsBytes(action);
        data = combine(data, longToBytes(nonce, 8));

        if (vaultAddress == null) {
            data = combine(data, new byte[] { 0x00 });
        } else {
            data = combine(data, new byte[] { 0x01 });
            data = combine(data, addressToBytes(vaultAddress));
        }
        return Hash.sha3(data);
    }


    private static byte[] longToBytes(long value, int byteSize) {
        ByteBuffer buffer = ByteBuffer.allocate(byteSize);
        buffer.order(ByteOrder.BIG_ENDIAN);
        buffer.putLong(value);
        return buffer.array();
    }

    private static byte[] combine(byte[] a, byte[] b) {
        byte[] combined = new byte[a.length + b.length];
        System.arraycopy(a, 0, combined, 0, a.length);
        System.arraycopy(b, 0, combined, a.length, b.length);
        return combined;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy