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:
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.