Requesting Proofs of Location

Make sure your users have installed the ioPay wallet and enabled trusted location in ioPay.

Prepare the query

The first step to request Proof of Location to the Trusted Location API is to prepare a POST call the API endpoint with the following body:

{
    "owner": "0x926CA7b35C2b5F528460A8f164054cE61BfCacFb",
    "message": "awesome.app wants you to sign in with your Ethereum account:\n0x926CA7b35C2b5F528460A8f164054cE61BfCacFb\n\nSign in Location Based NFT The application will know if you were located in one of the following regions in the time range below: from: Tue Dec 06 2022 16:58:58 GMT+0000 to: Tue Dec 06 2022 16:58:58 GMT+0000\n\nURI: http://localhost:3000\nVersion: 1\nChain ID: 4690\nNonce: CcWaTbGzTDPcqF1Ov\nIssued At: 2022-12-06T16:58:58.554Z\nExpiration Time: 2022-12-06T16:59:58.553Z'",
    "signature": "0x740c730c6486c8edc56ff22322f16044d4b761dcdf717a067f8241e2bf54d7f477f79ba10cbe21d9efb14ee12fa0c8321972806ad7ea848a4248d575532332f81b",    
    "locations": [
      {"scaled_latitude": 120520000, "scaled_longitude":  30400000, "distance": 1000, "from": 1669963142, "to": 1669964142},
      {"scaled_latitude":  26092603, "scaled_longitude": 119255364, "distance": 1000, "from": 1669963142, "to": 1672555142},
      {"scaled_latitude":  45481106, "scaled_longitude":   9146373, "distance":  500, "from": 1670216401, "to": 1670367600}
    ]
}

owner: is the ioPay wallet address that the user associated with service

message: is a prepared SIWE (Sign In With Ethereum) message

signature: owner's is the signature of the SIWE message

locations: is an array of locations and time ranges, in the following format:

{ 
    "scaled_latitude": 120520000, // Integer(Location Latitude * 10^6)
    "scaled_longitude": 30400000, // Integer(Longitude * 10^6)
    "distance": 500,              // Max distance from the location
    "from": 1669963142,           // Start of time range
    "to": 1669964142              // End of time range
}

Create a SIWE message

the code below shows an example of how to generate a SIWE message and have the user sign it inside the Metamask or ioPay Mobile wallet:

import { SiweMessage } from "siwe";
import moment from "moment";

const OWNER_ADDRESS = "0x926CA7b35C2b5F528460A8f164054cE61BfCacFb";
const CHAIN_ID = 4690;
...
createSiweMessage = () => {
  const message = new SiweMessage({
      domain: globalThis.location.host,
      address: OWNER_ADDRESS,
      statement: `Sign in Location Based NFT The application will know if you were located in one of the following regions in the time range below: from: ${moment().utc().subtract(1, "days");} to: ${moment().utc().add(1, "days"}`,
      uri: globalThis.location.origin,
      version: "1",
      chainId: CHAIN_ID,
      expirationTime: moment().add(1, "minutes").toISOString(),
    });
  return message.prepareMessage();
};

Example SIWE message

This is how a SIWE message would look like before it's prepared for the user:

{
    "domain": "awesome.app",
    "address": "0x926CA7b35C2b5F528460A8f164054cE61BfCacFb",
    "chainId": 4690,
    "expirationTime": "2022-11-30T15:20:03.433Z",
    "statement": "Sign in Location Based NFT",
    "uri": "https://awesome.app",
    "version": "1"
}

This is how this message would look in Metamask after it's prepared and displayed to the user for signing in Metamask:

awesome.app wants you to sign in with your Ethereum account:
0x926CA7b35C2b5F528460A8f164054cE61BfCacFb

Sign in Location Based NFT The application will know if you were located in one of the following regions in the time range below: from: Mon Dec 05 2022 18:20:33 GMT+0000 to: Wed Dec 07 2022 18:20:33 GMT+0000

URI: https://awesome.app
Version: 1
Chain ID: 4690
Nonce: sVlTp2bcgCEYVz1Ou
Issued At: 2022-12-06T18:20:33.260Z
Expiration Time: 2022-12-06T18:21:33.259Z

Sign the SIWE message

The example below shows a possible way to sign the SIWE message in Metamask or ioPay mobile:

import { useSDK } from "@thirdweb-dev/react";
const sdk = useSDK();

...

// Sign the SIWE message in the wallet app
const message = createSiweMessage();
const signature = await sdk?.wallet.sign(message);

Send the Query to GeoStream

Below is an example of how to send the query to GeoStream:

import axios from "axios";
const NEXT_PUBLIC_APIURL = "https://geo-test.w3bstream.com/api/pol";

...

const body = 
  {
     signature,         // SIWE signature
     message,           // Prepared SIWE message
     owner: this.owner, // User's ioPay address that was associated to GeoStream
     locations: [       // Locations to be queried, with resp. time ranges
       {"scaled_latitude": 120520000, "scaled_longitude":  30400000, "distance": 1000, "from": 1669963142, "to": 1669964142},
       {"scaled_latitude":  26092603, "scaled_longitude": 119255364, "distance": 1000, "from": 1669963142, "to": 1672555142},
       {"scaled_latitude":  45481106, "scaled_longitude":   9146373, "distance":  500, "from": 1670216401, "to": 1670367600}
     ]
   };
   
// Query the proof of location
const response = await axios.post(
  `${NEXT_PUBLIC_APIURL}/api/get_sign_data_for_location`, 
  body
);

// Get the respose data from the API
const signData: SIGN_DATA[] = response.data.result.data;

The API response data contain the actual Proofs of Location in the form of a subset of the queried locations, with some added information. Let's take a closer look:

"locations": [
      {"scaled_latitude": 120520000, "scaled_longitude":  30400000, "distance": 1000, "from": 129098787, "to": 1779987, "signature: "0x...", "devicehash": "0x...", "imei": "123456789012345" },
      {"scaled_latitude":  26092603, "scaled_longitude": 119255364, "distance": 1000, "from": 129098787, "to": 1779987, "signature: "0x...", "devicehash": "0x...", "imei": "123456789012345" },
      {"scaled_latitude":  45481106, "scaled_longitude":   9146373, "distance":  500, "from": 129098787, "to": 1779987, "signature: "0x...", "devicehash": "0x...", "imei": "123456789012345" }
    ]

For each GeoStream device that a user associated with the ioPay address, and for each queried location, the API will return a signed "(device, location)" entry if that device was actually in that location in the respective time range. Each entry will include the following fields:

{
    // The location data as provided in the query
    "scaled_latitude":  45481106, 
    "scaled_longitude":  9146373, 
    "distance": 500, 
    "from": 129098787, 
    "to": 1779987, 
    // The data of the user owned device that was in that location in that time range
    "devicehash": "0x...", 
    "imei": "123456789012345" 
    // The GeoStream API signature of a message including the fields above
    "signature: "0x...", 
}

Each one of those entries can be easily verified by the GeoStream Verifier Contract.

Last updated