Repository: prebid/prebid-server
Pull request #1891 (2021-06-16 15:10:13)

New Adapter: SA Lunamedia 

SyntaxNode: How is this different from the existing LunaMedia adapter?
lunamedia: @SyntaxNode 
We have created a new adapter, will test it with several publishers and if the test is successful, we deprecate the old one.

Patch:
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index b2c53776..bbb76d36 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -5,8 +5,8 @@
 	"build": {
 		"dockerfile": "Dockerfile",
 		"args": {
-			// Update the VARIANT arg to pick a version of Go: 1, 1.15, 1.14
-			"VARIANT": "1.14",
+			// Update the VARIANT arg to pick a version of Go
+			"VARIANT": "1.16",
 			// Options
 			"INSTALL_NODE": "false",
 			"NODE_VERSION": "lts/*",
diff --git a/.github/workflows/validate-merge.yml b/.github/workflows/validate-merge.yml
index 30370178..9cf371ca 100644
--- a/.github/workflows/validate-merge.yml
+++ b/.github/workflows/validate-merge.yml
@@ -12,7 +12,7 @@ jobs:
     - name: Install Go
       uses: actions/setup-go@v2
       with:
-        go-version: 1.14.2
+        go-version: 1.16.4
 
     - name: Checkout Merged Branch
       uses: actions/checkout@v2
diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml
index 3efc51d2..1eb13746 100644
--- a/.github/workflows/validate.yml
+++ b/.github/workflows/validate.yml
@@ -10,7 +10,7 @@ jobs:
   validate:
     strategy:
       matrix:
-        go-version: [1.14.x, 1.15.x]
+        go-version: [1.15.x, 1.16.x]
         os: [ubuntu-18.04]
     runs-on: ${{ matrix.os }}
     
diff --git a/Dockerfile b/Dockerfile
index d76398dc..defb64c8 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -3,8 +3,8 @@ RUN apt-get update && \
     apt-get -y upgrade && \
     apt-get install -y wget
 RUN cd /tmp && \
-    wget https://dl.google.com/go/go1.14.2.linux-amd64.tar.gz && \
-    tar -xf go1.14.2.linux-amd64.tar.gz && \
+    wget https://dl.google.com/go/go1.16.4.linux-amd64.tar.gz && \
+    tar -xf go1.16.4.linux-amd64.tar.gz && \
     mv go /usr/local
 RUN mkdir -p /app/prebid-server/
 WORKDIR /app/prebid-server/
diff --git a/README.md b/README.md
index f3338ce1..64486fd4 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@ Please consider [registering your Prebid Server](https://docs.prebid.org/prebid-
 
 ## Installation
 
-First install [Go](https://golang.org/doc/install) version 1.14 or newer.
+First install [Go](https://golang.org/doc/install) version 1.15 or newer.
 
 Note that prebid-server is using [Go modules](https://blog.golang.org/using-go-modules).
 We officially support the most recent two major versions of the Go runtime. However, if you'd like to use a version <1.13 and are inside GOPATH `GO111MODULE` needs to be set to `GO111MODULE=on`.
diff --git a/adapters/bidder.go b/adapters/bidder.go
index 2e5ec83c..b7bde4bc 100644
--- a/adapters/bidder.go
+++ b/adapters/bidder.go
@@ -7,6 +7,7 @@ import (
 
 	"github.com/mxmCherry/openrtb/v15/openrtb2"
 	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/currency"
 	"github.com/prebid/prebid-server/metrics"
 	"github.com/prebid/prebid-server/openrtb_ext"
 )
@@ -138,6 +139,25 @@ func (r *RequestData) SetBasicAuth(username string, password string) {
 type ExtraRequestInfo struct {
 	PbsEntryPoint              metrics.RequestType
 	GlobalPrivacyControlHeader string
+	currencyConversions        currency.Conversions
+}
+
+func NewExtraRequestInfo(c currency.Conversions) ExtraRequestInfo {
+	return ExtraRequestInfo{
+		currencyConversions: c,
+	}
+}
+
+// ConvertCurrency converts a given amount from one currency to another, or returns:
+//  - Error if the `from` or `to` arguments are malformed or unknown ISO-4217 codes.
+//  - ConversionNotFoundError if the conversion mapping is unknown to Prebid Server
+//    and not provided in the bid request.
+func (r ExtraRequestInfo) ConvertCurrency(value float64, from, to string) (float64, error) {
+	if rate, err := r.currencyConversions.GetRate(from, to); err == nil {
+		return value * rate, nil
+	} else {
+		return 0, err
+	}
 }
 
 type Builder func(openrtb_ext.BidderName, config.Adapter) (Bidder, error)
diff --git a/adapters/bidmyadz/bidmyadz.go b/adapters/bidmyadz/bidmyadz.go
new file mode 100644
index 00000000..829d57e6
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadz.go
@@ -0,0 +1,157 @@
+package bidmyadz
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"net/http"
+)
+
+type adapter struct {
+	endpoint string
+}
+
+type bidExt struct {
+	MediaType string `json:"mediaType"`
+}
+
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		endpoint: config.Endpoint,
+	}
+	return bidder, nil
+}
+
+func (a *adapter) MakeRequests(
+	openRTBRequest *openrtb2.BidRequest,
+	reqInfo *adapters.ExtraRequestInfo,
+) (
+	requestsToBidder []*adapters.RequestData,
+	errs []error,
+) {
+
+	var errors []error
+
+	if len(openRTBRequest.Imp) > 1 {
+		errors = append(errors, &errortypes.BadInput{
+			Message: "Bidder does not support multi impression",
+		})
+	}
+
+	if openRTBRequest.Device.IP == "" && openRTBRequest.Device.IPv6 == "" {
+		errors = append(errors, &errortypes.BadInput{
+			Message: "IP/IPv6 is a required field",
+		})
+	}
+
+	if openRTBRequest.Device.UA == "" {
+		errors = append(errors, &errortypes.BadInput{
+			Message: "User-Agent is a required field",
+		})
+	}
+
+	if len(errors) != 0 {
+		return nil, errors
+	}
+
+	reqJSON, err := json.Marshal(openRTBRequest)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	headers.Add("X-Openrtb-Version", "2.5")
+
+	return []*adapters.RequestData{{
+		Method:  http.MethodPost,
+		Body:    reqJSON,
+		Uri:     a.endpoint,
+		Headers: headers,
+	}}, nil
+}
+
+func (a *adapter) MakeBids(
+	openRTBRequest *openrtb2.BidRequest,
+	requestToBidder *adapters.RequestData,
+	bidderRawResponse *adapters.ResponseData,
+) (
+	bidderResponse *adapters.BidderResponse,
+	errs []error,
+) {
+	if bidderRawResponse.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if bidderRawResponse.StatusCode == http.StatusBadRequest {
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Bad Request. %s", string(bidderRawResponse.Body)),
+		}}
+	}
+
+	if bidderRawResponse.StatusCode == http.StatusServiceUnavailable {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Bidder is unavailable. Please contact your account manager.",
+		}}
+	}
+
+	if bidderRawResponse.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Something went wrong. Status Code: [ %d ] %s", bidderRawResponse.StatusCode, string(bidderRawResponse.Body)),
+		}}
+	}
+
+	responseBody := bidderRawResponse.Body
+	var bidResp openrtb2.BidResponse
+	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
+		return nil, []error{err}
+	}
+
+	if len(bidResp.SeatBid) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid",
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+
+	bids := bidResp.SeatBid[0].Bid
+
+	if len(bids) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid.Bids",
+		}}
+	}
+
+	bid := bids[0]
+
+	var bidExt bidExt
+	var bidType openrtb_ext.BidType
+
+	if err := json.Unmarshal(bid.Ext, &bidExt); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("BidExt parsing error. %s", err.Error()),
+		}}
+	}
+
+	bidType, err := getBidType(bidExt)
+
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+		Bid:     &bid,
+		BidType: bidType,
+	})
+	return bidResponse, nil
+}
+
+func getBidType(ext bidExt) (openrtb_ext.BidType, error) {
+	return openrtb_ext.ParseBidType(ext.MediaType)
+}
diff --git a/adapters/bidmyadz/usersync.go b/adapters/bidmyadz/usersync.go
new file mode 100644
index 00000000..755a184d
--- /dev/null
+++ b/adapters/bidmyadz/usersync.go
@@ -0,0 +1,12 @@
+package bidmyadz
+
+import (
+	"text/template"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/usersync"
+)
+
+func NewBidmyadzSyncer(temp *template.Template) usersync.Usersyncer {
+	return adapters.NewSyncer("bidmyadz", temp, adapters.SyncTypeRedirect)
+}
diff --git a/adapters/outbrain/outbrain.go b/adapters/outbrain/outbrain.go
index 282a6d53..6b121cb4 100644
--- a/adapters/outbrain/outbrain.go
+++ b/adapters/outbrain/outbrain.go
@@ -43,8 +43,10 @@ func (a *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte
 			errs = append(errs, err)
 			continue
 		}
-		imp.TagID = outbrainExt.TagId
-		reqCopy.Imp[i] = imp
+		if outbrainExt.TagId != "" {
+			imp.TagID = outbrainExt.TagId
+			reqCopy.Imp[i] = imp
+		}
 	}
 
 	publisher := &openrtb2.Publisher{
diff --git a/adapters/pubmatic/pubmatic.go b/adapters/pubmatic/pubmatic.go
index dc1ee9d0..c2e9fffa 100644
--- a/adapters/pubmatic/pubmatic.go
+++ b/adapters/pubmatic/pubmatic.go
@@ -56,6 +56,21 @@ type pubmaticBidExt struct {
 	VideoCreativeInfo *pubmaticBidExtVideo `json:"video,omitempty"`
 }
 
+type ExtImpBidderPubmatic struct {
+	adapters.ExtImpBidder
+	Data *ExtData `json:"data,omitempty"`
+}
+
+type ExtData struct {
+	AdServer *ExtAdServer `json:"adserver"`
+	PBAdSlot string       `json:"pbadslot"`
+}
+
+type ExtAdServer struct {
+	Name   string `json:"name"`
+	AdSlot string `json:"adslot"`
+}
+
 const (
 	INVALID_PARAMS    = "Invalid BidParam"
 	MISSING_PUBID     = "Missing PubID"
@@ -70,6 +85,8 @@ const (
 	dctrKeyName        = "key_val"
 	pmZoneIDKeyName    = "pmZoneId"
 	pmZoneIDKeyNameOld = "pmZoneID"
+	ImpExtAdUnitKey    = "dfp_ad_unit_code"
+	AdServerGAM        = "gam"
 )
 
 func PrepareLogMessage(tID, pubId, adUnitId, bidID, details string, args ...interface{}) string {
@@ -453,7 +470,7 @@ func parseImpressionObject(imp *openrtb2.Imp, wrapExt *string, pubID *string) er
 		imp.Audio = nil
 	}
 
-	var bidderExt adapters.ExtImpBidder
+	var bidderExt ExtImpBidderPubmatic
 	if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil {
 		return err
 	}
@@ -501,6 +518,14 @@ func parseImpressionObject(imp *openrtb2.Imp, wrapExt *string, pubID *string) er
 		extMap[pmZoneIDKeyName] = pubmaticExt.PmZoneID
 	}
 
+	if bidderExt.Data != nil {
+		if bidderExt.Data.AdServer != nil && bidderExt.Data.AdServer.Name == AdServerGAM && bidderExt.Data.AdServer.AdSlot != "" {
+			extMap[ImpExtAdUnitKey] = bidderExt.Data.AdServer.AdSlot
+		} else if bidderExt.Data.PBAdSlot != "" {
+			extMap[ImpExtAdUnitKey] = bidderExt.Data.PBAdSlot
+		}
+	}
+
 	imp.Ext = nil
 	if len(extMap) > 0 {
 		ext, err := json.Marshal(extMap)
diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go
index 89d69522..73f6a5d3 100644
--- a/adapters/rubicon/rubicon.go
+++ b/adapters/rubicon/rubicon.go
@@ -750,6 +750,10 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 			continue
 		}
 
+		resolvedBidFloor, resolvedBidFloorCur := resolveBidFloorAttributes(thisImp.BidFloor, thisImp.BidFloorCur)
+		thisImp.BidFloorCur = resolvedBidFloorCur
+		thisImp.BidFloor = resolvedBidFloor
+
 		if request.User != nil {
 			userCopy := *request.User
 			userExtRP := rubiconUserExt{RP: rubiconUserExtRP{Target: rubiconExt.Visitor}}
@@ -893,6 +897,17 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada
 	return requestData, errs
 }
 
+// Will be replaced after https://github.com/prebid/prebid-server/issues/1482 resolution
+func resolveBidFloorAttributes(bidFloor float64, bidFloorCur string) (float64, string) {
+	if bidFloor > 0 {
+		if strings.ToUpper(bidFloorCur) == "EUR" {
+			return bidFloor * 1.2, "USD"
+		}
+	}
+
+	return bidFloor, bidFloorCur
+}
+
 func updateUserExtWithIabAttribute(userExtRP *rubiconUserExt, data []openrtb2.Data) error {
 	var segmentIdsToCopy = make([]string, 0)
 
diff --git a/adapters/sa_lunamedia/salunamedia.go b/adapters/sa_lunamedia/salunamedia.go
new file mode 100644
index 00000000..ea6e12b0
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamedia.go
@@ -0,0 +1,132 @@
+package salunamedia
+
+import (
+	"encoding/json"
+	"fmt"
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"net/http"
+)
+
+type adapter struct {
+	endpoint string
+}
+
+type bidExt struct {
+	MediaType string `json:"mediaType"`
+}
+
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		endpoint: config.Endpoint,
+	}
+	return bidder, nil
+}
+
+func (a *adapter) MakeRequests(
+	openRTBRequest *openrtb2.BidRequest,
+	reqInfo *adapters.ExtraRequestInfo,
+) (
+	requestsToBidder []*adapters.RequestData,
+	errs []error,
+) {
+
+	reqJSON, err := json.Marshal(openRTBRequest)
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+
+	return []*adapters.RequestData{{
+		Method:  http.MethodPost,
+		Body:    reqJSON,
+		Uri:     a.endpoint,
+		Headers: headers,
+	}}, nil
+}
+
+func (a *adapter) MakeBids(
+	openRTBRequest *openrtb2.BidRequest,
+	requestToBidder *adapters.RequestData,
+	bidderRawResponse *adapters.ResponseData,
+) (
+	bidderResponse *adapters.BidderResponse,
+	errs []error,
+) {
+	if bidderRawResponse.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if bidderRawResponse.StatusCode == http.StatusBadRequest {
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Bad Request. %s", string(bidderRawResponse.Body)),
+		}}
+	}
+
+	if bidderRawResponse.StatusCode == http.StatusServiceUnavailable {
+		return nil, []error{&errortypes.BadInput{
+			Message: "Bidder unavailable. Please contact the bidder support.",
+		}}
+	}
+
+	if bidderRawResponse.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Status Code: [ %d ] %s", bidderRawResponse.StatusCode, string(bidderRawResponse.Body)),
+		}}
+	}
+
+	responseBody := bidderRawResponse.Body
+	var bidResp openrtb2.BidResponse
+	if err := json.Unmarshal(responseBody, &bidResp); err != nil {
+		return nil, []error{err}
+	}
+
+	if len(bidResp.SeatBid) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid",
+		}}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(1)
+
+	bids := bidResp.SeatBid[0].Bid
+
+	if len(bids) == 0 {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Empty SeatBid.Bids",
+		}}
+	}
+
+	bid := bids[0]
+
+	var bidExt bidExt
+	var bidType openrtb_ext.BidType
+
+	if err := json.Unmarshal(bid.Ext, &bidExt); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: "Missing BidExt",
+		}}
+	}
+
+	bidType, err := getBidType(bidExt)
+
+	if err != nil {
+		return nil, []error{err}
+	}
+
+	bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+		Bid:     &bid,
+		BidType: bidType,
+	})
+	return bidResponse, nil
+}
+
+func getBidType(ext bidExt) (openrtb_ext.BidType, error) {
+	return openrtb_ext.ParseBidType(ext.MediaType)
+}
diff --git a/adapters/sa_lunamedia/usersync.go b/adapters/sa_lunamedia/usersync.go
new file mode 100644
index 00000000..f78b7944
--- /dev/null
+++ b/adapters/sa_lunamedia/usersync.go
@@ -0,0 +1,12 @@
+package salunamedia
+
+import (
+	"text/template"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/usersync"
+)
+
+func NewSaLunamediaSyncer(temp *template.Template) usersync.Usersyncer {
+	return adapters.NewSyncer("salunamedia", temp, adapters.SyncTypeRedirect)
+}
diff --git a/adapters/smilewanted/smilewanted.go b/adapters/smilewanted/smilewanted.go
new file mode 100644
index 00000000..376389df
--- /dev/null
+++ b/adapters/smilewanted/smilewanted.go
@@ -0,0 +1,106 @@
+package smilewanted
+
+import (
+	"encoding/json"
+	"fmt"
+	"net/http"
+
+	"github.com/mxmCherry/openrtb/v15/openrtb2"
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/errortypes"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+type adapter struct {
+	URI string
+}
+
+func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+
+	request.AT = 1 //Defaulting to first price auction for all prebid requests
+
+	reqJSON, err := json.Marshal(request)
+	if err != nil {
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Json not encoded. err: %s", err),
+		}}
+	}
+
+	headers := http.Header{}
+	headers.Add("Content-Type", "application/json;charset=utf-8")
+	headers.Add("Accept", "application/json")
+	headers.Add("x-openrtb-version", "2.5")
+	headers.Add("sw-integration-type", "prebid_server")
+
+	return []*adapters.RequestData{{
+		Method:  "POST",
+		Uri:     a.URI,
+		Body:    reqJSON,
+		Headers: headers,
+	}}, []error{}
+}
+
+func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+
+	if response.StatusCode == http.StatusNoContent {
+		return nil, nil
+	}
+
+	if response.StatusCode == http.StatusBadRequest {
+		return nil, []error{&errortypes.BadInput{
+			Message: fmt.Sprintf("Unexpected status code: %d.", response.StatusCode),
+		}}
+	}
+
+	if response.StatusCode != http.StatusOK {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", response.StatusCode),
+		}}
+	}
+
+	var bidResp openrtb2.BidResponse
+	if err := json.Unmarshal(response.Body, &bidResp); err != nil {
+		return nil, []error{&errortypes.BadServerResponse{
+			Message: fmt.Sprintf("Bad server response: %s.", err),
+		}}
+	}
+
+	var bidReq openrtb2.BidRequest
+	if err := json.Unmarshal(externalRequest.Body, &bidReq); err != nil {
+		return nil, []error{err}
+	}
+
+	bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid))
+	sb := bidResp.SeatBid[0]
+	for i := 0; i < len(sb.Bid); i++ {
+		bid := sb.Bid[i]
+		bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{
+			Bid:     &bid,
+			BidType: getMediaTypeForImp(bid.ImpID, internalRequest.Imp),
+		})
+	}
+	return bidResponse, nil
+}
+
+// getMediaTypeForImp figures out which media type this bid is for.
+func getMediaTypeForImp(impId string, imps []openrtb2.Imp) openrtb_ext.BidType {
+	mediaType := openrtb_ext.BidTypeBanner //default type
+	for _, imp := range imps {
+		if imp.ID == impId {
+			if imp.Video != nil {
+				mediaType = openrtb_ext.BidTypeVideo
+			}
+			return mediaType
+		}
+	}
+	return mediaType
+}
+
+// Builder builds a new instance of the SmileWanted adapter for the given bidder with the given config.
+func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) {
+	bidder := &adapter{
+		URI: config.Endpoint,
+	}
+	return bidder, nil
+}
diff --git a/adapters/smilewanted/usersync.go b/adapters/smilewanted/usersync.go
new file mode 100644
index 00000000..8f29cb84
--- /dev/null
+++ b/adapters/smilewanted/usersync.go
@@ -0,0 +1,12 @@
+package smilewanted
+
+import (
+	"text/template"
+
+	"github.com/prebid/prebid-server/adapters"
+	"github.com/prebid/prebid-server/usersync"
+)
+
+func NewSmileWantedSyncer(temp *template.Template) usersync.Usersyncer {
+	return adapters.NewSyncer("smilewanted", temp, adapters.SyncTypeRedirect)
+}
diff --git a/config/config.go b/config/config.go
index 1260d28a..f6fa9917 100644
--- a/config/config.go
+++ b/config/config.go
@@ -93,7 +93,7 @@ type HTTPClient struct {
 	IdleConnTimeout     int `mapstructure:"idle_connection_timeout_seconds"`
 }
 
