The adex-market
(formerly named adex-node
) is the RESTful service responsible for the discovery of advertising demand and supply.
To be more precise, it facilitates submission and tracking of campaigns, as well as user registrations.
NOTE: in AdEx, a campaign is a superset of a channel; when talking about the Market, we will use "campaign", but when pulling information from the validators, we are usually interacting with the /channel
Sentry API
The primary job of the market is to allow for advertisers to register their campaigns, and to track the campaign state after.
This is accomplished by querying each individual validator about the channel state periodically.
Please note: each publisher should rely on their publisher-side platform to track the demand for them. The Market only aggregates the information from validators to facilitate discovery.
The Market must be configured with a list of validators beforehand, as well as whether we want to enable further methods of discovery.
For example:
{
"initialValidators": ["https://one.adex.network", "https://thirdpartyvalidator.network"],
"discoverValidators": {
"enabled": true
}
}
Currently, the only method of discovering validators that are not in the configuration set, is by scanning channels and aggregating validator information from the campaignSpec
field of the channels it scrapes.
For example, if we start with one validator in initialValidators
, and it reports 3 channels, each of these 3 channels will have one more validator that we'll discover. If we repeat this cycle, we will discover even more channels and validators.
Discovery methods we plan to implement in the future:
- AdEx Registry
- ENS + DNSSEC
- Kademlia DHT
Even though the AdEx Registry is the only method here that ensures validator reputation, any method is valuable if we want the market to be aware of as many validators/campaigns as possible.
This will return all campaigns (paginated to a maximum of 100 results, through ?limit
and ?skip
)
By default, this will return all the Active
or Ready
campaigns. Use ?status
to get campaigns with a different status. You can filter by multiple status values, e.g. ?status=Ready,Active
Each campaign will have:
- id
- status
- creator
- validUntil
- campaignSpec
- depositAsset
- depositAmount
This will return detailed information about each campaign, such as:
- leaderBalanceTree
- followerBalanceTree
Validators are identified by their Ethereum address in the Channel
data structure, but in order to send events to them, you need the HTTPS address of their Sentry node.
In order to find the HTTPS address, you can query this resource.
Returns all validators this Market knows of.
Allows filtering returned validators by status (active, offline).
Returns all validators with that Ethereum address. It should usually return one validator.
Returns:
- publisherCount - all the registered publishers where
hasInteracted
is true - advertiserCount - all the registered advertisers where
hasInteracted
is true - anonPublisherCount - count of all non-registered earners that appear in campaign balance trees (that are not validators)
- anonAdvertiserCount - count of all non-registered advertisers (creators of campaigns)
- campaignCount
- campaignsByStatus: campaigns by status, counted
- totalSpentFundsByAssetType
At some point, we may add a method that returns an aggregated list of all ad units found in campaignSpec
fields of known campaigns.
This routes requires user authentication with x-user-signature
header.
Advertisers can add and get their Ad Units and Publishers Ad Slots
Post body params:
identity
: string, identity contract address, will be usedowner
prop in Ad unit and Ad Slotaddress
: string, user eth address which signs theauthToken
, we check if the address hasprivileges > 0
in theidentity
contract addresssignature
: string, signature of the signed hash parammode
: number, the way data is signed.0
for EIP signature (Metamask),1
for ETH Personal sig (GETH, LEDGER),2
for Trezor (Legacy)authToken
: number, random integerhash
: string, hash of the signed typed data[{ type: 'uint', name: 'Auth token', value: authToken }]
Returns user session in JSON format:
status
:"OK"
ifaddress
match the recovered address fromsignature
,mode
, andhash
, and hasprivileges > 0
in theidentity
contract addressidentity
: string, the verified identitysignature
: string, checked signature to be used asx-user-signature
header for accessing/media
,/unit
, and/slot
endpointsexpiryTime
: number, UTC timestamp in milliseconds until the session is active
Accepts Multipart form data
with media
field for the media blob and media-type
field for the media type and returns ipfs hash/
Returns:
ipfs
, string with ipfs hash
Accepts JSON in valid Ad Unit format. Adds the data from the Ad Unit to ipfs
Returns:
Ad Unit JSON plus ipfs hash
Use ?limit
and ?skip
for pagination.
Returns aray with user's Ad Units.
Returns Ad Unit by it's ipfs hash
Accepts JSON in valid Ad Slot format. Adds the data from the Ad Slot to ipfs
Returns:
Ad Slot JSON plus ipfs hash
Use ?limit
and ?skip
for pagination.
Returns aray with user's Ad Slots.
Returns array of all predefined TargetingTags as array of strings without the score
prop. This tags are meant for discovery between publishers/advertisers.
Every tick, we go through all the validators, and:
- query the
/channel/list
- for each channel, we create a corresponding campaign entry (if we didn't already)
- for each channel, we record every validator that we didn't know of
This loop starts with all the campaigns that we know of.
For each campaign:
- It queries
/channel/:id/validator-messages
of every validator - Determines the status from all of the responses
- Saves the status and a timestamp of when the status was last updated
The status is determined:
Initializing
: there are no messages at all for at least one validatorOffline
: at least one validator doesn't have a recentHeartbeat
messageDisconnected
: validators have recentHeartbeat
messages, but they don't seem to be propagating messages between one another (the majority of Heartbeats are not found on both validators)Invalid
: there are recentNewState
messages, but the follower does not issue or propagateApproveState
Unhealthy
: there are recentNewState
andApproveState
, but theApproveState
reports unhealthyReady
: both validators have a recentHeartbeat
but aNewState
has never been emittedActive
: there are recentNewState
,ApproveState
andHeartbeat
's, and theApproveState
reports healthyExhausted
: all of the funds in the channel have been distributedExpired
: the channel is expired
For simplicity, initial implementations might merge Disconnected
and Invalid
Later, we will add detailed status reports: for example, "validator A is offline: has not produced any messages since ..."
For discussion, see AmbireTech/adex-market#1
In reality, running a Market service is nothing more than an optimization: the same procedures described in internals could be ran directly at the dApp or the SDK. The Market service aggregates all this data so that the dApp/SDK don't need to send requests to every validator in the network on every user impression.
However, we also provide an ability to use the adex-market
repository as a library: if you only want to pull demand from a few validators, you can do that directly in your usecase without depending on another service.
The library exposes both the discovery loop and the status loop.
The full process to get your campaign discovered by the dApp/SDK is:
- Create a campaign; this creates an OUTPACE channel on the Ethereum blockchain
- Send the campaign/channel information to every validator you've elected
- Once each validator ensures that the channel exists, and there are funds locked up in it, it will start returning it in
/channel/list
and issuingHeartbeat
messages - At this stage, the Market will discover it
- Once both validators have issued a
Heartbeat
, the status will turn intoReady
Channels that are Ready
or Active
will be considered by the SDK
The AdEx Explorer is a user interface directly on top of the Market, designed to provide all the detailed information the Market contains in an accessible way.
It uses third-party APIs to provide extra information that's not available in the Market, for example:
- Provides a list of all channels on the Ethereum blockchain that are not associated with a validator
- Provides the USD/EUR value of campaign deposits