|
| 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 | + |
| 214 | + |
| 215 | + |
0 commit comments