Skip to content

Commit 91b6d4f

Browse files
authored
Merge pull request #140 from backyard-coder/main
Add RadSense, a decentralised version of Google's AdSense
2 parents def2012 + 4f5773d commit 91b6d4f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+12790
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.idea
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
# RadSense
2+
3+
RadSense is a proof of concept (PoC) for a decentralised version of Google's
4+
[AdSense](https://de.wikipedia.org/wiki/Google_AdSense). It brings together *advertisers*, people that have a product or
5+
service to advertise, with *ad slot providers*, people who have a website on which advertisements may be displayed.
6+
A third group of users called *ad brokers* takes on the important task of matching up the *ads* of *advertisers* with
7+
the *ad slots* of *ad slot providers*. They do this by selecting which advertisements are to be displayed in which ad
8+
slots. Advertisers incur a cost every time on of their ads is clicked. Ad slot providers earn money every time an ad
9+
that is displayed in one of their slots is clicked. Finally, ad brokers are also paid a percentage for every ad
10+
clicked, as they provide an absolutely vital service to the platform. Very importantly the RadSense platform allows the
11+
settling of all payments between advertisers, ad slot providers and ad brokers on the network.
12+
13+
# Caveats
14+
15+
As a PoC, the feature set is obviously much smaller of what the original AdSense service offers to its user. Many
16+
concepts have been simplified or omitted and while AdSense features a quite involved bidding mechanism that takes into
17+
account the cost per click (CPC) and the click-through-rate (CTR) of an ad, RadSense uses a much simpler approach where
18+
users can only set a CPC for an ad and ad brokers then have to decide how to prioritise ads at their own discretion.
19+
20+
# NFRs (NFTs)
21+
22+
RadSense is the entry to the Scrypto NFT Challenge and as such features NFTs in some prominent places of its
23+
architecture. While the term NFT broadly refers to any kind of non-fungible token, it is now mostly used in the context
24+
of art that is represented by a token on-chain. A term that is historically less burned is that of a non-fungible
25+
resource (NFR). This term will be used in lieu of NTFs throughout this document and the code base.
26+
27+
## Ad
28+
29+
Every ad on the RadSense platform is represented by a NFR that (among some other fields) has a media item (i.e. link to
30+
an image or video), an url to where users should be directed when clicking the ad and some size constraints that
31+
describe the size and shape of the ad. It also has tags, describing its content (e.g. finance, blockchain, bitcoin), a
32+
cost per click (CPC) and a cost budget. Additionally, the NFR has a field for one single ad broker who is allowed to
33+
handle this ad and assign it to ad slots.
34+
Advertisers can publish new ads by simply calling a single method that creates a new ad NFR. The NFR is returned to the
35+
advertiser who created it and can be used when interacting with RadSense, e.g. when increasing the budget for the ad.
36+
37+
## Ad Slots
38+
39+
Similar to ads, ad slots are also represented as NFRs. Broadly speaking, an ad slot is any identifiable space on a
40+
website where ads may be displayed. Ad slots have a set of tags that describe the content of their surrounding website
41+
(e.g. news, finance, crypto) and some size constraints that indicate which ads can be placed inside them. Additionally,
42+
every ad slot stores a list of ad brokers that are allowed to place ads inside it.
43+
Ad slots are also created by calling a single method on the RadSense component.
44+
45+
## Users
46+
47+
Every user of RadSense is represented by a unique NFR. For all three kinds of users this NFR stores whether a user is
48+
KYCed (which can increases a user's trust level in the eyes of other users). Additionally, depending on a user's role,
49+
some further information is stored.
50+
51+
### Ad Brokers
52+
53+
Ad brokers have the important task of bringing together advertisers and ad slot providers. They have to decide which ad
54+
should be displayed in which ad slot. They also have to track the costs and revenues that are generated by ads and ad
55+
slots respectively and publish invoices which can then be settled on the network.
56+
57+
For each ad broker the user NFR stores:
58+
59+
- `broker_api_url`: An URL pointing to the broker's operational REST API. This API is invoked every time an ad slot is
60+
about to be displayed and now needs to know which ad it should render.
61+
- `tracking_api_url`: An URL pointing to the broker's tracking REST API. This API is invoked every time an ad has been
62+
rendered in an ad slot (i.e. the ad has been placed) or an ad is clicked by a user.
63+
- `fee_ratio`: A value between 0 and 1 that controls how much the broker can claim from the amount that is paid from
64+
advertisers to ad slot providers for each click on an ad.
65+
66+
### Advertisers
67+
68+
Advertisers are the financiers of RadSense. They pay ad slot providers and ad brokers for the ad space resp. the service
69+
they provide. For each advertiser the user NFR only stores an optional `tracking_api_url`. This is analogous to the
70+
tracking API of ad brokers. Because it is the responsibility of broker to track ad costs and to create invoices, this
71+
field is optional. However, advertisers might still be interested in receiving this data, so that they can verify
72+
invoices and see how their ads perform.
73+
74+
### Ad slot providers
75+
76+
Ad slot providers offer their website (and traffic) to advertisers and allow ad brokers to choose which ads should
77+
be placed on tit. Just as with advertisers, the ad slot provider NFR also stores an optional `tracking_api_url`.
78+
79+
## Invoices
80+
81+
Invoices are created by ad brokers so that advertisers can safely pay the ad slot providers for the ad space they have
82+
provided. Invoices themselves are not represented as NFRs because they are likely too big to be encapsulated in a single
83+
NFR. Given enough users, thousands of ads can be placed in thousands of ad slots, for which the costs and revenues have
84+
to be tracked properly and transparently. Therefore, invoices have been designed as components, which act as a wrapper
85+
for *ad cost items* on the one side of the invoice and *ad slot revenue items* on the other side. Both items are
86+
represented as NFRs.
87+
Please see the [code documentation](scrypto/src/invoice.rs) for a more in-depth description of invoices.
88+
89+
### Ad Costs
90+
91+
Ad costs make up the one side of an invoice. For every ad that has been clicked, an advertiser must pay a certain amount
92+
of XRD to the ad slot provider in whose ad slot the ad was displayed. Ad brokers must track this cost data, add it up
93+
per ad and then list it in an invoice. They do so, by creating an `AdCost` NFR, which is then stored in a vault of the
94+
invoice component. The NFR has fields that store the ID of the `Ad` NFR, to which the cost item belongs to, the cost
95+
amount and whether the cost item has been confirmed by the advertiser. Advertiser are required to confirm each cost item
96+
on an invoice before the invoice can be settled.
97+
98+
### Ad Slot Revenues
99+
100+
Ad slot revenues make up the other side of an invoice. Here ad brokers must sum up the revenues that have been generated
101+
by the individual ad slots. Having done that, they create a `AdSlotRevenue` NFR and also put that into a vault of the
102+
invoice. This NFR stores the ID of the `AdSlot` NFR it belongs to as well as the revenue amount. Additionally, this NFR
103+
also keeps track of whether the ad slot provider has already claimed their earning.
104+
105+
# Working mechanism
106+
107+
Implementing a decentralised form of advertising on the web comes with many requirements and challenges. Even when
108+
starting out small, possibly thousands of different ads must be displayed on thousands of websites to possibly millions
109+
of visitors. Each advertisement must be carefully chosen to match the content of the websites on which it is about to be
110+
displayed as well as to the interests of the visitor who is going to see it. Running the required matching logic on the
111+
Radix network would be sheer impossible. Furthermore, it is of course unreasonable to expect visitors to sign a
112+
transaction every time an advertisement is to be displayed to them. Many of the visitors may not even be crypto users at
113+
all. Circumventing this problem by assigning ads statically to ad slots would be a very meager solution. It would
114+
make for a weired user experience, where every visitor of a website would see the exact same ad every time, regardless
115+
of their interests.
116+
117+
RadSense overcomes this challenge by having ad brokers as a third party next to advertisers and ad slot providers. Ad
118+
brokers operate off-line (not on ledger) services that are vital for the operation of the platform. They offer a highly
119+
available API that can respond instantly whenever an ad slot is about to be rendered and an ad must be chosen to be
120+
displayed to a website visitor. It is at the sole discretion of the ad broker which ad they assign to an ad slot, but
121+
it is of course in their best interest to choose one that is likely to be clicked. After all, they are paid a
122+
percentage for every ad that is clicked and nothing if an ad is only displayed but never clicked.
123+
124+
## How an ad slot is registered and placed on a website
125+
126+
Registering an ad slot and getting it to display on a website only requires two easy to perform steps by an ad slot
127+
provider:
128+
129+
1. First, the ad slot provider has to register the ad slot as an `AdSlot` NFR with the RadSense component by calling the
130+
appropriate method. They must supply all the relevant data, i.e. the slots tags (e.g. finance, news, etc.) and the
131+
slots size constraints, as it makes quite the difference whether the slot is a horizontal banner on top of a website
132+
of a vertical column on the side.
133+
2. Next, the ad slot provider must embed an `AdSlotWebComponent` on their page in the appropriate place and link this
134+
to the `AdSlot` NFR. This is achieved by simply initializing the `AdSlotWebComponent` with the
135+
NFRs `NonFungibleAddress` (or equivalently it's resource address + non fungible id). The `AdSlotWebComponent` would
136+
be a pre-made component that is published to a registry (e.g. the npm registry) for everyone to use.
137+
138+
## How an ad slot is rendered
139+
140+
The `AdSlotWebComponent` performs the following steps when it is rendered in the browser of a website visitor. It only
141+
requires interaction with a Gateway of the Radix Network and with the operational API and the tracking API of the ad
142+
broker. It can also interact with the tracking APIs of the advertiser whose ad is being displayed and the ad slot
143+
provider in whose slot the ad is rendered but this is strictly optional.
144+
145+
1. The `AdSlotWebComponent` loads the data of its associated `AdSlot` NFR from the Radix network Gateway. It also loads
146+
the data of the associated ad slot provider and then the data of one of the ad brokers that are allowed to serve the
147+
ad slot. This data contains the broker's operational API URL.
148+
2. The component calls the broker's operational API and requests an ad for the slot. It sends the slot's ID and also a
149+
tracking cookie that identifies the user.
150+
3. It receives the ID of an `Ad` NFR as a response and loads the data of this NFR via the Radix network gateway.
151+
4. It takes the data of the `Ad` NFR (e.g. the URL of the media, which should be rendered and the URL of to the page to
152+
which the visitor should be redirected upon clicking the ad) and renders the ad accordingly.
153+
5. It sends an event to the tracking API of the ad broker indicating that the event has been placed. It sends the same
154+
event to the tracking APIs of the advertiser and ad slot provider if they have provided one.
155+
6. If the ad is clicked, the `AdSlotWebComponent` sends an event to the tracking API of the ad broker. It sends the same
156+
event to the tracking APIs of the advertiser and ad slot provider if they have provided one.
157+
158+
## How an ad is registered
159+
160+
Registering an ad is simple and only requires that an advertiser registers an `Ad` NFR with the RadSense component by
161+
calling the appropriate method. The advertiser of course has to make sure that the media they have linked in the NFR is
162+
always available, as it is not stored on chain.
163+
164+
## Incentive structure and freedom of choice
165+
166+
One of the central guiding principles of RadSense is, to give all users a free choice who to work/interact with.
167+
Advertiser must choose a single broker per ad, who then handles it, but they can choose different brokers for different
168+
ads. If a broker does not perform well (an ad e.g. doesn't generate a lot of site visits), advertisers can easily choose
169+
another broker for another ad.
170+
171+
Ad slot providers can allow multiple brokers to serve each of their slots. If a broker does not work in the best
172+
interest of the ad slot provider e.g. by displaying ads with NSFW content on a family friendly site, the ad slot
173+
provider can move away from that broker and offer their slots to other brokers who behave appropriately.
174+
175+
Finally, ad brokers can also decide to deny service to ad slot providers or advertisers if they are acting
176+
maliciously. For example, if an ad slot provider generates fake clicks on their own ad slots, brokers must be able to
177+
detect such behavior and prevent it. If they don't, advertisers that are now being defrauded, will move on to brokers
178+
who offer them better protections.
179+
It seems logical that ad brokers are going to build a database of all ad slots (and their surrounding websites), all ads
180+
and all users they are serving. This data will help them to identify good and bad actors and last but not least to
181+
provide good and targeted ad placements.
182+
183+
## Dealing with conflict
184+
185+
As described above, RadSense is built around a positive incentive structure. It also employs an optimistic strategy when
186+
handling the transfer of payments from advertisers to ad slot providers. This is described in greater detail in the code
187+
documentation of the [Invoice component](scrypto/src/invoice.rs). Nevertheless, conflict will be unavoidable. For this
188+
reason RadSense uses an arbitration DAO that springs into action whenever a broker's invoice is being disputed by any of
189+
the involved users. The members of this DAO (called arbitrators) have to check every invoice that is being disputed and
190+
give a verdict to either reject or approve the invoice. In the current design there is no incentive for arbitrators to
191+
provide their services. Instead, it is assumed that arbitrators do this work nonsalaried.
192+
193+
The arbitration DAO is built using [dao-kit](https://github.com/radixdlt/scrypto-challenges/tree/main/5-DAO/dao-kit)
194+
from the last Scrypto challenge. I would have loved to use the `import!` macro, but sadly it still contains a bug which
195+
forced me to copy the code over to this project.
196+
197+
# Alphanet demo
198+
199+
To prove the viability of the above described design/working mechanism I created a small [demo frontend](alphanet-demo).
200+
This demo also contains an implementation prototype of the above-mentioned `AdSlotWebComponent`. While I did not
201+
implement it as a proper web component but rather as a simple svelte component, it is still conceptually self-sufficient
202+
and does not need to be served from a web server.
203+
204+
The demo frontend enables a user to
205+
206+
- instantiate a new RadSense component
207+
- register an ad broker, an ad slot provider and an advertiser
208+
- register ad slots for the ad slot provider (including specifying their constraints)
209+
- register ads for the advertiser (including specifying an image to be displayed as well as a URL to a landing page)
210+
- open up a demo page on which ad slots are rendered. If the ads that are rendered in the slots are clicked, an event is
211+
sent to mocks of the tracking APIs of all users. These events are also displayed in the front end.
212+
213+
![Demo Frontend](screenshots/demo-frontend.png)
214+
215+
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
.DS_Store
2+
node_modules
3+
/build
4+
/.svelte-kit
5+
/package
6+
.env
7+
.env.*
8+
!.env.example
9+
.vercel
10+
.output
11+
.idea
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
engine-strict=true
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# alphanet-demo
2+
3+
To run the demo please execute the following commands:
4+
5+
```bash
6+
npm install
7+
npm run dev
8+
```
9+
10+
If you experience any trouble during the first time you run the demo, try relaoding the browser tab or restart the server.
11+
Vite seems to be generating things on the fly which might trip up the demos state.

0 commit comments

Comments
 (0)