-func (cfg *Configuration) validate() []error {
+func (cfg *Configuration) validate(v *viper.Viper) []error {
 	var errs []error
 	errs = cfg.AuctionTimeouts.validate(errs)
 	errs = cfg.StoredRequests.validate(errs)
@@ -105,7 +105,7 @@ func (cfg *Configuration) validate() []error {
 	if cfg.MaxRequestSize < 0 {
 		errs = append(errs, fmt.Errorf("cfg.max_request_size must be >= 0. Got %d", cfg.MaxRequestSize))
 	}
-	errs = cfg.GDPR.validate(errs)
+	errs = cfg.GDPR.validate(v, errs)
 	errs = cfg.CurrencyConverter.validate(errs)
 	errs = validateAdapters(cfg.Adapters, errs)
 	errs = cfg.Debug.validate(errs)
@@ -207,8 +207,10 @@ type GDPR struct {
 	EEACountriesMap map[string]struct{}
 }
 
-func (cfg *GDPR) validate(errs []error) []error {
-	if cfg.DefaultValue != "0" && cfg.DefaultValue != "1" {
+func (cfg *GDPR) validate(v *viper.Viper, errs []error) []error {
+	if !v.IsSet("gdpr.default_value") {
+		errs = append(errs, fmt.Errorf("gdpr.default_value is required and must be specified"))
+	} else if cfg.DefaultValue != "0" && cfg.DefaultValue != "1" {
 		errs = append(errs, fmt.Errorf("gdpr.default_value must be 0 or 1"))
 	}
 	if cfg.HostVendorID < 0 || cfg.HostVendorID > 0xffff {
@@ -520,7 +522,7 @@ func New(v *viper.Viper) (*Configuration, error) {
 
 	glog.Info("Logging the resolved configuration:")
 	logGeneral(reflect.ValueOf(c), "  \t")
-	if errs := c.validate(); len(errs) > 0 {
+	if errs := c.validate(v); len(errs) > 0 {
 		return &c, errortypes.NewAggregateError("validation errors", errs)
 	}
 
@@ -585,6 +587,7 @@ func (cfg *Configuration) setDerivedDefaults() {
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderAvocet, "https://ads.avct.cloud/getuid?&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Davocet%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7B%7BUUID%7D%7D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeachfront, "https://sync.bfmio.com/sync_s2s?gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeachfront%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Bio_cid%5D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBeintoo, "https://ib.beintoo.com/um?ssp=pbs&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbeintoo%26uid%3D%24UID")
+	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBidmyadz, "https://cookie-sync.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&red="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbidmyadz%26uid%3D%5BUID%5D%26us_privacy%3D{{.USPrivacy}}%26gdpr_consent%3D{{.GDPRConsent}}%26gdpr%3D{{.GDPR}}")
 	// openrtb_ext.BidderBidsCube doesn't have a good default.
 	// openrtb_ext.BidderBmtm doesn't have a good default.
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderBrightroll, "https://pr-bh.ybp.yahoo.com/sync/appnexusprebidserver/?gdpr={{.GDPR}}&euconsent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&url="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dbrightroll%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
@@ -615,6 +618,7 @@ func (cfg *Configuration) setDerivedDefaults() {
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderLockerDome, "https://lockerdome.com/usync/prebidserver?pid="+cfg.Adapters["lockerdome"].PlatformID+"&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dlockerdome%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%7B%7Buid%7D%7D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderLogicad, "https://cr-p31.ladsp.jp/cookiesender/31?r=true&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ru="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dlogicad%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderLunaMedia, "https://api.lunamedia.io/xp/user-sync?redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dlunamedia%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
+	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSaLunaMedia, "https://cookie.lmgssp.com/pserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsa_lunamedia%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5BUID%5D")
 	// openrtb_ext.BidderMadvertise doesn't have a good default.
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderMarsmedia, "https://dmp.rtbsrv.com/dmp/profiles/cm?p_id=179&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dmarsmedia%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUUID%7D")
 	// openrtb_ext.BidderMediafuse doesn't have a good default.
@@ -634,6 +638,7 @@ func (cfg *Configuration) setDerivedDefaults() {
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSmartAdserver, "https://ssbsync-global.smartadserver.com/api/sync?callerId=5&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirectUri="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsmartadserver%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%5Bssb_sync_pid%5D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSmartRTB, "https://market-global.smrtb.com/sync/all?nid=smartrtb&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&rr="+url.QueryEscape(externalURL)+"%252Fsetuid%253Fbidder%253Dsmartrtb%2526gdpr%253D{{.GDPR}}%2526gdpr_consent%253D{{.GDPRConsent}}%2526uid%253D%257BXID%257D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSmartyAds, "https://as.ck-ie.com/prebid.gif?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsmartyads%26uid%3D%5BUID%5D")
+	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSmileWanted, "https://csync.smilewanted.com/getuid?source=prebid-server&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsmilewanted%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSomoaudience, "https://publisher-east.mobileadtrading.com/usersync?ru="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsomoaudience%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUID%7D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSonobi, "https://sync.go.sonobi.com/us.gif?loc="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsonobi%26consent_string%3D{{.GDPR}}%26gdpr%3D{{.GDPRConsent}}%26uid%3D%5BUID%5D")
 	setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderSovrn, "https://ap.lijit.com/pixel?redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dsovrn%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID")
@@ -839,6 +844,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.beintoo.endpoint", "https://ib.beintoo.com/um")
 	v.SetDefault("adapters.between.endpoint", "http://{{.Host}}.betweendigital.com/openrtb_bid?sspId={{.PublisherID}}")
 	v.SetDefault("adapters.bidmachine.endpoint", "https://{{.Host}}.bidmachine.io")
+	v.SetDefault("adapters.bidmyadz.endpoint", "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc")
 	v.SetDefault("adapters.bidscube.endpoint", "http://supply.bidscube.com/?c=o&m=rtb")
 	v.SetDefault("adapters.bmtm.endpoint", "https://one.elitebidder.com/api/pbs")
 	v.SetDefault("adapters.brightroll.endpoint", "http://east-bid.ybp.yahoo.com/bid/appnexuspbs")
@@ -875,6 +881,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.lockerdome.endpoint", "https://lockerdome.com/ladbid/prebidserver/openrtb2")
 	v.SetDefault("adapters.logicad.endpoint", "https://pbs.ladsp.com/adrequest/prebidserver")
 	v.SetDefault("adapters.lunamedia.endpoint", "http://api.lunamedia.io/xp/get?pubid={{.PublisherID}}")
+	v.SetDefault("adapters.sa_lunamedia.endpoint", "http://balancer.lmgssp.com/pserver")
 	v.SetDefault("adapters.madvertise.endpoint", "https://mobile.mng-ads.com/bidrequest{{.ZoneID}}")
 	v.SetDefault("adapters.marsmedia.endpoint", "https://bid306.rtbsrv.com/bidder/?bid=f3xtet")
 	v.SetDefault("adapters.mediafuse.endpoint", "http://ghb.hbmp.mediafuse.com/pbs/ortb")
@@ -904,6 +911,7 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("adapters.smartadserver.endpoint", "https://ssb-global.smartadserver.com")
 	v.SetDefault("adapters.smartrtb.endpoint", "http://market-east.smrtb.com/json/publisher/rtb?pubid={{.PublisherID}}")
 	v.SetDefault("adapters.smartyads.endpoint", "http://{{.Host}}.smartyads.com/bid?rtb_seat_id={{.SourceId}}&secret_key={{.AccountID}}")
+	v.SetDefault("adapters.smilewanted.endpoint", "http://prebid-server.smilewanted.com")
 	v.SetDefault("adapters.somoaudience.endpoint", "http://publisher-east.mobileadtrading.com/rtb/bid")
 	v.SetDefault("adapters.sonobi.endpoint", "https://apex.go.sonobi.com/prebid?partnerid=71d9d3d8af")
 	v.SetDefault("adapters.sovrn.endpoint", "http://ap.lijit.com/rtb/bid?src=prebid_server")
@@ -938,9 +946,9 @@ func SetupViper(v *viper.Viper, filename string) {
 	v.SetDefault("analytics.pubstack.buffers.count", 100)
 	v.SetDefault("analytics.pubstack.buffers.timeout", "900s")
 	v.SetDefault("amp_timeout_adjustment_ms", 0)
+	v.BindEnv("gdpr.default_value")
 	v.SetDefault("gdpr.enabled", true)
 	v.SetDefault("gdpr.host_vendor_id", 0)
-	v.SetDefault("gdpr.default_value", "1")
 	v.SetDefault("gdpr.timeouts_ms.init_vendorlist_fetches", 0)
 	v.SetDefault("gdpr.timeouts_ms.active_vendorlist_fetch", 0)
 	v.SetDefault("gdpr.non_standard_publishers", []string{""})
diff --git a/currency/aggregate_conversions.go b/currency/aggregate_conversions.go
index 53c5ebff..a15404fe 100644
--- a/currency/aggregate_conversions.go
+++ b/currency/aggregate_conversions.go
@@ -23,7 +23,7 @@ func (re *AggregateConversions) GetRate(from string, to string) (float64, error)
 	rate, err := re.customRates.GetRate(from, to)
 	if err == nil {
 		return rate, nil
-	} else if _, isMissingRateErr := err.(ConversionRateNotFound); !isMissingRateErr {
+	} else if _, isMissingRateErr := err.(ConversionNotFoundError); !isMissingRateErr {
 		// other error, return the error
 		return 0, err
 	}
diff --git a/currency/constant_rates.go b/currency/constant_rates.go
index dde317d8..ccc5c24d 100644
--- a/currency/constant_rates.go
+++ b/currency/constant_rates.go
@@ -27,7 +27,7 @@ func (r *ConstantRates) GetRate(from string, to string) (float64, error) {
 	}
 
 	if fromUnit.String() != toUnit.String() {
-		return 0, ConversionRateNotFound{fromUnit.String(), toUnit.String()}
+		return 0, ConversionNotFoundError{FromCur: fromUnit.String(), ToCur: toUnit.String()}
 	}
 
 	return 1, nil
diff --git a/currency/errors.go b/currency/errors.go
index d764c15b..bb4c42aa 100644
--- a/currency/errors.go
+++ b/currency/errors.go
@@ -2,12 +2,12 @@ package currency
 
 import "fmt"
 
-// ConversionRateNotFound is thrown by the currency.Conversions GetRate(from string, to string) method
+// ConversionNotFoundError is thrown by the currency.Conversions GetRate(from string, to string) method
 // when the conversion rate between the two currencies, nor its reciprocal, can be found.
-type ConversionRateNotFound struct {
+type ConversionNotFoundError struct {
 	FromCur, ToCur string
 }
 
-func (err ConversionRateNotFound) Error() string {
+func (err ConversionNotFoundError) Error() string {
 	return fmt.Sprintf("Currency conversion rate not found: '%s' => '%s'", err.FromCur, err.ToCur)
 }
diff --git a/currency/rates.go b/currency/rates.go
index 62914c4b..b9cb0201 100644
--- a/currency/rates.go
+++ b/currency/rates.go
@@ -47,9 +47,9 @@ func (r *Rates) UnmarshalJSON(b []byte) error {
 // GetRate returns the conversion rate between two currencies or:
 //  - An error if one of the currency strings is not well-formed
 //  - An error if any of the currency strings is not a recognized currency code.
-//  - A MissingConversionRate error in case the conversion rate between the two
+//  - A ConversionNotFoundError in case the conversion rate between the two
 //    given currencies is not in the currencies rates map
-func (r *Rates) GetRate(from string, to string) (float64, error) {
+func (r *Rates) GetRate(from, to string) (float64, error) {
 	var err error
 	fromUnit, err := currency.ParseISO(from)
 	if err != nil {
@@ -70,7 +70,7 @@ func (r *Rates) GetRate(from string, to string) (float64, error) {
 			// In case we have an entry TO -> FROM
 			return 1 / conversion, nil
 		}
-		return 0, ConversionRateNotFound{fromUnit.String(), toUnit.String()}
+		return 0, ConversionNotFoundError{FromCur: fromUnit.String(), ToCur: toUnit.String()}
 	}
 	return 0, errors.New("rates are nil")
 }
diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go
index a773d268..17e0d4f5 100755
--- a/exchange/adapter_builders.go
+++ b/exchange/adapter_builders.go
@@ -33,6 +33,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/beintoo"
 	"github.com/prebid/prebid-server/adapters/between"
 	"github.com/prebid/prebid-server/adapters/bidmachine"
+	"github.com/prebid/prebid-server/adapters/bidmyadz"
 	"github.com/prebid/prebid-server/adapters/bidscube"
 	"github.com/prebid/prebid-server/adapters/bmtm"
 	"github.com/prebid/prebid-server/adapters/brightroll"
@@ -88,12 +89,14 @@ import (
 	"github.com/prebid/prebid-server/adapters/rhythmone"
 	"github.com/prebid/prebid-server/adapters/rtbhouse"
 	"github.com/prebid/prebid-server/adapters/rubicon"
+	"github.com/prebid/prebid-server/adapters/sa_lunamedia"
 	"github.com/prebid/prebid-server/adapters/sharethrough"
 	"github.com/prebid/prebid-server/adapters/silvermob"
 	"github.com/prebid/prebid-server/adapters/smaato"
 	"github.com/prebid/prebid-server/adapters/smartadserver"
 	"github.com/prebid/prebid-server/adapters/smartrtb"
 	"github.com/prebid/prebid-server/adapters/smartyads"
+	"github.com/prebid/prebid-server/adapters/smilewanted"
 	"github.com/prebid/prebid-server/adapters/somoaudience"
 	"github.com/prebid/prebid-server/adapters/sonobi"
 	"github.com/prebid/prebid-server/adapters/sovrn"
@@ -153,6 +156,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderBeintoo:           beintoo.Builder,
 		openrtb_ext.BidderBetween:           between.Builder,
 		openrtb_ext.BidderBidmachine:        bidmachine.Builder,
+		openrtb_ext.BidderBidmyadz:          bidmyadz.Builder,
 		openrtb_ext.BidderBidsCube:          bidscube.Builder,
 		openrtb_ext.BidderBmtm:              bmtm.Builder,
 		openrtb_ext.BidderBrightroll:        brightroll.Builder,
@@ -188,6 +192,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderLockerDome:        lockerdome.Builder,
 		openrtb_ext.BidderLogicad:           logicad.Builder,
 		openrtb_ext.BidderLunaMedia:         lunamedia.Builder,
+		openrtb_ext.BidderSaLunaMedia:       salunamedia.Builder,
 		openrtb_ext.BidderMadvertise:        madvertise.Builder,
 		openrtb_ext.BidderMarsmedia:         marsmedia.Builder,
 		openrtb_ext.BidderMediafuse:         adtelligent.Builder,
@@ -215,6 +220,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder {
 		openrtb_ext.BidderSmartAdserver:     smartadserver.Builder,
 		openrtb_ext.BidderSmartRTB:          smartrtb.Builder,
 		openrtb_ext.BidderSmartyAds:         smartyads.Builder,
+		openrtb_ext.BidderSmileWanted:       smilewanted.Builder,
 		openrtb_ext.BidderSomoaudience:      somoaudience.Builder,
 		openrtb_ext.BidderSonobi:            sonobi.Builder,
 		openrtb_ext.BidderSovrn:             sovrn.Builder,
diff --git a/exchange/exchange.go b/exchange/exchange.go
index 7b156b5d..6aaafcd1 100644
--- a/exchange/exchange.go
+++ b/exchange/exchange.go
@@ -59,7 +59,7 @@ type exchange struct {
 	gDPR              gdpr.Permissions
 	currencyConverter *currency.RateConverter
 	externalURL       string
-	gdprDefaultValue  string
+	gdprDefaultValue  gdpr.Signal
 	privacyConfig     config.Privacy
 	categoriesFetcher stored_requests.CategoryFetcher
 	bidIDGenerator    BidIDGenerator
@@ -110,6 +110,11 @@ func (randomDeduplicateBidBooleanGenerator) Generate() bool {
 }
 
 func NewExchange(adapters map[openrtb_ext.BidderName]adaptedBidder, cache prebid_cache_client.Client, cfg *config.Configuration, metricsEngine metrics.MetricsEngine, infos config.BidderInfos, gDPR gdpr.Permissions, currencyConverter *currency.RateConverter, categoriesFetcher stored_requests.CategoryFetcher) Exchange {
+	gdprDefaultValue := gdpr.SignalYes
+	if cfg.GDPR.DefaultValue == "0" {
+		gdprDefaultValue = gdpr.SignalNo
+	}
+
 	return &exchange{
 		adapterMap:        adapters,
 		bidderInfo:        infos,
@@ -120,7 +125,7 @@ func NewExchange(adapters map[openrtb_ext.BidderName]adaptedBidder, cache prebid
 		externalURL:       cfg.ExternalURL,
 		gDPR:              gDPR,
 		me:                metricsEngine,
-		gdprDefaultValue:  cfg.GDPR.DefaultValue,
+		gdprDefaultValue:  gdprDefaultValue,
 		privacyConfig: config.Privacy{
 			CCPA: cfg.CCPA,
 			GDPR: cfg.GDPR,
@@ -301,7 +306,7 @@ func (e *exchange) HoldAuction(ctx context.Context, r AuctionRequest, debugLog *
 	return e.buildBidResponse(ctx, liveAdapters, adapterBids, r.BidRequest, adapterExtra, auc, bidResponseExt, cacheInstructions.returnCreative, errs)
 }
 
-func (e *exchange) parseGDPRDefaultValue(bidRequest *openrtb2.BidRequest) string {
+func (e *exchange) parseGDPRDefaultValue(bidRequest *openrtb2.BidRequest) gdpr.Signal {
 	gdprDefaultValue := e.gdprDefaultValue
 	var geo *openrtb2.Geo = nil
 
@@ -314,10 +319,10 @@ func (e *exchange) parseGDPRDefaultValue(bidRequest *openrtb2.BidRequest) string
 		// If we have a country set, and it is on the list, we assume GDPR applies if not set on the request.
 		// Otherwise we assume it does not apply as long as it appears "valid" (is 3 characters long).
 		if _, found := e.privacyConfig.GDPR.EEACountriesMap[strings.ToUpper(geo.Country)]; found {
-			gdprDefaultValue = "1"
+			gdprDefaultValue = gdpr.SignalYes
 		} else if len(geo.Country) == 3 {
 			// The country field is formatted properly as a three character country code
-			gdprDefaultValue = "0"
+			gdprDefaultValue = gdpr.SignalNo
 		}
 	}
 
@@ -444,7 +449,7 @@ func (e *exchange) getAllBids(
 			if givenAdjustment, ok := bidAdjustments[string(bidderRequest.BidderName)]; ok {
 				adjustmentFactor = givenAdjustment
 			}
-			var reqInfo adapters.ExtraRequestInfo
+			reqInfo := adapters.NewExtraRequestInfo(conversions)
 			reqInfo.PbsEntryPoint = bidderRequest.BidderLabels.RType
 			reqInfo.GlobalPrivacyControlHeader = globalPrivacyControlHeader
 			bids, err := e.adapterMap[bidderRequest.BidderCoreName].requestBid(ctx, bidderRequest.BidRequest, bidderRequest.BidderName, adjustmentFactor, conversions, &reqInfo, accountDebugAllowed, headerDebugAllowed)
diff --git a/exchange/utils.go b/exchange/utils.go
index c5cf6732..3def0425 100644
--- a/exchange/utils.go
+++ b/exchange/utils.go
@@ -57,7 +57,7 @@ func cleanOpenRTBRequests(ctx context.Context,
 	requestExt *openrtb_ext.ExtRequest,
 	gDPR gdpr.Permissions,
 	metricsEngine metrics.MetricsEngine,
-	gdprDefaultValue string,
+	gdprDefaultValue gdpr.Signal,
 	privacyConfig config.Privacy,
 	account *config.Account) (allowedBidderRequests []BidderRequest, privacyLabels metrics.PrivacyLabels, errs []error) {
 
@@ -87,7 +87,7 @@ func cleanOpenRTBRequests(ctx context.Context,
 	if err != nil {
 		errs = append(errs, err)
 	}
-	gdprEnforced := gdprSignal == gdpr.SignalYes || (gdprSignal == gdpr.SignalAmbiguous && gdprDefaultValue == "1")
+	gdprEnforced := gdprSignal == gdpr.SignalYes || (gdprSignal == gdpr.SignalAmbiguous && gdprDefaultValue == gdpr.SignalYes)
 
 	ccpaEnforcer, err := extractCCPA(req.BidRequest, privacyConfig, &req.Account, aliases, integrationTypeMap[req.LegacyLabels.RType])
 	if err != nil {
diff --git a/gdpr/gdpr.go b/gdpr/gdpr.go
index 4179d812..47d20a50 100644
--- a/gdpr/gdpr.go
+++ b/gdpr/gdpr.go
@@ -39,9 +39,15 @@ func NewPermissions(ctx context.Context, cfg config.GDPR, vendorIDs map[openrtb_
 		return &AlwaysAllow{}
 	}
 
+	gdprDefaultValue := SignalYes
+	if cfg.DefaultValue == "0" {
+		gdprDefaultValue = SignalNo
+	}
+
 	permissionsImpl := &permissionsImpl{
-		cfg:       cfg,
-		vendorIDs: vendorIDs,
+		cfg:              cfg,
+		gdprDefaultValue: gdprDefaultValue,
+		vendorIDs:        vendorIDs,
 		fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){
 			tcf2SpecVersion: newVendorListFetcher(ctx, cfg, client, vendorListURLMaker)},
 	}
diff --git a/gdpr/impl.go b/gdpr/impl.go
index 9c09e90b..17a1a893 100644
--- a/gdpr/impl.go
+++ b/gdpr/impl.go
@@ -28,9 +28,10 @@ const (
 )
 
 type permissionsImpl struct {
-	cfg             config.GDPR
-	vendorIDs       map[openrtb_ext.BidderName]uint16
-	fetchVendorList map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error)
+	cfg              config.GDPR
+	gdprDefaultValue Signal
+	vendorIDs        map[openrtb_ext.BidderName]uint16
+	fetchVendorList  map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error)
 }
 
 func (p *permissionsImpl) HostCookiesAllowed(ctx context.Context, gdprSignal Signal, consent string) (bool, error) {
@@ -80,6 +81,8 @@ func (p *permissionsImpl) AuctionActivitiesAllowed(ctx context.Context,
 
 	if id, ok := p.vendorIDs[bidder]; ok {
 		return p.allowActivities(ctx, id, consent, weakVendorEnforcement)
+	} else if weakVendorEnforcement {
+		return p.allowActivities(ctx, 0, consent, weakVendorEnforcement)
 	}
 
 	return p.defaultVendorPermissions()
@@ -94,7 +97,7 @@ func (p *permissionsImpl) normalizeGDPR(gdprSignal Signal) Signal {
 		return gdprSignal
 	}
 
-	if p.cfg.DefaultValue == "0" {
+	if p.gdprDefaultValue == SignalNo {
 		return SignalNo
 	}
 
@@ -135,7 +138,11 @@ func (p *permissionsImpl) allowActivities(ctx context.Context, vendorID uint16,
 
 	// vendor will be nil if not a valid TCF2 consent string
 	if vendor == nil {
-		return false, false, false, nil
+		if weakVendorEnforcement && parsedConsent.Version() == 2 {
+			vendor = vendorTrue{}
+		} else {
+			return false, false, false, nil
+		}
 	}
 
 	if !p.cfg.TCF2.Enabled {
@@ -208,6 +215,7 @@ func (p *permissionsImpl) parseVendor(ctx context.Context, vendorID uint16, cons
 	if version != 2 {
 		return
 	}
+
 	vendorList, err := p.fetchVendorList[version](ctx, parsedConsent.VendorListVersion())
 	if err != nil {
 		return
@@ -241,3 +249,22 @@ func (a AlwaysAllow) BidderSyncAllowed(ctx context.Context, bidder openrtb_ext.B
 func (a AlwaysAllow) AuctionActivitiesAllowed(ctx context.Context, bidder openrtb_ext.BidderName, PublisherID string, gdprSignal Signal, consent string, weakVendorEnforcement bool) (allowBidRequest bool, passGeo bool, passID bool, err error) {
 	return true, true, true, nil
 }
+
+// vendorTrue claims everything.
+type vendorTrue struct{}
+
+func (v vendorTrue) Purpose(purposeID consentconstants.Purpose) bool {
+	return true
+}
+func (v vendorTrue) PurposeStrict(purposeID consentconstants.Purpose) bool {
+	return true
+}
+func (v vendorTrue) LegitimateInterest(purposeID consentconstants.Purpose) bool {
+	return true
+}
+func (v vendorTrue) LegitimateInterestStrict(purposeID consentconstants.Purpose) bool {
+	return true
+}
+func (v vendorTrue) SpecialPurpose(purposeID consentconstants.Purpose) (hasSpecialPurpose bool) {
+	return true
+}
diff --git a/go.mod b/go.mod
index 6d1fe334..7d10a5c9 100644
--- a/go.mod
+++ b/go.mod
@@ -1,6 +1,6 @@
 module github.com/prebid/prebid-server
 
-go 1.14
+go 1.16
 
 require (
 	github.com/BurntSushi/toml v0.3.1 // indirect
@@ -22,7 +22,6 @@ require (
 	github.com/hashicorp/hcl v1.0.0 // indirect
 	github.com/influxdata/influxdb v1.6.1
 	github.com/julienschmidt/httprouter v1.1.0
-	github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
 	github.com/lib/pq v1.0.0
 	github.com/magiconair/properties v1.8.0
 	github.com/mattn/go-colorable v0.1.2 // indirect
diff --git a/go.sum b/go.sum
index 78b21ae1..4cb5863d 100644
--- a/go.sum
+++ b/go.sum
@@ -58,8 +58,6 @@ github.com/influxdata/influxdb v1.6.1 h1:OseoBlzI5ftNI/bczyxSWq6PKRCNEeiXvyWP/wS
 github.com/influxdata/influxdb v1.6.1/go.mod h1:qZna6X/4elxqT3yI9iZYdZrWWdeFOOprn86kgg4+IzY=
 github.com/julienschmidt/httprouter v1.1.0 h1:7wLdtIiIpzOkC9u6sXOozpBauPdskj3ru4EI5MABq68=
 github.com/julienschmidt/httprouter v1.1.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
-github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
-github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
 github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
 github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
diff --git a/main.go b/main.go
index ebeabf29..5c5a2a46 100644
--- a/main.go
+++ b/main.go
@@ -34,12 +34,12 @@ func main() {
 
 	cfg, err := loadConfig()
 	if err != nil {
-		glog.Fatalf("Configuration could not be loaded or did not pass validation: %v", err)
+		glog.Exitf("Configuration could not be loaded or did not pass validation: %v", err)
 	}
 
 	err = serve(Rev, cfg)
 	if err != nil {
-		glog.Errorf("prebid-server failed: %v", err)
+		glog.Exitf("prebid-server failed: %v", err)
 	}
 }
 
diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go
index ea6c809f..f2dd9815 100644
--- a/openrtb_ext/bidders.go
+++ b/openrtb_ext/bidders.go
@@ -104,6 +104,7 @@ const (
 	BidderBeintoo           BidderName = "beintoo"
 	BidderBetween           BidderName = "between"
 	BidderBidmachine        BidderName = "bidmachine"
+	BidderBidmyadz          BidderName = "bidmyadz"
 	BidderBidsCube          BidderName = "bidscube"
 	BidderBmtm              BidderName = "bmtm"
 	BidderBrightroll        BidderName = "brightroll"
@@ -139,6 +140,7 @@ const (
 	BidderLockerDome        BidderName = "lockerdome"
 	BidderLogicad           BidderName = "logicad"
 	BidderLunaMedia         BidderName = "lunamedia"
+	BidderSaLunaMedia       BidderName = "sa_lunamedia"
 	BidderMadvertise        BidderName = "madvertise"
 	BidderMarsmedia         BidderName = "marsmedia"
 	BidderMediafuse         BidderName = "mediafuse"
@@ -166,6 +168,7 @@ const (
 	BidderSmartAdserver     BidderName = "smartadserver"
 	BidderSmartRTB          BidderName = "smartrtb"
 	BidderSmartyAds         BidderName = "smartyads"
+	BidderSmileWanted       BidderName = "smilewanted"
 	BidderSomoaudience      BidderName = "somoaudience"
 	BidderSonobi            BidderName = "sonobi"
 	BidderSovrn             BidderName = "sovrn"
@@ -224,6 +227,7 @@ func CoreBidderNames() []BidderName {
 		BidderBeintoo,
 		BidderBetween,
 		BidderBidmachine,
+		BidderBidmyadz,
 		BidderBidsCube,
 		BidderBmtm,
 		BidderBrightroll,
@@ -259,6 +263,7 @@ func CoreBidderNames() []BidderName {
 		BidderLockerDome,
 		BidderLogicad,
 		BidderLunaMedia,
+		BidderSaLunaMedia,
 		BidderMadvertise,
 		BidderMarsmedia,
 		BidderMediafuse,
@@ -286,6 +291,7 @@ func CoreBidderNames() []BidderName {
 		BidderSmartAdserver,
 		BidderSmartRTB,
 		BidderSmartyAds,
+		BidderSmileWanted,
 		BidderSomoaudience,
 		BidderSonobi,
 		BidderSovrn,
diff --git a/openrtb_ext/imp_sa_lunamedia.go b/openrtb_ext/imp_sa_lunamedia.go
new file mode 100644
index 00000000..cb99b0ac
--- /dev/null
+++ b/openrtb_ext/imp_sa_lunamedia.go
@@ -0,0 +1,6 @@
+package openrtb_ext
+
+type ExtImpSaLunamedia struct {
+	Key  string `json:"key"`
+	Type string `json:"type,omitempty"`
+}
diff --git a/static/bidder-info/bidmyadz.yaml b/static/bidder-info/bidmyadz.yaml
new file mode 100644
index 00000000..70a995a2
--- /dev/null
+++ b/static/bidder-info/bidmyadz.yaml
@@ -0,0 +1,13 @@
+maintainer:
+  email: "contact@bidmyadz.com"
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
\ No newline at end of file
diff --git a/static/bidder-info/sa_lunamedia.yaml b/static/bidder-info/sa_lunamedia.yaml
new file mode 100644
index 00000000..181e1fd6
--- /dev/null
+++ b/static/bidder-info/sa_lunamedia.yaml
@@ -0,0 +1,14 @@
+maintainer:
+  email: "support@lunamedia.io"
+gvlVendorID: 998
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+      - native
+  site:
+    mediaTypes:
+      - banner
+      - video
+      - native
\ No newline at end of file
diff --git a/static/bidder-info/smilewanted.yaml b/static/bidder-info/smilewanted.yaml
new file mode 100644
index 00000000..81b0585b
--- /dev/null
+++ b/static/bidder-info/smilewanted.yaml
@@ -0,0 +1,12 @@
+maintainer:
+  email: "tech@smilewanted.com"
+gvlVendorID: 639
+capabilities:
+  app:
+    mediaTypes:
+      - banner
+      - video
+  site:
+    mediaTypes:
+      - banner
+      - video
diff --git a/static/bidder-params/bidmyadz.json b/static/bidder-params/bidmyadz.json
new file mode 100644
index 00000000..4e7b1119
--- /dev/null
+++ b/static/bidder-params/bidmyadz.json
@@ -0,0 +1,12 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "BidMyAdz Adapter Params",
+    "description": "A schema which validates params accepted by the BidMyAdz adapter",
+    "type": "object",
+    "properties": {
+      "placementId": {
+        "type": "string"
+      }
+    },
+    "required": ["placementId"]
+  }
\ No newline at end of file
diff --git a/static/bidder-params/sa_lunamedia.json b/static/bidder-params/sa_lunamedia.json
new file mode 100644
index 00000000..51ca0909
--- /dev/null
+++ b/static/bidder-params/sa_lunamedia.json
@@ -0,0 +1,17 @@
+{
+    "$schema": "http://json-schema.org/draft-04/schema#",
+    "title": "Sa_Lunamedia Adapter Params",
+    "description": "A schema which validates params accepted by the Sa_Lunamedia adapter",
+    "type": "object",
+    "properties": {
+      "key": {
+        "type": "string",
+        "description": "network or placement key"
+      },
+      "type": {
+        "type": "string",
+        "enum": ["network", "publisher"]
+      }
+    },
+    "required": ["key"]
+  }
\ No newline at end of file
diff --git a/static/bidder-params/smilewanted.json b/static/bidder-params/smilewanted.json
new file mode 100644
index 00000000..be4f9bc1
--- /dev/null
+++ b/static/bidder-params/smilewanted.json
@@ -0,0 +1,14 @@
+{
+  "$schema": "http://json-schema.org/draft-04/schema#",
+  "title": "SmileWanted Adapter Params",
+  "description": "A schema which validates params accepted by the SmileWanted adapter",
+  "type": "object",
+  "properties": {
+    "zoneId": {
+      "type": "string",
+      "description": "An ID which identifies the SmileWanted zone code",
+      "minLength": 1
+    }
+  },
+  "required": ["zoneId"]
+}
diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go
index 88752f4d..7472bf3a 100644
--- a/usersync/usersyncers/syncer.go
+++ b/usersync/usersyncers/syncer.go
@@ -28,6 +28,7 @@ import (
 	"github.com/prebid/prebid-server/adapters/beachfront"
 	"github.com/prebid/prebid-server/adapters/beintoo"
 	"github.com/prebid/prebid-server/adapters/between"
+	"github.com/prebid/prebid-server/adapters/bidmyadz"
 	"github.com/prebid/prebid-server/adapters/bmtm"
 	"github.com/prebid/prebid-server/adapters/brightroll"
 	"github.com/prebid/prebid-server/adapters/colossus"
@@ -69,10 +70,12 @@ import (
 	"github.com/prebid/prebid-server/adapters/rhythmone"
 	"github.com/prebid/prebid-server/adapters/rtbhouse"
 	"github.com/prebid/prebid-server/adapters/rubicon"
+	"github.com/prebid/prebid-server/adapters/sa_lunamedia"
 	"github.com/prebid/prebid-server/adapters/sharethrough"
 	"github.com/prebid/prebid-server/adapters/smartadserver"
 	"github.com/prebid/prebid-server/adapters/smartrtb"
 	"github.com/prebid/prebid-server/adapters/smartyads"
+	"github.com/prebid/prebid-server/adapters/smilewanted"
 	"github.com/prebid/prebid-server/adapters/somoaudience"
 	"github.com/prebid/prebid-server/adapters/sonobi"
 	"github.com/prebid/prebid-server/adapters/sovrn"
@@ -127,6 +130,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderBeintoo, beintoo.NewBeintooSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderBmtm, bmtm.NewBmtmSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderBrightroll, brightroll.NewBrightrollSyncer)
+	insertIntoMap(cfg, syncers, openrtb_ext.BidderBidmyadz, bidmyadz.NewBidmyadzSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderColossus, colossus.NewColossusSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderConnectAd, connectad.NewConnectAdSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderConsumable, consumable.NewConsumableSyncer)
@@ -153,6 +157,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderLockerDome, lockerdome.NewLockerDomeSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderLogicad, logicad.NewLogicadSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderLunaMedia, lunamedia.NewLunaMediaSyncer)
+	insertIntoMap(cfg, syncers, openrtb_ext.BidderSaLunaMedia, salunamedia.NewSaLunamediaSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderMarsmedia, marsmedia.NewMarsmediaSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderMediafuse, mediafuse.NewMediafuseSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderMgid, mgid.NewMgidSyncer)
@@ -174,6 +179,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSmartAdserver, smartadserver.NewSmartadserverSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSmartRTB, smartrtb.NewSmartRTBSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSmartyAds, smartyads.NewSmartyAdsSyncer)
+	insertIntoMap(cfg, syncers, openrtb_ext.BidderSmileWanted, smilewanted.NewSmileWantedSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderSynacormedia, synacormedia.NewSynacorMediaSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderTappx, tappx.NewTappxSyncer)
 	insertIntoMap(cfg, syncers, openrtb_ext.BidderTelaria, telaria.NewTelariaSyncer)


Test patch:
diff --git a/adapters/bidder_test.go b/adapters/bidder_test.go
new file mode 100644
index 00000000..f0b833ce
--- /dev/null
+++ b/adapters/bidder_test.go
@@ -0,0 +1,63 @@
+package adapters
+
+import (
+	"errors"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
+)
+
+func TestExtraRequestInfoConvertCurrency(t *testing.T) {
+	var (
+		givenValue float64 = 2
+		givenFrom  string  = "AAA"
+		givenTo    string  = "BBB"
+	)
+
+	testCases := []struct {
+		description   string
+		setMock       func(m *mock.Mock)
+		expectedValue float64
+		expectedError error
+	}{
+		{
+			description:   "Success",
+			setMock:       func(m *mock.Mock) { m.On("GetRate", "AAA", "BBB").Return(2.5, nil) },
+			expectedValue: 5,
+			expectedError: nil,
+		},
+		{
+			description:   "Error",
+			setMock:       func(m *mock.Mock) { m.On("GetRate", "AAA", "BBB").Return(2.5, errors.New("some error")) },
+			expectedValue: 0,
+			expectedError: errors.New("some error"),
+		},
+	}
+
+	for _, test := range testCases {
+		mockConversions := &mockConversions{}
+		test.setMock(&mockConversions.Mock)
+
+		extraRequestInfo := NewExtraRequestInfo(mockConversions)
+		result, err := extraRequestInfo.ConvertCurrency(givenValue, givenFrom, givenTo)
+
+		mockConversions.AssertExpectations(t)
+		assert.Equal(t, test.expectedValue, result, test.description+":result")
+		assert.Equal(t, test.expectedError, err, test.description+":err")
+	}
+}
+
+type mockConversions struct {
+	mock.Mock
+}
+
+func (m mockConversions) GetRate(from string, to string) (float64, error) {
+	args := m.Called(from, to)
+	return args.Get(0).(float64), args.Error(1)
+}
+
+func (m mockConversions) GetRates() *map[string]map[string]float64 {
+	args := m.Called()
+	return args.Get(0).(*map[string]map[string]float64)
+}
diff --git a/adapters/bidmyadz/bidmyadz_test.go b/adapters/bidmyadz/bidmyadz_test.go
new file mode 100644
index 00000000..b0de6a02
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadz_test.go
@@ -0,0 +1,18 @@
+package bidmyadz
+
+import (
+	"github.com/stretchr/testify/assert"
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderBidmyadz, config.Adapter{
+		Endpoint: "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc"})
+
+	assert.NoError(t, buildErr)
+	adapterstest.RunJSONBidderTest(t, "bidmyadztest", bidder)
+}
diff --git a/adapters/bidmyadz/bidmyadztest/exemplary/banner.json b/adapters/bidmyadz/bidmyadztest/exemplary/banner.json
new file mode 100644
index 00000000..460291bc
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/exemplary/banner.json
@@ -0,0 +1,146 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "d910ceef496ff2d746176506e296f4b3_z53356_a126365",
+          "bidid": "880184da7ec02b1f42802acb46b63b3c",
+          "seatbid": [{
+            "bid": [{
+              "id": "6ca51ef38eb42820d27503ee96b634b5",
+              "impid": "126365",
+              "price": 0.1,
+              "nurl": "http://test.com/nurl",
+              "burl": "http://test.com/burl",
+              "adm": "<ADM>",
+              "adomain": ["test.com"],
+              "cat": ["IAB1"],
+              "cid": "1",
+              "crid": "1",
+              "w": 300,
+              "h": 250,
+              "ext": {
+                "mediaType": "banner"
+              }
+            }],
+            "seat": "1"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "6ca51ef38eb42820d27503ee96b634b5",
+            "impid": "126365",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "<ADM>",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "1",
+            "crid": "1",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "mediaType": "banner"
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/exemplary/native.json b/adapters/bidmyadz/bidmyadztest/exemplary/native.json
new file mode 100644
index 00000000..98480260
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/exemplary/native.json
@@ -0,0 +1,141 @@
+{
+  "mockBidRequest": {
+    "id": "111",
+    "tmax": 150,
+    "at": 1,
+    "device": {
+      "dnt": 0,
+      "devicetype": 2,
+      "ip": "71.106.52.124",
+      "ua": "Mozilla/5.0 (X11; Linux x86_64; Ubuntu 14.04.2 LTS) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.0 Maxthon/1.0.5.3 Safari/537.36"
+    },
+    "user": {
+      "id": "user-id"
+    },
+    "site": {
+      "id": "native",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    },
+    "cur": [
+      "USD"
+    ],
+    "imp": [{
+      "id": "1",
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "instl": 0,
+      "secure": 1,
+      "native": {
+        "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":15}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":300,\"hmin\":300,\"type\":3}}, {\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}",
+        "ver": "1.1"
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tnative"
+        }
+      }
+    }]
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+      "body": {
+        "id": "111",
+        "tmax": 150,
+        "at": 1,
+        "device": {
+          "dnt": 0,
+          "devicetype": 2,
+          "ip": "71.106.52.124",
+          "ua": "Mozilla/5.0 (X11; Linux x86_64; Ubuntu 14.04.2 LTS) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.0 Maxthon/1.0.5.3 Safari/537.36"
+        },
+        "user": {
+          "id": "user-id"
+        },
+        "site": {
+          "id": "native",
+          "domain": "test.com",
+          "cat": ["IAB1"],
+          "page": "https://test.com",
+          "publisher": {
+            "id": "1"
+          }
+        },
+        "cur": [
+          "USD"
+        ],
+        "imp": [{
+          "id": "1",
+          "bidfloor": 0.01,
+          "bidfloorcur": "USD",
+          "secure": 1,
+          "native": {
+            "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":15}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":300,\"hmin\":300,\"type\":3}}, {\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}",
+            "ver": "1.1"
+          },
+          "ext": {
+            "bidder": {
+              "placementId": "tnative"
+            }
+          }
+        }]
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": {
+        "id": "a1580f2f-be6d-11eb-a150-d094662c1c35",
+        "bidid": "359da97d0384d8a14767029c18fd840d",
+        "seatbid": [{
+          "bid": [{
+            "id": "1",
+            "impid": "1",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "{native-ads}",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "1",
+            "crid": "2",
+            "w": 0,
+            "h": 0,
+            "ext": {
+              "mediaType": "native"
+            }
+          }],
+          "seat": "1"
+        }],
+        "cur": "USD"
+      }
+    }
+  }],
+
+  "expectedBidResponses": [{
+    "currency": "USD",
+    "bids": [{
+      "bid": {
+        "id": "1",
+        "impid": "1",
+        "price": 0.1,
+        "nurl": "http://test.com/nurl",
+        "burl": "http://test.com/burl",
+        "adm": "{native-ads}",
+        "adomain": ["test.com"],
+        "cat": ["IAB1"],
+        "cid": "1",
+        "crid": "2",
+        "ext": {
+          "mediaType": "native"
+        }
+      },
+      "type": "native"
+    }]
+  }]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/exemplary/video.json b/adapters/bidmyadz/bidmyadztest/exemplary/video.json
new file mode 100644
index 00000000..92c42f83
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/exemplary/video.json
@@ -0,0 +1,160 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "video": {
+        "mimes": ["video/mp4", "video/ogg", "video/webm"],
+        "minduration": 5,
+        "maxduration": 60,
+        "protocols": [2, 3, 5, 6, 7, 8],
+        "w": 300,
+        "h": 250,
+        "linearity": 1,
+        "playbackmethod": [2]
+      },
+      "bidfloor": 0.001,
+      "bidfloorcur": "USD",
+      "secure": 1,
+      "exp": 3600,
+      "ext": {
+        "bidder": {
+          "placementId": "tvideo"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "video": {
+              "mimes": ["video/mp4", "video/ogg", "video/webm"],
+              "minduration": 5,
+              "maxduration": 60,
+              "protocols": [2, 3, 5, 6, 7, 8],
+              "w": 300,
+              "h": 250,
+              "linearity": 1,
+              "playbackmethod": [2]
+            },
+            "bidfloor": 0.001,
+            "bidfloorcur": "USD",
+            "secure": 1,
+            "exp": 3600,
+            "ext": {
+              "bidder": {
+                "placementId": "tvideo"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "d910ceef496ff2d746176506e296f4b3_z53356_a126365",
+          "bidid": "880184da7ec02b1f42802acb46b63b3c",
+          "seatbid": [{
+            "bid": [{
+              "id": "6ca51ef38eb42820d27503ee96b634b5",
+              "impid": "126365",
+              "price": 0.1,
+              "nurl": "http://test.com/nurl",
+              "burl": "http://test.com/burl",
+              "adm": "<VAST>",
+              "adomain": ["test.com"],
+              "cat": ["IAB1"],
+              "cid": "1",
+              "crid": "1",
+              "w": 300,
+              "h": 250,
+              "ext": {
+                "mediaType": "video"
+              }
+            }],
+            "seat": "1"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "6ca51ef38eb42820d27503ee96b634b5",
+            "impid": "126365",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "<VAST>",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "1",
+            "crid": "1",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "mediaType": "video"
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/params/race/banner.json b/adapters/bidmyadz/bidmyadztest/params/race/banner.json
new file mode 100644
index 00000000..18dce42f
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+  "placementId": "tbanner"
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/params/race/native.json b/adapters/bidmyadz/bidmyadztest/params/race/native.json
new file mode 100644
index 00000000..0600af3a
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/params/race/native.json
@@ -0,0 +1,3 @@
+{
+  "placementId": "tnative"
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/params/race/video.json b/adapters/bidmyadz/bidmyadztest/params/race/video.json
new file mode 100644
index 00000000..85478bf2
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+  "placementId": "tvideo"
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/invalid-device-fields.json b/adapters/bidmyadz/bidmyadztest/supplemental/invalid-device-fields.json
new file mode 100644
index 00000000..d620a050
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/invalid-device-fields.json
@@ -0,0 +1,48 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "expectedMakeRequestsErrors": [{
+    "value": "IP/IPv6 is a required field",
+    "comparison": "literal"
+  }, {
+    "value": "User-Agent is a required field",
+    "comparison": "literal"
+  }]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/invalid-multi-imps.json b/adapters/bidmyadz/bidmyadztest/supplemental/invalid-multi-imps.json
new file mode 100644
index 00000000..09020fc8
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/invalid-multi-imps.json
@@ -0,0 +1,61 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }, {
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.11,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 320,
+        "h": 50
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "3234"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "expectedMakeRequestsErrors": [{
+    "value": "Bidder does not support multi impression",
+    "comparison": "literal"
+  }]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/missing-mediatype.json b/adapters/bidmyadz/bidmyadztest/supplemental/missing-mediatype.json
new file mode 100644
index 00000000..486d7324
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/missing-mediatype.json
@@ -0,0 +1,122 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "d910ceef496ff2d746176506e296f4b3_z53356_a126365",
+          "bidid": "880184da7ec02b1f42802acb46b63b3c",
+          "seatbid": [{
+            "bid": [{
+              "id": "6ca51ef38eb42820d27503ee96b634b5",
+              "impid": "126365",
+              "price": 0.1,
+              "nurl": "http://test.com/nurl",
+              "burl": "http://test.com/burl",
+              "adm": "<ADM>",
+              "adomain": ["test.com"],
+              "cat": ["IAB1"],
+              "cid": "1",
+              "crid": "1",
+              "w": 300,
+              "h": 250
+            }],
+            "seat": "1"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "BidExt parsing error. unexpected end of JSON input",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/response-without-bids.json b/adapters/bidmyadz/bidmyadztest/supplemental/response-without-bids.json
new file mode 100644
index 00000000..fe3361f6
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/response-without-bids.json
@@ -0,0 +1,109 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "d910ceef496ff2d746176506e296f4b3_z53356_a126365",
+          "bidid": "880184da7ec02b1f42802acb46b63b3c",
+          "seatbid": [{
+            "bid": [],
+            "seat": "1"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid.Bids",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/response-without-seatbid.json b/adapters/bidmyadz/bidmyadztest/supplemental/response-without-seatbid.json
new file mode 100644
index 00000000..727e745e
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/response-without-seatbid.json
@@ -0,0 +1,106 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "1"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "a66e61ff8c2ab5460ecf156c4b892fd84d41fad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "1"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "d910ceef496ff2d746176506e296f4b3_z53356_a126365",
+          "bidid": "880184da7ec02b1f42802acb46b63b3c",
+          "seatbid": [],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/status-204.json b/adapters/bidmyadz/bidmyadztest/supplemental/status-204.json
new file mode 100644
index 00000000..05efda0e
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/status-204.json
@@ -0,0 +1,94 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "test"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 204,
+        "body": {}
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/status-400.json b/adapters/bidmyadz/bidmyadztest/supplemental/status-400.json
new file mode 100644
index 00000000..e24acdc6
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/status-400.json
@@ -0,0 +1,101 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "test"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": "Source blocked"
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bad Request. \"Source blocked\"",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/status-service-unavailable.json b/adapters/bidmyadz/bidmyadztest/supplemental/status-service-unavailable.json
new file mode 100644
index 00000000..13e22f55
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/status-service-unavailable.json
@@ -0,0 +1,100 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "test"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 503
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bidder is unavailable. Please contact your account manager.",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/bidmyadztest/supplemental/status-unknown.json b/adapters/bidmyadz/bidmyadztest/supplemental/status-unknown.json
new file mode 100644
index 00000000..69b649e1
--- /dev/null
+++ b/adapters/bidmyadz/bidmyadztest/supplemental/status-unknown.json
@@ -0,0 +1,101 @@
+{
+  "mockBidRequest": {
+    "id": "12345",
+    "imp": [{
+      "id": "1",
+      "secure": 1,
+      "bidfloor": 0.31,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "placementId": "tbanner"
+        }
+      }
+    }],
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+      "geo": {
+        "country": "USA",
+        "lat": 47.627500,
+        "lon": -122.346200
+      },
+      "ip": "18.146.18.241",
+      "devicetype": 2
+    },
+    "user": {
+      "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+    },
+    "site": {
+      "id": "banner",
+      "domain": "test.com",
+      "cat": ["IAB1"],
+      "page": "https://test.com",
+      "publisher": {
+        "id": "test"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://endpoint.bidmyadz.com/c0f68227d14ed938c6c49f3967cbe9bc",
+        "body": {
+          "id": "12345",
+          "imp": [{
+            "id": "1",
+            "secure": 1,
+            "bidfloor": 0.31,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "placementId": "tbanner"
+              }
+            }
+          }],
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36",
+            "geo": {
+              "country": "USA",
+              "lat": 47.627500,
+              "lon": -122.346200
+            },
+            "ip": "18.146.18.241",
+            "devicetype": 2
+          },
+          "user": {
+            "id": "460ecf1d41fa6656c4b892fd84e61ff8c2ab5ad5"
+          },
+          "site": {
+            "id": "banner",
+            "domain": "test.com",
+            "cat": ["IAB1"],
+            "page": "https://test.com",
+            "publisher": {
+              "id": "test"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 403,
+        "body": "Forbidden"
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Something went wrong. Status Code: [ 403 ] \"Forbidden\"",
+      "comparison": "literal"
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/bidmyadz/params_test.go b/adapters/bidmyadz/params_test.go
new file mode 100644
index 00000000..857cde86
--- /dev/null
+++ b/adapters/bidmyadz/params_test.go
@@ -0,0 +1,49 @@
+package bidmyadz
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+var validParams = []string{
+	`{ "placementId": "1234" }`,
+}
+
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderBidmyadz, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected bidmyadz params: %s", validParam)
+		}
+	}
+}
+
+var invalidParams = []string{
+	`1234`,
+	``,
+	`true`,
+	`null`,
+	`[]`,
+	`{}`,
+	`{ "anyparam": "anyvalue" }`,
+	`{ "placementId": null }`,
+}
+
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderBidmyadz, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
diff --git a/adapters/bidmyadz/usersync_test.go b/adapters/bidmyadz/usersync_test.go
new file mode 100644
index 00000000..11b5fedd
--- /dev/null
+++ b/adapters/bidmyadz/usersync_test.go
@@ -0,0 +1,33 @@
+package bidmyadz
+
+import (
+	"testing"
+	"text/template"
+
+	"github.com/prebid/prebid-server/privacy"
+	"github.com/prebid/prebid-server/privacy/ccpa"
+	"github.com/prebid/prebid-server/privacy/gdpr"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewBidmyadzSyncer(t *testing.T) {
+	syncURL := "https://test.com/c0f68227d14ed938c6c49f3967cbe9bc?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}"
+	syncURLTemplate := template.Must(
+		template.New("sync-template").Parse(syncURL),
+	)
+	syncer := NewBidmyadzSyncer(syncURLTemplate)
+	syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+		GDPR: gdpr.Policy{
+			Signal:  "0",
+			Consent: "allGdpr",
+		},
+		CCPA: ccpa.Policy{
+			Consent: "1---",
+		},
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, "https://test.com/c0f68227d14ed938c6c49f3967cbe9bc?gdpr=0&gdpr_consent=allGdpr&ccpa=1---", syncInfo.URL)
+	assert.Equal(t, "redirect", syncInfo.Type)
+	assert.Equal(t, false, syncInfo.SupportCORS)
+}
diff --git a/adapters/outbrain/outbraintest/supplemental/general_params.json b/adapters/outbrain/outbraintest/supplemental/general_params.json
new file mode 100644
index 00000000..b2a547c8
--- /dev/null
+++ b/adapters/outbrain/outbraintest/supplemental/general_params.json
@@ -0,0 +1,139 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "tagid": "tag-id",
+        "ext": {
+          "bidder": {
+            "publisher": {
+              "id": "publisher-id"
+            }
+          }
+        }
+      }
+    ],
+    "bcat": ["bad-category"],
+    "badv": ["bad-advertiser"],
+    "site": {
+      "page": "http://example.com"
+    },
+    "device": {
+      "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36",
+      "h": 500,
+      "w": 1000
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com/bid",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  }
+                ]
+              },
+              "tagid": "tag-id",
+              "ext": {
+                "bidder": {
+                  "publisher": {
+                    "id": "publisher-id"
+                  }
+                }
+              }
+            }
+          ],
+          "bcat": ["bad-category"],
+          "badv": ["bad-advertiser"],
+          "site": {
+            "page": "http://example.com",
+            "publisher": {
+              "id": "publisher-id"
+            }
+          },
+          "device": {
+            "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36",
+            "h": 500,
+            "w": 1000
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "5095a742-1c27-402b-ab6f-66b1bd53383b",
+          "seatbid": [
+            {
+              "bid": [
+                {
+                  "id": "test-request-id",
+                  "impid": "test-imp-id",
+                  "price": 1000,
+                  "nurl": "http://example.com/win/1000",
+                  "adm": "<div>ad</div>",
+                  "adomain": [
+                    "example.com"
+                  ],
+                  "cid": "test-cid",
+                  "crid": "test-crid",
+                  "cat": [
+                    "IAB13-4"
+                  ],
+                  "w": 300,
+                  "h": 250
+                }
+              ],
+              "seat": "acc-1876"
+            }
+          ],
+          "bidid": "43ccadf2-8b2e-11eb-b294-de4c49e99ff6",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "test-request-id",
+            "impid": "test-imp-id",
+            "price": 1000,
+            "nurl": "http://example.com/win/1000",
+            "adm": "<div>ad</div>",
+            "adomain": [
+              "example.com"
+            ],
+            "cid": "test-cid",
+            "crid": "test-crid",
+            "cat": [
+              "IAB13-4"
+            ],
+            "w": 300,
+            "h": 250
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/outbrain/outbraintest/supplemental/optional_params.json b/adapters/outbrain/outbraintest/supplemental/optional_params.json
index a69ceaa0..d75875e0 100644
--- a/adapters/outbrain/outbraintest/supplemental/optional_params.json
+++ b/adapters/outbrain/outbraintest/supplemental/optional_params.json
@@ -12,6 +12,7 @@
             }
           ]
         },
+        "tagid": "should-be-overwritten-tagid",
         "ext": {
           "bidder": {
             "publisher": {
@@ -26,6 +27,8 @@
         }
       }
     ],
+    "bcat": ["should-be-overwritten-bcat"],
+    "badv": ["should-be-overwritten-badv"],
     "site": {
       "page": "http://example.com"
     },
diff --git a/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExt.json b/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExt.json
new file mode 100644
index 00000000..50f677c8
--- /dev/null
+++ b/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExt.json
@@ -0,0 +1,167 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "adSlot": "AdTag_Div1@300x250",
+            "publisherId": "999",
+            "keywords": [
+              {
+                "key": "pmZoneID",
+                "value": [
+                  "Zone1",
+                  "Zone2"
+                ]
+              },
+              {
+                "key": "preference",
+                "value": [
+                  "sports",
+                  "movies"
+                ]
+              }
+            ],
+            "wrapper": {
+              "version": 1,
+              "profile": 5123
+            }
+          },
+          "data": {
+            "adserver": {
+              "name": "gam",
+              "adslot": "/1111/home"
+            },
+            "pbadslot": "/2222/home"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
+    },
+    "site": {
+      "id": "siteID",
+      "publisher": {
+        "id": "1234"
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://hbopenbid.pubmatic.com/translator?source=prebid-server",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "tagid": "AdTag_Div1",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  }
+                ],
+                "h": 250,
+                "w": 300
+              },
+              "ext": {
+                "pmZoneId": "Zone1,Zone2",
+                "preference": "sports,movies",
+                "dfp_ad_unit_code": "/1111/home"
+              }
+            }
+          ],
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
+          },
+          "site": {
+            "id": "siteID",
+            "publisher": {
+              "id": "999"
+            }
+          },
+          "ext": {
+            "wrapper": {
+              "profile": 5123,
+              "version": 1
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "958",
+              "bid": [
+                {
+                  "id": "7706636740145184841",
+                  "impid": "test-imp-id",
+                  "price": 0.500000,
+                  "adid": "29681110",
+                  "adm": "some-test-ad",
+                  "adomain": [
+                    "pubmatic.com"
+                  ],
+                  "crid": "29681110",
+                  "h": 250,
+                  "w": 300,
+                  "dealid": "test deal",
+                  "ext": {
+                    "dspid": 6,
+                    "deal_channel": 1
+                  }
+                }
+              ]
+            }
+          ],
+          "bidid": "5778926625248726496",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7706636740145184841",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adid": "29681110",
+            "adm": "some-test-ad",
+            "adomain": [
+              "pubmatic.com"
+            ],
+            "crid": "29681110",
+            "w": 300,
+            "h": 250,
+            "dealid": "test deal",
+            "ext": {
+              "dspid": 6,
+              "deal_channel": 1
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExtPbAdslot.json b/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExtPbAdslot.json
new file mode 100644
index 00000000..cc057909
--- /dev/null
+++ b/adapters/pubmatic/pubmatictest/supplemental/gptSlotNameInImpExtPbAdslot.json
@@ -0,0 +1,163 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "adSlot": "AdTag_Div1@300x250",
+            "publisherId": "999",
+            "keywords": [
+              {
+                "key": "pmZoneID",
+                "value": [
+                  "Zone1",
+                  "Zone2"
+                ]
+              },
+              {
+                "key": "preference",
+                "value": [
+                  "sports",
+                  "movies"
+                ]
+              }
+            ],
+            "wrapper": {
+              "version": 1,
+              "profile": 5123
+            }
+          },
+          "data": {
+            "pbadslot": "/2222/home"
+          }
+        }
+      }
+    ],
+    "device": {
+      "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
+    },
+    "site": {
+      "id": "siteID",
+      "publisher": {
+        "id": "1234"
+      }
+    }
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "https://hbopenbid.pubmatic.com/translator?source=prebid-server",
+        "body": {
+          "id": "test-request-id",
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "tagid": "AdTag_Div1",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  }
+                ],
+                "h": 250,
+                "w": 300
+              },
+              "ext": {
+                "pmZoneId": "Zone1,Zone2",
+                "preference": "sports,movies",
+                "dfp_ad_unit_code": "/2222/home"
+              }
+            }
+          ],
+          "device": {
+            "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36"
+          },
+          "site": {
+            "id": "siteID",
+            "publisher": {
+              "id": "999"
+            }
+          },
+          "ext": {
+            "wrapper": {
+              "profile": 5123,
+              "version": 1
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "958",
+              "bid": [
+                {
+                  "id": "7706636740145184841",
+                  "impid": "test-imp-id",
+                  "price": 0.500000,
+                  "adid": "29681110",
+                  "adm": "some-test-ad",
+                  "adomain": [
+                    "pubmatic.com"
+                  ],
+                  "crid": "29681110",
+                  "h": 250,
+                  "w": 300,
+                  "dealid": "test deal",
+                  "ext": {
+                    "dspid": 6,
+                    "deal_channel": 1
+                  }
+                }
+              ]
+            }
+          ],
+          "bidid": "5778926625248726496",
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "7706636740145184841",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adid": "29681110",
+            "adm": "some-test-ad",
+            "adomain": [
+              "pubmatic.com"
+            ],
+            "crid": "29681110",
+            "w": 300,
+            "h": 250,
+            "dealid": "test deal",
+            "ext": {
+              "dspid": 6,
+              "deal_channel": 1
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/rubicon/rubicon_test.go b/adapters/rubicon/rubicon_test.go
index dc5b3a90..8f8d3fb1 100644
--- a/adapters/rubicon/rubicon_test.go
+++ b/adapters/rubicon/rubicon_test.go
@@ -572,6 +572,52 @@ func TestResolveVideoSizeId(t *testing.T) {
 	}
 }
 
+func TestResolveBidFloorAttributes(t *testing.T) {
+	testScenarios := []struct {
+		bidFloor            float64
+		bidFloorCur         string
+		expectedBidFloor    float64
+		expectedBidFloorCur string
+	}{
+		{
+			bidFloor:            1,
+			bidFloorCur:         "EUR",
+			expectedBidFloor:    1.2,
+			expectedBidFloorCur: "USD",
+		},
+		{
+			bidFloor:            1,
+			bidFloorCur:         "Eur",
+			expectedBidFloor:    1.2,
+			expectedBidFloorCur: "USD",
+		},
+		{
+			bidFloor:            0,
+			bidFloorCur:         "EUR",
+			expectedBidFloor:    0,
+			expectedBidFloorCur: "EUR",
+		},
+		{
+			bidFloor:            -1,
+			bidFloorCur:         "EUR",
+			expectedBidFloor:    -1,
+			expectedBidFloorCur: "EUR",
+		},
+		{
+			bidFloor:            1,
+			bidFloorCur:         "USD",
+			expectedBidFloor:    1,
+			expectedBidFloorCur: "USD",
+		},
+	}
+
+	for _, scenario := range testScenarios {
+		bidFloor, bidFloorCur := resolveBidFloorAttributes(scenario.bidFloor, scenario.bidFloorCur)
+		assert.Equal(t, scenario.expectedBidFloor, bidFloor)
+		assert.Equal(t, scenario.expectedBidFloorCur, bidFloorCur)
+	}
+}
+
 func TestNoContentResponse(t *testing.T) {
 	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 		w.WriteHeader(http.StatusNoContent)
diff --git a/adapters/rubicon/rubicontest/exemplary/simple-video.json b/adapters/rubicon/rubicontest/exemplary/simple-video.json
index b85c28de..a90670e5 100644
--- a/adapters/rubicon/rubicontest/exemplary/simple-video.json
+++ b/adapters/rubicon/rubicontest/exemplary/simple-video.json
@@ -71,6 +71,8 @@
           "w": 1024,
           "h": 576
         },
+        "bidfloor": 1,
+        "bidfloorcur": "EuR",
         "ext": {
           "bidder": {
             "video": {
@@ -192,6 +194,8 @@
                 "w": 1024,
                 "h": 576
               },
+              "bidfloor": 1.2,
+              "bidfloorcur": "USD",
               "ext": {
                 "rp": {
                   "track": {
diff --git a/adapters/sa_lunamedia/params_test.go b/adapters/sa_lunamedia/params_test.go
new file mode 100644
index 00000000..bf7a1f49
--- /dev/null
+++ b/adapters/sa_lunamedia/params_test.go
@@ -0,0 +1,52 @@
+package salunamedia
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+var validParams = []string{
+	`{ "key": "2", "type": "network"}`,
+	`{ "key": "1"}`,
+	`{ "key": "33232", "type": "publisher"}`,
+}
+
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderSaLunaMedia, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected sa_lunamedia params: %s", validParam)
+		}
+	}
+}
+
+var invalidParams = []string{
+	``,
+	`null`,
+	`true`,
+	`5`,
+	`[]`,
+	`{}`,
+	`{ "anyparam": "anyvalue" }`,
+	`{ "type": "network" }`,
+	`{ "key": "asddsfd", "type": "any"}`,
+}
+
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderSaLunaMedia, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
diff --git a/adapters/sa_lunamedia/salunamedia_test.go b/adapters/sa_lunamedia/salunamedia_test.go
new file mode 100644
index 00000000..f5d20582
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamedia_test.go
@@ -0,0 +1,18 @@
+package salunamedia
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderSaLunaMedia, config.Adapter{
+		Endpoint: "http://test.com/pserver"})
+
+	assert.NoError(t, buildErr)
+	adapterstest.RunJSONBidderTest(t, "salunamediatest", bidder)
+}
diff --git a/adapters/sa_lunamedia/salunamediatest/exemplary/banner.json b/adapters/sa_lunamedia/salunamediatest/exemplary/banner.json
new file mode 100644
index 00000000..2ce4ad81
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/exemplary/banner.json
@@ -0,0 +1,142 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "id",
+          "bidid": "id",
+          "seatbid": [{
+            "bid": [{
+              "id": "id",
+              "impid": "id",
+              "price": 0.1,
+              "nurl": "http://test.com/nurl",
+              "burl": "http://test.com/burl",
+              "adm": "<span>Test</span>",
+              "adomain": ["test.com"],
+              "cat": ["IAB1"],
+              "cid": "cid",
+              "crid": "crid",
+              "w": 300,
+              "h": 250,
+              "ext": {
+                "mediaType": "banner"
+              }
+            }],
+            "seat": "seat"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "id",
+            "impid": "id",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "<span>Test</span>",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "cid",
+            "crid": "crid",
+            "w": 300,
+            "h": 250,
+            "ext": {
+              "mediaType": "banner"
+            }
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/exemplary/native.json b/adapters/sa_lunamedia/salunamediatest/exemplary/native.json
new file mode 100644
index 00000000..74d8940f
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/exemplary/native.json
@@ -0,0 +1,132 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "native": {
+        "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}",
+        "ver": "1.1"
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://test.com/pserver",
+      "body": {
+        "id": "id",
+        "imp": [{
+          "id": "id",
+          "secure": 1,
+          "bidfloor": 0.01,
+          "bidfloorcur": "USD",
+          "native": {
+            "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}",
+            "ver": "1.1"
+          },
+          "ext": {
+            "bidder": {
+              "key": "test"
+            }
+          }
+        }],
+        "device": {
+          "ua": "UA",
+          "ip": "123.3.4.123"
+        },
+        "regs": {
+          "ext": {
+            "gdpr": 0
+          }
+        },
+        "user": {
+          "id": "userid"
+        },
+        "site": {
+          "id": "id",
+          "domain": "test,com",
+          "cat": ["IAB12"],
+          "publisher": {
+            "id": "pubid"
+          }
+        }
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": {
+        "id": "id",
+        "bidid": "id",
+        "seatbid": [{
+          "bid": [{
+            "id": "id",
+            "impid": "id",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "{}",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "cid",
+            "crid": "crid",
+            "ext": {
+              "mediaType": "native"
+            }
+          }],
+          "seat": "seat"
+        }],
+        "cur": "USD"
+      }
+    }
+  }],
+
+  "expectedBidResponses": [{
+    "currency": "USD",
+    "bids": [{
+      "bid": {
+        "id": "id",
+        "impid": "id",
+        "price": 0.1,
+        "nurl": "http://test.com/nurl",
+        "burl": "http://test.com/burl",
+        "adm": "{}",
+        "adomain": ["test.com"],
+        "cat": ["IAB1"],
+        "cid": "cid",
+        "crid": "crid",
+        "ext": {
+          "mediaType": "native"
+        }
+      },
+      "type": "native"
+    }]
+  }]
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/exemplary/video.json b/adapters/sa_lunamedia/salunamediatest/exemplary/video.json
new file mode 100644
index 00000000..9a042d72
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/exemplary/video.json
@@ -0,0 +1,169 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "video": {
+        "mimes": ["video/mp4", "video/ogg", "video/webm"],
+        "minduration": 3,
+        "maxduration": 3000,
+        "protocols": [2, 3, 5, 6, 7, 8],
+        "w": 480,
+        "h": 320,
+        "linearity": 1,
+        "playbackmethod": [2],
+        "pos": 0
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [
+            {
+              "id": "id",
+              "secure": 1,
+              "bidfloor": 0.01,
+              "bidfloorcur": "USD",
+              "video": {
+                "mimes": [
+                  "video/mp4",
+                  "video/ogg",
+                  "video/webm"
+                ],
+                "minduration": 3,
+                "maxduration": 3000,
+                "protocols": [
+                  2,
+                  3,
+                  5,
+                  6,
+                  7,
+                  8
+                ],
+                "w": 480,
+                "h": 320,
+                "linearity": 1,
+                "playbackmethod": [
+                  2
+                ],
+                "pos": 0
+              },
+              "ext": {
+                "bidder": {
+                  "key": "test"
+                }
+              }
+            }
+          ],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": [
+              "IAB12"
+            ],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "id",
+          "bidid": "id",
+          "seatbid": [{
+            "bid": [{
+              "id": "id",
+              "impid": "id",
+              "price": 0.1,
+              "nurl": "http://test.com/nurl",
+              "burl": "http://test.com/burl",
+              "adm": "<VAST>",
+              "adomain": ["test.com"],
+              "cat": ["IAB1"],
+              "cid": "cid",
+              "crid": "crid",
+              "ext": {
+                "mediaType": "video"
+              }
+            }],
+            "seat": "seat"
+          }],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "currency": "USD",
+      "bids": [
+        {
+          "bid": {
+            "id": "id",
+            "impid": "id",
+            "price": 0.1,
+            "nurl": "http://test.com/nurl",
+            "burl": "http://test.com/burl",
+            "adm": "<VAST>",
+            "adomain": ["test.com"],
+            "cat": ["IAB1"],
+            "cid": "cid",
+            "crid": "crid",
+            "ext": {
+              "mediaType": "video"
+            }
+          },
+          "type": "video"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/params/race/banner.json b/adapters/sa_lunamedia/salunamediatest/params/race/banner.json
new file mode 100644
index 00000000..c02a5de9
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+  "key": "test"
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/params/race/native.json b/adapters/sa_lunamedia/salunamediatest/params/race/native.json
new file mode 100644
index 00000000..c02a5de9
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/params/race/native.json
@@ -0,0 +1,3 @@
+{
+  "key": "test"
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/params/race/video.json b/adapters/sa_lunamedia/salunamediatest/params/race/video.json
new file mode 100644
index 00000000..c02a5de9
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+  "key": "test"
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/bad-response.json b/adapters/sa_lunamedia/salunamediatest/supplemental/bad-response.json
new file mode 100644
index 00000000..6373207d
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/bad-response.json
@@ -0,0 +1,98 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": ""
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "json: cannot unmarshal string into Go value of type openrtb2.BidResponse",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/empty-seatbid.json b/adapters/sa_lunamedia/salunamediatest/supplemental/empty-seatbid.json
new file mode 100644
index 00000000..8942b3be
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/empty-seatbid.json
@@ -0,0 +1,102 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [{
+    "expectedRequest": {
+      "uri": "http://test.com/pserver",
+      "body": {
+        "id": "id",
+        "imp": [{
+          "id": "id",
+          "secure": 1,
+          "bidfloor": 0.01,
+          "bidfloorcur": "USD",
+          "banner": {
+            "w": 300,
+            "h": 250
+          },
+          "ext": {
+            "bidder": {
+              "key": "test"
+            }
+          }
+        }],
+        "device": {
+          "ua": "UA",
+          "ip": "123.3.4.123"
+        },
+        "regs": {
+          "ext": {
+            "gdpr": 0
+          }
+        },
+        "user": {
+          "id": "userid"
+        },
+        "site": {
+          "id": "id",
+          "domain": "test,com",
+          "cat": ["IAB12"],
+          "publisher": {
+            "id": "pubid"
+          }
+        }
+      }
+    },
+    "mockResponse": {
+      "status": 200,
+      "body": {
+        "id": "a1580f2f-be6d-11eb-a150-d094662c1c35",
+        "bidid": "359da97d0384d8a14767029c18fd840d",
+        "seatbid": [],
+        "cur": "USD"
+      }
+    }
+  }],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Empty SeatBid",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/status-204.json b/adapters/sa_lunamedia/salunamediatest/supplemental/status-204.json
new file mode 100644
index 00000000..042b96bd
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/status-204.json
@@ -0,0 +1,92 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 204,
+        "body": {}
+      }
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/status-400.json b/adapters/sa_lunamedia/salunamediatest/supplemental/status-400.json
new file mode 100644
index 00000000..1ecdc46e
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/status-400.json
@@ -0,0 +1,99 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 400,
+        "body": "The Key has a different ad format"
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bad Request. \"The Key has a different ad format\"",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/status-503.json b/adapters/sa_lunamedia/salunamediatest/supplemental/status-503.json
new file mode 100644
index 00000000..2590418a
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/status-503.json
@@ -0,0 +1,98 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 503
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bidder unavailable. Please contact the bidder support.",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/salunamediatest/supplemental/unexpected-status.json b/adapters/sa_lunamedia/salunamediatest/supplemental/unexpected-status.json
new file mode 100644
index 00000000..a54737ca
--- /dev/null
+++ b/adapters/sa_lunamedia/salunamediatest/supplemental/unexpected-status.json
@@ -0,0 +1,99 @@
+{
+  "mockBidRequest": {
+    "id": "id",
+    "imp": [{
+      "id": "id",
+      "secure": 1,
+      "bidfloor": 0.01,
+      "bidfloorcur": "USD",
+      "banner": {
+        "w": 300,
+        "h": 250
+      },
+      "ext": {
+        "bidder": {
+          "key": "test"
+        }
+      }
+    }],
+    "device": {
+      "ua": "UA",
+      "ip": "123.3.4.123"
+    },
+    "regs": {
+      "ext": {
+        "gdpr": 0
+      }
+    },
+    "user": {
+      "id": "userid"
+    },
+    "site": {
+      "id": "id",
+      "domain": "test,com",
+      "cat": ["IAB12"],
+      "publisher": {
+        "id": "pubid"
+      }
+    }
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://test.com/pserver",
+        "body": {
+          "id": "id",
+          "imp": [{
+            "id": "id",
+            "secure": 1,
+            "bidfloor": 0.01,
+            "bidfloorcur": "USD",
+            "banner": {
+              "w": 300,
+              "h": 250
+            },
+            "ext": {
+              "bidder": {
+                "key": "test"
+              }
+            }
+          }],
+          "device": {
+            "ua": "UA",
+            "ip": "123.3.4.123"
+          },
+          "regs": {
+            "ext": {
+              "gdpr": 0
+            }
+          },
+          "user": {
+            "id": "userid"
+          },
+          "site": {
+            "id": "id",
+            "domain": "test,com",
+            "cat": ["IAB12"],
+            "publisher": {
+              "id": "pubid"
+            }
+          }
+        }
+      },
+      "mockResponse": {
+        "status": 403,
+        "body": "Access is denied"
+      }
+    }
+  ],
+
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Status Code: [ 403 ] \"Access is denied\"",
+      "comparison": "literal"
+    }
+  ],
+
+  "expectedBidResponses": []
+}
\ No newline at end of file
diff --git a/adapters/sa_lunamedia/usersync_test.go b/adapters/sa_lunamedia/usersync_test.go
new file mode 100644
index 00000000..e3820fbc
--- /dev/null
+++ b/adapters/sa_lunamedia/usersync_test.go
@@ -0,0 +1,33 @@
+package salunamedia
+
+import (
+	"testing"
+	"text/template"
+
+	"github.com/prebid/prebid-server/privacy"
+	"github.com/prebid/prebid-server/privacy/ccpa"
+	"github.com/prebid/prebid-server/privacy/gdpr"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewSaLunamediaSyncer(t *testing.T) {
+	syncURL := "https://test.com/pserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&ccpa={{.USPrivacy}}"
+	syncURLTemplate := template.Must(
+		template.New("sync-template").Parse(syncURL),
+	)
+	syncer := NewSaLunamediaSyncer(syncURLTemplate)
+	syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+		GDPR: gdpr.Policy{
+			Signal:  "0",
+			Consent: "allGdpr",
+		},
+		CCPA: ccpa.Policy{
+			Consent: "1---",
+		},
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, "https://test.com/pserver?gdpr=0&gdpr_consent=allGdpr&ccpa=1---", syncInfo.URL)
+	assert.Equal(t, "redirect", syncInfo.Type)
+	assert.Equal(t, false, syncInfo.SupportCORS)
+}
diff --git a/adapters/smilewanted/params_test.go b/adapters/smilewanted/params_test.go
new file mode 100644
index 00000000..2ea032d6
--- /dev/null
+++ b/adapters/smilewanted/params_test.go
@@ -0,0 +1,58 @@
+package smilewanted
+
+import (
+	"encoding/json"
+	"testing"
+
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+// This file actually intends to test static/bidder-params/smilewanted.json
+//
+// These also validate the format of the external API: request.imp[i].ext.smilewanted
+
+// TestValidParams makes sure that the smilewanted schema accepts all imp.ext fields which we intend to support.
+func TestValidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, validParam := range validParams {
+		if err := validator.Validate(openrtb_ext.BidderSmileWanted, json.RawMessage(validParam)); err != nil {
+			t.Errorf("Schema rejected SmileWanted params: %s", validParam)
+		}
+	}
+}
+
+// TestInvalidParams makes sure that the SmileWanted schema rejects all the imp.ext fields we don't support.
+func TestInvalidParams(t *testing.T) {
+	validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params")
+	if err != nil {
+		t.Fatalf("Failed to fetch the json-schemas. %v", err)
+	}
+
+	for _, invalidParam := range invalidParams {
+		if err := validator.Validate(openrtb_ext.BidderSmileWanted, json.RawMessage(invalidParam)); err == nil {
+			t.Errorf("Schema allowed unexpected params: %s", invalidParam)
+		}
+	}
+}
+
+var validParams = []string{
+	`{"zoneId": "zone_code"}`,
+}
+
+var invalidParams = []string{
+	`{"zoneId": 100}`,
+	`{"zoneId": true}`,
+	`{"zoneId": 123}`,
+	`{"zoneID": "1"}`,
+	``,
+	`null`,
+	`true`,
+	`9`,
+	`1.2`,
+	`[]`,
+	`{}`,
+}
diff --git a/adapters/smilewanted/smilewanted_test.go b/adapters/smilewanted/smilewanted_test.go
new file mode 100644
index 00000000..75e7849e
--- /dev/null
+++ b/adapters/smilewanted/smilewanted_test.go
@@ -0,0 +1,20 @@
+package smilewanted
+
+import (
+	"testing"
+
+	"github.com/prebid/prebid-server/adapters/adapterstest"
+	"github.com/prebid/prebid-server/config"
+	"github.com/prebid/prebid-server/openrtb_ext"
+)
+
+func TestJsonSamples(t *testing.T) {
+	bidder, buildErr := Builder(openrtb_ext.BidderSmileWanted, config.Adapter{
+		Endpoint: "http://example.com"})
+
+	if buildErr != nil {
+		t.Fatalf("Builder returned unexpected error %v", buildErr)
+	}
+
+	adapterstest.RunJSONBidderTest(t, "smilewantedtest", bidder)
+}
diff --git a/adapters/smilewanted/smilewantedtest/exemplary/simple-banner.json b/adapters/smilewanted/smilewantedtest/exemplary/simple-banner.json
new file mode 100644
index 00000000..0c68d74c
--- /dev/null
+++ b/adapters/smilewanted/smilewantedtest/exemplary/simple-banner.json
@@ -0,0 +1,94 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "at" : 1,
+        "banner": {
+          "format": [
+            {
+                "w": 300,
+                "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone_code_test_display"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com",
+        "body": {
+          "id": "test-request-id",
+          "at" : 1,
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                      "w": 300,
+                      "h": 250
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone_code_test_display"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "seatbid": [
+            {
+              "seat": "smilewanted",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.5,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "h": 250,
+                "w": 300
+              }]
+            }
+          ],
+          "cur": "USD"
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [
+        {
+          "bid": {
+            "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+            "impid": "test-imp-id",
+            "price": 0.5,
+            "adm": "some-test-ad",
+            "crid": "crid_10",
+            "h": 250,
+            "w": 300
+          },
+          "type": "banner"
+        }
+      ]
+    }
+  ]
+}
diff --git a/adapters/smilewanted/smilewantedtest/exemplary/simple-video.json b/adapters/smilewanted/smilewantedtest/exemplary/simple-video.json
new file mode 100644
index 00000000..b3ff9ba9
--- /dev/null
+++ b/adapters/smilewanted/smilewantedtest/exemplary/simple-video.json
@@ -0,0 +1,87 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "video": {
+          "mimes": ["video/mp4"],
+          "protocols": [2, 5],
+          "w": 1024,
+          "h": 576
+        },
+        "ext":{
+          "bidder":{
+            "zoneId": "zone_code_test_video"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com",
+        "body": {
+          "id": "test-request-id",
+          "at": 1,
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "video": {
+                "mimes": ["video/mp4"],
+                "protocols": [2, 5],
+                "w": 1024,
+                "h": 576
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone_code_test_video"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": {
+          "id": "test-request-id",
+          "cur": "USD",
+          "seatbid": [
+            {
+              "seat": "smilewanted",
+              "bid": [{
+                "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+                "impid": "test-imp-id",
+                "price": 0.5,
+                "adm": "some-test-ad",
+                "crid": "crid_10",
+                "w": 1024,
+                "h": 576
+              }]
+            }
+          ]
+        }
+      }
+    }
+  ],
+
+  "expectedBidResponses": [
+    {
+      "bids": [{
+        "bid": {
+          "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800",
+          "impid": "test-imp-id",
+          "price": 0.5,
+          "adm": "some-test-ad",
+          "crid": "crid_10",
+          "w": 1024,
+          "h": 576
+        },
+        "type": "video"
+      }]
+    }
+  ]
+}
diff --git a/adapters/smilewanted/smilewantedtest/params/race/banner.json b/adapters/smilewanted/smilewantedtest/params/race/banner.json
new file mode 100644
index 00000000..42dddd70
--- /dev/null
+++ b/adapters/smilewanted/smilewantedtest/params/race/banner.json
@@ -0,0 +1,3 @@
+{
+  "zoneId": "zone_code_test_display"
+}
diff --git a/adapters/smilewanted/smilewantedtest/params/race/video.json b/adapters/smilewanted/smilewantedtest/params/race/video.json
new file mode 100644
index 00000000..64ac780e
--- /dev/null
+++ b/adapters/smilewanted/smilewantedtest/params/race/video.json
@@ -0,0 +1,3 @@
+{
+  "zoneId": "zone_code_test_video"
+}
diff --git a/adapters/smilewanted/smilewantedtest/supplemental/bad-server-response.json b/adapters/smilewanted/smilewantedtest/supplemental/bad-server-response.json
new file mode 100644
index 00000000..461ad932
--- /dev/null
+++ b/adapters/smilewanted/smilewantedtest/supplemental/bad-server-response.json
@@ -0,0 +1,63 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "at" : 1,
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone_code_test_display"
+          }
+        }
+      }
+    ]
+  },
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com",
+        "body": {
+          "id": "test-request-id",
+          "at" : 1,
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone_code_test_display"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 200,
+        "body": "bad_json"
+      }
+    }
+  ],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Bad server response: json: cannot unmarshal string into Go value of type openrtb2.BidResponse.",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/smilewanted/smilewantedtest/supplemental/status-code-204.json b/adapters/smilewanted/smilewantedtest/supplemental/status-code-204.json
new file mode 100644
index 00000000..0d8a432e
--- /dev/null
+++ b/adapters/smilewanted/smilewantedtest/supplemental/status-code-204.json
@@ -0,0 +1,59 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "at" : 1,
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone_code_test_display"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com",
+        "body": {
+          "id": "test-request-id",
+          "at" : 1,
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone_code_test_display"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 204
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": []
+}
diff --git a/adapters/smilewanted/smilewantedtest/supplemental/status-code-400.json b/adapters/smilewanted/smilewantedtest/supplemental/status-code-400.json
new file mode 100644
index 00000000..bdf2caa3
--- /dev/null
+++ b/adapters/smilewanted/smilewantedtest/supplemental/status-code-400.json
@@ -0,0 +1,64 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "at" : 1,
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone_code_test_display"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com",
+        "body": {
+          "id": "test-request-id",
+          "at" : 1,
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone_code_test_display"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 400
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 400.",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/smilewanted/smilewantedtest/supplemental/unexpected-status-code.json b/adapters/smilewanted/smilewantedtest/supplemental/unexpected-status-code.json
new file mode 100644
index 00000000..49a11e3e
--- /dev/null
+++ b/adapters/smilewanted/smilewantedtest/supplemental/unexpected-status-code.json
@@ -0,0 +1,64 @@
+{
+  "mockBidRequest": {
+    "id": "test-request-id",
+    "imp": [
+      {
+        "id": "test-imp-id",
+        "at" : 1,
+        "banner": {
+          "format": [
+            {
+              "w": 300,
+              "h": 250
+            }
+          ]
+        },
+        "ext": {
+          "bidder": {
+            "zoneId": "zone_code_test_display"
+          }
+        }
+      }
+    ]
+  },
+
+  "httpCalls": [
+    {
+      "expectedRequest": {
+        "uri": "http://example.com",
+        "body": {
+          "id": "test-request-id",
+          "at" : 1,
+          "imp": [
+            {
+              "id": "test-imp-id",
+              "banner": {
+                "format": [
+                  {
+                    "w": 300,
+                    "h": 250
+                  }
+                ]
+              },
+              "ext": {
+                "bidder": {
+                  "zoneId": "zone_code_test_display"
+                }
+              }
+            }
+          ]
+        }
+      },
+      "mockResponse": {
+        "status": 500
+      }
+    }
+  ],
+  "expectedBidResponses": [],
+  "expectedMakeBidsErrors": [
+    {
+      "value": "Unexpected status code: 500. Run with request.debug = 1 for more info.",
+      "comparison": "literal"
+    }
+  ]
+}
diff --git a/adapters/smilewanted/usersync_test.go b/adapters/smilewanted/usersync_test.go
new file mode 100644
index 00000000..497e5061
--- /dev/null
+++ b/adapters/smilewanted/usersync_test.go
@@ -0,0 +1,34 @@
+package smilewanted
+
+import (
+	"testing"
+	"text/template"
+
+	"github.com/prebid/prebid-server/privacy"
+	"github.com/prebid/prebid-server/privacy/ccpa"
+	"github.com/prebid/prebid-server/privacy/gdpr"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestSmileWantedSyncer(t *testing.T) {
+	syncURL := "//csync.smilewanted.com/getuid?source=prebid-server&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect=https%3A%2F%2Flocalhost%2Fsetuid%3Fbidder%3Dsmilewanted%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID"
+	syncURLTemplate := template.Must(
+		template.New("sync-template").Parse(syncURL),
+	)
+
+	syncer := NewSmileWantedSyncer(syncURLTemplate)
+	syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{
+		GDPR: gdpr.Policy{
+			Signal:  "1",
+			Consent: "COyASAoOyASAoAfAAAENAfCAAAAAAAAAAAAAAAAAAAAA",
+		},
+		CCPA: ccpa.Policy{
+			Consent: "1YNN",
+		},
+	})
+
+	assert.NoError(t, err)
+	assert.Equal(t, "//csync.smilewanted.com/getuid?source=prebid-server&gdpr=1&gdpr_consent=COyASAoOyASAoAfAAAENAfCAAAAAAAAAAAAAAAAAAAAA&us_privacy=1YNN&redirect=https%3A%2F%2Flocalhost%2Fsetuid%3Fbidder%3Dsmilewanted%26gdpr%3D1%26gdpr_consent%3DCOyASAoOyASAoAfAAAENAfCAAAAAAAAAAAAAAAAAAAAA%26uid%3D%24UID", syncInfo.URL)
+	assert.Equal(t, "redirect", syncInfo.Type)
+	assert.Equal(t, false, syncInfo.SupportCORS)
+}
diff --git a/config/config_test.go b/config/config_test.go
index a2b28d02..fa9dcdc5 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -116,10 +116,7 @@ func TestExternalCacheURLValidate(t *testing.T) {
 }
 
 func TestDefaults(t *testing.T) {
-	v := viper.New()
-	SetupViper(v, "")
-	cfg, err := New(v)
-	assert.NoError(t, err, "Setting up config should work but it doesn't")
+	cfg, _ := newDefaultConfig(t)
 
 	cmpInts(t, "port", cfg.Port, 8000)
 	cmpInts(t, "admin_port", cfg.AdminPort, 6060)
@@ -148,7 +145,7 @@ func TestDefaults(t *testing.T) {
 var fullConfig = []byte(`
 gdpr:
   host_vendor_id: 15
-  default_value: "0"
+  default_value: "1"
   non_standard_publishers: ["siteID","fake-site-id","appID","agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA"]
 ccpa:
   enforce: true
@@ -352,7 +349,7 @@ func TestFullConfig(t *testing.T) {
 	cmpInts(t, "http_client_cache.max_idle_connections_per_host", cfg.CacheClient.MaxIdleConnsPerHost, 2)
 	cmpInts(t, "http_client_cache.idle_connection_timeout_seconds", cfg.CacheClient.IdleConnTimeout, 3)
 	cmpInts(t, "gdpr.host_vendor_id", cfg.GDPR.HostVendorID, 15)
-	cmpStrings(t, "gdpr.default_value", cfg.GDPR.DefaultValue, "0")
+	cmpStrings(t, "gdpr.default_value", cfg.GDPR.DefaultValue, "1")
 
 	//Assert the NonStandardPublishers was correctly unmarshalled
 	cmpStrings(t, "gdpr.non_standard_publishers", cfg.GDPR.NonStandardPublishers[0], "siteID")
@@ -429,6 +426,7 @@ func TestFullConfig(t *testing.T) {
 func TestUnmarshalAdapterExtraInfo(t *testing.T) {
 	v := viper.New()
 	SetupViper(v, "")
+	v.Set("gdpr.default_value", "0")
 	v.SetConfigType("yaml")
 	v.ReadConfig(bytes.NewBuffer(adapterExtraInfoConfig))
 	cfg, err := New(v)
@@ -484,14 +482,18 @@ func TestValidConfig(t *testing.T) {
 		},
 	}
 
+	v := viper.New()
+	v.Set("gdpr.default_value", "0")
+
 	resolvedStoredRequestsConfig(&cfg)
-	err := cfg.validate()
+	err := cfg.validate(v)
 	assert.Nil(t, err, "OpenRTB filesystem config should work. %v", err)
 }
 
 func TestMigrateConfig(t *testing.T) {
 	v := viper.New()
 	SetupViper(v, "")
+	v.Set("gdpr.default_value", "0")
 	v.SetConfigType("yaml")
 	v.ReadConfig(bytes.NewBuffer(oldStoredRequestsConfig))
 	migrateConfig(v)
@@ -508,10 +510,7 @@ func TestMigrateConfigFromEnv(t *testing.T) {
 		defer os.Unsetenv("PBS_STORED_REQUESTS_FILESYSTEM")
 	}
 	os.Setenv("PBS_STORED_REQUESTS_FILESYSTEM", "true")
-	v := viper.New()
-	SetupViper(v, "")
-	cfg, err := New(v)
-	assert.NoError(t, err, "Setting up config should work but it doesn't")
+	cfg, _ := newDefaultConfig(t)
 	cmpBools(t, "stored_requests.filesystem.enabled", true, cfg.StoredRequests.Files.Enabled)
 }
 
@@ -591,6 +590,7 @@ func TestMigrateConfigPurposeOneTreatment(t *testing.T) {
 func TestInvalidAdapterEndpointConfig(t *testing.T) {
 	v := viper.New()
 	SetupViper(v, "")
+	v.Set("gdpr.default_value", "0")
 	v.SetConfigType("yaml")
 	v.ReadConfig(bytes.NewBuffer(invalidAdapterEndpointConfig))
 	_, err := New(v)
@@ -600,6 +600,7 @@ func TestInvalidAdapterEndpointConfig(t *testing.T) {
 func TestInvalidAdapterUserSyncURLConfig(t *testing.T) {
 	v := viper.New()
 	SetupViper(v, "")
+	v.Set("gdpr.default_value", "0")
 	v.SetConfigType("yaml")
 	v.ReadConfig(bytes.NewBuffer(invalidUserSyncURLConfig))
 	_, err := New(v)
@@ -607,16 +608,16 @@ func TestInvalidAdapterUserSyncURLConfig(t *testing.T) {
 }
 
 func TestNegativeRequestSize(t *testing.T) {
-	cfg := newDefaultConfig(t)
+	cfg, v := newDefaultConfig(t)
 	cfg.MaxRequestSize = -1
-	assertOneError(t, cfg.validate(), "cfg.max_request_size must be >= 0. Got -1")
+	assertOneError(t, cfg.validate(v), "cfg.max_request_size must be >= 0. Got -1")
 }
 
 func TestNegativePrometheusTimeout(t *testing.T) {
-	cfg := newDefaultConfig(t)
+	cfg, v := newDefaultConfig(t)
 	cfg.Metrics.Prometheus.Port = 8001
 	cfg.Metrics.Prometheus.TimeoutMillisRaw = 0
-	assertOneError(t, cfg.validate(), "metrics.prometheus.timeout_ms must be positive if metrics.prometheus.port is defined. Got timeout=0 and port=8001")
+	assertOneError(t, cfg.validate(v), "metrics.prometheus.timeout_ms must be positive if metrics.prometheus.port is defined. Got timeout=0 and port=8001")
 }
 
 func TestInvalidHostVendorID(t *testing.T) {
@@ -638,9 +639,9 @@ func TestInvalidHostVendorID(t *testing.T) {
 	}
 
 	for _, tt := range tests {
-		cfg := newDefaultConfig(t)
+		cfg, v := newDefaultConfig(t)
 		cfg.GDPR.HostVendorID = tt.vendorID
-		errs := cfg.validate()
+		errs := cfg.validate(v)
 
 		assert.Equal(t, 1, len(errs), tt.description)
 		assert.EqualError(t, errs[0], tt.wantErrorMsg, tt.description)
@@ -648,34 +649,47 @@ func TestInvalidHostVendorID(t *testing.T) {
 }
 
 func TestInvalidAMPException(t *testing.T) {
-	cfg := newDefaultConfig(t)
+	cfg, v := newDefaultConfig(t)
 	cfg.GDPR.AMPException = true
-	assertOneError(t, cfg.validate(), "gdpr.amp_exception has been discontinued and must be removed from your config. If you need to disable GDPR for AMP, you may do so per-account (gdpr.integration_enabled.amp) or at the host level for the default account (account_defaults.gdpr.integration_enabled.amp)")
+	assertOneError(t, cfg.validate(v), "gdpr.amp_exception has been discontinued and must be removed from your config. If you need to disable GDPR for AMP, you may do so per-account (gdpr.integration_enabled.amp) or at the host level for the default account (account_defaults.gdpr.integration_enabled.amp)")
 }
 
 func TestInvalidGDPRDefaultValue(t *testing.T) {
-	cfg := newDefaultConfig(t)
+	cfg, v := newDefaultConfig(t)
 	cfg.GDPR.DefaultValue = "2"
-	assertOneError(t, cfg.validate(), "gdpr.default_value must be 0 or 1")
+	assertOneError(t, cfg.validate(v), "gdpr.default_value must be 0 or 1")
+}
+
+func TestMissingGDPRDefaultValue(t *testing.T) {
+	v := viper.New()
+
+	cfg, _ := newDefaultConfig(t)
+	assertOneError(t, cfg.validate(v), "gdpr.default_value is required and must be specified")
 }
 
 func TestNegativeCurrencyConverterFetchInterval(t *testing.T) {
+	v := viper.New()
+	v.Set("gdpr.default_value", "0")
+
 	cfg := Configuration{
 		CurrencyConverter: CurrencyConverter{
 			FetchIntervalSeconds: -1,
 		},
 	}
-	err := cfg.validate()
+	err := cfg.validate(v)
 	assert.NotNil(t, err, "cfg.currency_converter.fetch_interval_seconds should prevent negative values, but it doesn't")
 }
 
 func TestOverflowedCurrencyConverterFetchInterval(t *testing.T) {
+	v := viper.New()
+	v.Set("gdpr.default_value", "0")
+
 	cfg := Configuration{
 		CurrencyConverter: CurrencyConverter{
 			FetchIntervalSeconds: (0xffff) + 1,
 		},
 	}
-	err := cfg.validate()
+	err := cfg.validate(v)
 	assert.NotNil(t, err, "cfg.currency_converter.fetch_interval_seconds prevent values over %d, but it doesn't", 0xffff)
 }
 
@@ -733,6 +747,7 @@ func TestNewCallsRequestValidation(t *testing.T) {
 	for _, test := range testCases {
 		v := viper.New()
 		SetupViper(v, "")
+		v.Set("gdpr.default_value", "0")
 		v.SetConfigType("yaml")
 		v.ReadConfig(bytes.NewBuffer([]byte(
 			`request_validation:
@@ -750,31 +765,32 @@ func TestNewCallsRequestValidation(t *testing.T) {
 }
 
 func TestValidateDebug(t *testing.T) {
-	cfg := newDefaultConfig(t)
+	cfg, v := newDefaultConfig(t)
 	cfg.Debug.TimeoutNotification.SamplingRate = 1.1
 
-	err := cfg.validate()
+	err := cfg.validate(v)
 	assert.NotNil(t, err, "cfg.debug.timeout_notification.sampling_rate should not be allowed to be greater than 1.0, but it was allowed")
 }
 
 func TestValidateAccountsConfigRestrictions(t *testing.T) {
-	cfg := newDefaultConfig(t)
+	cfg, v := newDefaultConfig(t)
 	cfg.Accounts.Files.Enabled = true
 	cfg.Accounts.HTTP.Endpoint = "http://localhost"
 	cfg.Accounts.Postgres.ConnectionInfo.Database = "accounts"
 
-	errs := cfg.validate()
+	errs := cfg.validate(v)
 	assert.Len(t, errs, 1)
 	assert.Contains(t, errs, errors.New("accounts.postgres: retrieving accounts via postgres not available, use accounts.files"))
 }
 
-func newDefaultConfig(t *testing.T) *Configuration {
+func newDefaultConfig(t *testing.T) (*Configuration, *viper.Viper) {
 	v := viper.New()
 	SetupViper(v, "")
+	v.Set("gdpr.default_value", "0")
 	v.SetConfigType("yaml")
 	cfg, err := New(v)
-	assert.NoError(t, err)
-	return cfg
+	assert.NoError(t, err, "Setting up config should work but it doesn't")
+	return cfg, v
 }
 
 func assertOneError(t *testing.T, errs []error, message string) {
diff --git a/currency/aggregate_conversions_test.go b/currency/aggregate_conversions_test.go
index 35ca51a1..773a596c 100644
--- a/currency/aggregate_conversions_test.go
+++ b/currency/aggregate_conversions_test.go
@@ -65,7 +65,7 @@ func TestGroupedGetRate(t *testing.T) {
 			},
 		},
 		{
-			expectedError: ConversionRateNotFound{"GBP", "EUR"},
+			expectedError: ConversionNotFoundError{FromCur: "GBP", ToCur: "EUR"},
 			testCases: []aTest{
 				{"Valid three-digit currency codes, but conversion rate not found", "GBP", "EUR", 0},
 			},
diff --git a/endpoints/auction_test.go b/endpoints/auction_test.go
index 2062589e..bdf68db5 100644
--- a/endpoints/auction_test.go
+++ b/endpoints/auction_test.go
@@ -346,6 +346,7 @@ func TestCacheVideoOnly(t *testing.T) {
 	ctx := context.TODO()
 	v := viper.New()
 	config.SetupViper(v, "")
+	v.Set("gdpr.default_value", "0")
 	cfg, err := config.New(v)
 	if err != nil {
 		t.Fatal(err.Error())
diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go
index deff0662..213af9a0 100644
--- a/exchange/bidder_test.go
+++ b/exchange/bidder_test.go
@@ -564,7 +564,7 @@ func TestMultiCurrencies(t *testing.T) {
 				{currency: "USD", price: 1.3 * 1.3050530256},
 			},
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"JPY", "USD"},
+				currency.ConversionNotFoundError{FromCur: "JPY", ToCur: "USD"},
 			},
 			description: "Case 6 - Bidder respond with a mix of currencies and one unknown on all HTTP responses",
 		},
@@ -587,9 +587,9 @@ func TestMultiCurrencies(t *testing.T) {
 			},
 			expectedBids: []bid{},
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"JPY", "USD"},
-				currency.ConversionRateNotFound{"BZD", "USD"},
-				currency.ConversionRateNotFound{"DKK", "USD"},
+				currency.ConversionNotFoundError{FromCur: "JPY", ToCur: "USD"},
+				currency.ConversionNotFoundError{FromCur: "BZD", ToCur: "USD"},
+				currency.ConversionNotFoundError{FromCur: "DKK", ToCur: "USD"},
 			},
 			description: "Case 7 - Bidder respond with currencies not having any rate on all HTTP responses",
 		},
@@ -720,9 +720,9 @@ func TestMultiCurrencies_RateConverterNotSet(t *testing.T) {
 			bidCurrency:       []string{"EUR", "EUR", "EUR"},
 			expectedBidsCount: 0,
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"EUR", "USD"},
-				currency.ConversionRateNotFound{"EUR", "USD"},
-				currency.ConversionRateNotFound{"EUR", "USD"},
+				currency.ConversionNotFoundError{FromCur: "EUR", ToCur: "USD"},
+				currency.ConversionNotFoundError{FromCur: "EUR", ToCur: "USD"},
+				currency.ConversionNotFoundError{FromCur: "EUR", ToCur: "USD"},
 			},
 			description: "Case 2 - Bidder respond with the same currency (not default one) on all HTTP responses",
 		},
@@ -754,7 +754,7 @@ func TestMultiCurrencies_RateConverterNotSet(t *testing.T) {
 			bidCurrency:       []string{"EUR", "", "USD"},
 			expectedBidsCount: 2,
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"EUR", "USD"},
+				currency.ConversionNotFoundError{FromCur: "EUR", ToCur: "USD"},
 			},
 			description: "Case 7 - Bidder responds with a mix of not set, non default currency and default currency in HTTP responses",
 		},
@@ -762,7 +762,7 @@ func TestMultiCurrencies_RateConverterNotSet(t *testing.T) {
 			bidCurrency:       []string{"GBP", "", "USD"},
 			expectedBidsCount: 2,
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"GBP", "USD"},
+				currency.ConversionNotFoundError{FromCur: "GBP", ToCur: "USD"},
 			},
 			description: "Case 8 - Bidder responds with a mix of not set, non default currency and default currency in HTTP responses",
 		},
@@ -770,7 +770,7 @@ func TestMultiCurrencies_RateConverterNotSet(t *testing.T) {
 			bidCurrency:       []string{"GBP", "", ""},
 			expectedBidsCount: 2,
 			expectedBadCurrencyErrors: []error{
-				currency.ConversionRateNotFound{"GBP", "USD"},
+				currency.ConversionNotFoundError{FromCur: "GBP", ToCur: "USD"},
 			},
 			description: "Case 9 - Bidder responds with a mix of not set and empty currencies (default currency) in HTTP responses",
 		},
diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go
index 5a54b5e1..2a61a4e8 100644
--- a/exchange/exchange_test.go
+++ b/exchange/exchange_test.go
@@ -31,6 +31,7 @@ import (
 
 	"github.com/buger/jsonparser"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
 	"github.com/yudai/gojsondiff"
 	"github.com/yudai/gojsondiff/formatter"
 )
@@ -539,7 +540,7 @@ func TestTwoBiddersDebugDisabledAndEnabled(t *testing.T) {
 
 func TestOverrideWithCustomCurrency(t *testing.T) {
 
-	mockCurrencyClient := &mockCurrencyRatesClient{
+	mockCurrencyClient := &fakeCurrencyRatesHttpClient{
 		responseBody: `{"dataAsOf":"2018-09-12","conversions":{"USD":{"MXN":10.00}}}`,
 	}
 	mockCurrencyConverter := currency.NewRateConverter(
@@ -694,6 +695,72 @@ func TestOverrideWithCustomCurrency(t *testing.T) {
 	}
 }
 
+func TestAdapterCurrency(t *testing.T) {
+	fakeCurrencyClient := &fakeCurrencyRatesHttpClient{
+		responseBody: `{"dataAsOf":"2018-09-12","conversions":{"USD":{"MXN":10.00}}}`,
+	}
+	currencyConverter := currency.NewRateConverter(
+		fakeCurrencyClient,
+		"currency.fake.com",
+		24*time.Hour,
+	)
+	currencyConverter.Run()
+
+	// Initialize Mock Bidder
+	// - Response purposefully causes PBS-Core to stop processing the request, since this test is only
+	//   interested in the call to MakeRequests and nothing after.
+	mockBidder := &mockBidder{}
+	mockBidder.On("MakeRequests", mock.Anything, mock.Anything).Return([]*adapters.RequestData(nil), []error(nil))
+
+	// Initialize Real Exchange
+	e := exchange{
+		cache:             &wellBehavedCache{},
+		me:                &metricsConf.DummyMetricsEngine{},
+		gDPR:              gdpr.AlwaysAllow{},
+		currencyConverter: currencyConverter,
+		categoriesFetcher: nilCategoryFetcher{},
+		bidIDGenerator:    &mockBidIDGenerator{false, false},
+		adapterMap: map[openrtb_ext.BidderName]adaptedBidder{
+			openrtb_ext.BidderName("foo"): adaptBidder(mockBidder, nil, &config.Configuration{}, &metricsConfig.DummyMetricsEngine{}, openrtb_ext.BidderName("foo"), nil),
+		},
+	}
+
+	// Define Bid Request
+	request := &openrtb2.BidRequest{
+		ID: "some-request-id",
+		Imp: []openrtb2.Imp{{
+			ID:     "some-impression-id",
+			Banner: &openrtb2.Banner{Format: []openrtb2.Format{{W: 300, H: 250}, {W: 300, H: 600}}},
+			Ext:    json.RawMessage(`{"foo": {"placementId": 1}}`),
+		}},
+		Site: &openrtb2.Site{
+			Page: "prebid.org",
+			Ext:  json.RawMessage(`{"amp":0}`),
+		},
+		Cur: []string{"USD"},
+		Ext: json.RawMessage(`{"prebid": {"currency": {"rates": {"USD": {"MXN": 20.00}}}}}`),
+	}
+
+	// Run Auction
+	auctionRequest := AuctionRequest{
+		BidRequest: request,
+		Account:    config.Account{},
+		UserSyncs:  &emptyUsersync{},
+	}
+	response, err := e.HoldAuction(context.Background(), auctionRequest, &DebugLog{})
+	assert.NoError(t, err)
+	assert.Equal(t, "some-request-id", response.ID, "Response ID")
+	assert.Empty(t, response.SeatBid, "Response Bids")
+	assert.Contains(t, string(response.Ext), `"errors":{"foo":[{"code":5,"message":"The adapter failed to generate any bid requests, but also failed to generate an error explaining why"}]}`, "Response Ext")
+
+	// Test Currency Converter Properly Passed To Adapter
+	if assert.NotNil(t, mockBidder.lastExtraRequestInfo, "Currency Conversion Argument") {
+		converted, err := mockBidder.lastExtraRequestInfo.ConvertCurrency(2.0, "USD", "MXN")
+		assert.NoError(t, err, "Currency Conversion Error")
+		assert.Equal(t, 40.0, converted, "Currency Conversion Response")
+	}
+}
+
 func TestGetAuctionCurrencyRates(t *testing.T) {
 
 	pbsRates := map[string]map[string]float64{
@@ -859,7 +926,7 @@ func TestGetAuctionCurrencyRates(t *testing.T) {
 		}
 
 		// Init mock currency conversion service
-		mockCurrencyClient := &mockCurrencyRatesClient{
+		mockCurrencyClient := &fakeCurrencyRatesHttpClient{
 			responseBody: `{"dataAsOf":"2018-09-12","conversions":` + string(jsonPbsRates) + `}`,
 		}
 		mockCurrencyConverter := currency.NewRateConverter(
@@ -2162,6 +2229,11 @@ func newExchangeForTests(t *testing.T, filename string, expectations map[string]
 		t.Fatalf("Failed to create a category Fetcher: %v", error)
 	}
 
+	gdprDefaultValue := gdpr.SignalYes
+	if privacyConfig.GDPR.DefaultValue == "0" {
+		gdprDefaultValue = gdpr.SignalNo
+	}
+
 	return &exchange{
 		adapterMap:        bidderAdapters,
 		me:                metricsConf.NewMetricsEngine(&config.Configuration{}, openrtb_ext.CoreBidderNames()),
@@ -2169,7 +2241,7 @@ func newExchangeForTests(t *testing.T, filename string, expectations map[string]
 		cacheTime:         0,
 		gDPR:              &permissionsMock{allowAllBidders: true},
 		currencyConverter: currency.NewRateConverter(&http.Client{}, "", time.Duration(0)),
-		gdprDefaultValue:  privacyConfig.GDPR.DefaultValue,
+		gdprDefaultValue:  gdprDefaultValue,
 		privacyConfig:     privacyConfig,
 		categoriesFetcher: categoriesFetcher,
 		bidderInfo:        bidderInfos,
@@ -3649,15 +3721,32 @@ func (nilCategoryFetcher) FetchCategories(ctx context.Context, primaryAdServer,
 	return "", nil
 }
 
-// mockCurrencyRatesClient is a simple http client mock returning a constant response body
-type mockCurrencyRatesClient struct {
+// fakeCurrencyRatesHttpClient is a simple http client mock returning a constant response body
+type fakeCurrencyRatesHttpClient struct {
 	responseBody string
 }
 
-func (m *mockCurrencyRatesClient) Do(req *http.Request) (*http.Response, error) {
+func (m *fakeCurrencyRatesHttpClient) Do(req *http.Request) (*http.Response, error) {
 	return &http.Response{
 		Status:     "200 OK",
 		StatusCode: http.StatusOK,
 		Body:       ioutil.NopCloser(strings.NewReader(m.responseBody)),
 	}, nil
 }
+
+type mockBidder struct {
+	mock.Mock
+	lastExtraRequestInfo *adapters.ExtraRequestInfo
+}
+
+func (m *mockBidder) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) {
+	m.lastExtraRequestInfo = reqInfo
+
+	args := m.Called(request, reqInfo)
+	return args.Get(0).([]*adapters.RequestData), args.Get(1).([]error)
+}
+
+func (m *mockBidder) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) {
+	args := m.Called(internalRequest, externalRequest, response)
+	return args.Get(0).(*adapters.BidderResponse), args.Get(1).([]error)
+}
diff --git a/exchange/targeting_test.go b/exchange/targeting_test.go
index 86646957..f38a6c02 100644
--- a/exchange/targeting_test.go
+++ b/exchange/targeting_test.go
@@ -93,7 +93,7 @@ func runTargetingAuction(t *testing.T, mockBids map[openrtb_ext.BidderName][]*op
 		cacheTime:         time.Duration(0),
 		gDPR:              gdpr.AlwaysAllow{},
 		currencyConverter: currency.NewRateConverter(&http.Client{}, "", time.Duration(0)),
-		gdprDefaultValue:  "1",
+		gdprDefaultValue:  gdpr.SignalYes,
 		categoriesFetcher: categoriesFetcher,
 		bidIDGenerator:    &mockBidIDGenerator{false, false},
 	}
diff --git a/exchange/utils_test.go b/exchange/utils_test.go
index dad0d69d..5a281f9a 100644
--- a/exchange/utils_test.go
+++ b/exchange/utils_test.go
@@ -479,7 +479,7 @@ func TestCleanOpenRTBRequests(t *testing.T) {
 	for _, test := range testCases {
 		metricsMock := metrics.MetricsEngineMock{}
 		permissions := permissionsMock{allowAllBidders: true, passGeo: true, passID: true}
-		bidderRequests, _, err := cleanOpenRTBRequests(context.Background(), test.req, nil, &permissions, &metricsMock, "0", privacyConfig, nil)
+		bidderRequests, _, err := cleanOpenRTBRequests(context.Background(), test.req, nil, &permissions, &metricsMock, gdpr.SignalNo, privacyConfig, nil)
 		if test.hasError {
 			assert.NotNil(t, err, "Error shouldn't be nil")
 		} else {
@@ -636,7 +636,7 @@ func TestCleanOpenRTBRequestsCCPA(t *testing.T) {
 			nil,
 			&permissionsMock{allowAllBidders: true, passGeo: true, passID: true},
 			&metrics.MetricsEngineMock{},
-			"0",
+			gdpr.SignalNo,
 			privacyConfig,
 			nil)
 		result := bidderRequests[0]
@@ -698,7 +698,7 @@ func TestCleanOpenRTBRequestsCCPAErrors(t *testing.T) {
 		}
 		permissions := permissionsMock{allowAllBidders: true, passGeo: true, passID: true}
 		metrics := metrics.MetricsEngineMock{}
-		_, _, errs := cleanOpenRTBRequests(context.Background(), auctionReq, &reqExtStruct, &permissions, &metrics, "0", privacyConfig, nil)
+		_, _, errs := cleanOpenRTBRequests(context.Background(), auctionReq, &reqExtStruct, &permissions, &metrics, gdpr.SignalNo, privacyConfig, nil)
 
 		assert.ElementsMatch(t, []error{test.expectError}, errs, test.description)
 	}
@@ -740,7 +740,7 @@ func TestCleanOpenRTBRequestsCOPPA(t *testing.T) {
 
 		permissions := permissionsMock{allowAllBidders: true, passGeo: true, passID: true}
 		metrics := metrics.MetricsEngineMock{}
-		bidderRequests, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), auctionReq, nil, &permissions, &metrics, "0", config.Privacy{}, nil)
+		bidderRequests, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), auctionReq, nil, &permissions, &metrics, gdpr.SignalNo, config.Privacy{}, nil)
 		result := bidderRequests[0]
 
 		assert.Nil(t, errs)
@@ -849,7 +849,7 @@ func TestCleanOpenRTBRequestsSChain(t *testing.T) {
 
 		permissions := permissionsMock{allowAllBidders: true, passGeo: true, passID: true}
 		metrics := metrics.MetricsEngineMock{}
-		bidderRequests, _, errs := cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, &permissions, &metrics, "0", config.Privacy{}, nil)
+		bidderRequests, _, errs := cleanOpenRTBRequests(context.Background(), auctionReq, extRequest, &permissions, &metrics, gdpr.SignalNo, config.Privacy{}, nil)
 		if test.hasError == true {
 			assert.NotNil(t, errs)
 			assert.Len(t, bidderRequests, 0)
@@ -1432,7 +1432,7 @@ func TestCleanOpenRTBRequestsLMT(t *testing.T) {
 
 		permissions := permissionsMock{allowAllBidders: true, passGeo: true, passID: true}
 		metrics := metrics.MetricsEngineMock{}
-		results, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), auctionReq, nil, &permissions, &metrics, "0", privacyConfig, nil)
+		results, privacyLabels, errs := cleanOpenRTBRequests(context.Background(), auctionReq, nil, &permissions, &metrics, gdpr.SignalNo, privacyConfig, nil)
 		result := results[0]
 
 		assert.Nil(t, errs)
@@ -1639,13 +1639,18 @@ func TestCleanOpenRTBRequestsGDPR(t *testing.T) {
 			Account:    accountConfig,
 		}
 
+		gdprDefaultValue := gdpr.SignalYes
+		if test.gdprDefaultValue == "0" {
+			gdprDefaultValue = gdpr.SignalNo
+		}
+
 		results, privacyLabels, errs := cleanOpenRTBRequests(
 			context.Background(),
 			auctionReq,
 			nil,
 			&permissionsMock{allowAllBidders: true, passGeo: !test.gdprScrub, passID: !test.gdprScrub, activitiesError: test.permissionsError},
 			&metrics.MetricsEngineMock{},
-			test.gdprDefaultValue,
+			gdprDefaultValue,
 			privacyConfig,
 			nil)
 		result := results[0]
@@ -1736,7 +1741,7 @@ func TestCleanOpenRTBRequestsGDPRBlockBidRequest(t *testing.T) {
 			nil,
 			&permissionsMock{allowedBidders: test.gdprAllowedBidders, passGeo: true, passID: true, activitiesError: nil},
 			&metricsMock,
-			"0",
+			gdpr.SignalNo,
 			privacyConfig,
 			nil)
 
diff --git a/gdpr/impl_test.go b/gdpr/impl_test.go
index 345dd526..cde48546 100644
--- a/gdpr/impl_test.go
+++ b/gdpr/impl_test.go
@@ -21,7 +21,8 @@ func TestDisallowOnEmptyConsent(t *testing.T) {
 			HostVendorID: 3,
 			DefaultValue: "0",
 		},
-		vendorIDs: nil,
+		gdprDefaultValue: SignalNo,
+		vendorIDs:        nil,
 		fetchVendorList: map[uint8]func(ctx context.Context, id uint16) (vendorlist.VendorList, error){
 			tcf2SpecVersion: failedListFetcher,
 		},
@@ -303,6 +304,11 @@ func TestAllowActivities(t *testing.T) {
 
 	for _, tt := range tests {
 		perms.cfg.DefaultValue = tt.gdprDefaultValue
+		if tt.gdprDefaultValue == "0" {
+			perms.gdprDefaultValue = SignalNo
+		} else {
+			perms.gdprDefaultValue = SignalYes
+		}
 
 		_, _, passID, err := perms.AuctionActivitiesAllowed(context.Background(), tt.bidderName, tt.publisherID, tt.gdpr, tt.consent, tt.weakVendorEnforcement)
 
@@ -408,6 +414,15 @@ func TestAllowActivitiesGeoAndID(t *testing.T) {
 			passID:                true,
 			weakVendorEnforcement: true,
 		},
+		{
+			description:           "Unknown vendor test, insufficient purposes claimed, basic enforcement",
+			bidder:                openrtb_ext.BidderAudienceNetwork,
+			consent:               "COzTVhaOzTVhaGvAAAENAiCIAP_AAH_AAAAAAEEUACCKAAA",
+			allowBid:              true,
+			passGeo:               true,
+			passID:                true,
+			weakVendorEnforcement: true,
+		},
 		{
 			description: "Pubmatic vendor test, flex purposes claimed",
 			bidder:      openrtb_ext.BidderPubmatic,
@@ -719,6 +734,12 @@ func TestNormalizeGDPR(t *testing.T) {
 			},
 		}
 
+		if tt.gdprDefaultValue == "0" {
+			perms.gdprDefaultValue = SignalNo
+		} else {
+			perms.gdprDefaultValue = SignalYes
+		}
+
 		normalizedSignal := perms.normalizeGDPR(tt.giveSignal)
 
 		assert.Equal(t, tt.wantSignal, normalizedSignal, tt.description)
diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go
index 2ebd541d..81216b19 100644
--- a/usersync/usersyncers/syncer_test.go
+++ b/usersync/usersyncers/syncer_test.go
@@ -37,6 +37,7 @@ func TestNewSyncerMap(t *testing.T) {
 			string(openrtb_ext.BidderBeachfront):       syncConfig,
 			string(openrtb_ext.BidderBeintoo):          syncConfig,
 			string(openrtb_ext.BidderBetween):          syncConfig,
+			string(openrtb_ext.BidderBidmyadz):         syncConfig,
 			string(openrtb_ext.BidderBmtm):             syncConfig,
 			string(openrtb_ext.BidderBrightroll):       syncConfig,
 			string(openrtb_ext.BidderColossus):         syncConfig,
@@ -64,6 +65,7 @@ func TestNewSyncerMap(t *testing.T) {
 			string(openrtb_ext.BidderLockerDome):       syncConfig,
 			string(openrtb_ext.BidderLogicad):          syncConfig,
 			string(openrtb_ext.BidderLunaMedia):        syncConfig,
+			string(openrtb_ext.BidderSaLunaMedia):      syncConfig,
 			string(openrtb_ext.BidderMarsmedia):        syncConfig,
 			string(openrtb_ext.BidderMediafuse):        syncConfig,
 			string(openrtb_ext.BidderMgid):             syncConfig,
@@ -82,6 +84,7 @@ func TestNewSyncerMap(t *testing.T) {
 			string(openrtb_ext.BidderSmartAdserver):    syncConfig,
 			string(openrtb_ext.BidderSmartRTB):         syncConfig,
 			string(openrtb_ext.BidderSmartyAds):        syncConfig,
+			string(openrtb_ext.BidderSmileWanted):      syncConfig,
 			string(openrtb_ext.BidderSomoaudience):     syncConfig,
 			string(openrtb_ext.BidderSonobi):           syncConfig,
 			string(openrtb_ext.BidderSovrn):            syncConfig,