"Challenge: bulletproof payment form", Lev Davydov

fwdays 292 views 38 slides Oct 19, 2024
Slide 1
Slide 1 of 38
Slide 1
1
Slide 2
2
Slide 3
3
Slide 4
4
Slide 5
5
Slide 6
6
Slide 7
7
Slide 8
8
Slide 9
9
Slide 10
10
Slide 11
11
Slide 12
12
Slide 13
13
Slide 14
14
Slide 15
15
Slide 16
16
Slide 17
17
Slide 18
18
Slide 19
19
Slide 20
20
Slide 21
21
Slide 22
22
Slide 23
23
Slide 24
24
Slide 25
25
Slide 26
26
Slide 27
27
Slide 28
28
Slide 29
29
Slide 30
30
Slide 31
31
Slide 32
32
Slide 33
33
Slide 34
34
Slide 35
35
Slide 36
36
Slide 37
37
Slide 38
38

About This Presentation

Millions of daily users, hundreds of clients, one embeddable widget. How did we build it and what could possibly have gone wrong?


Slide Content

和 vv

BULLETPROOF
PATENT FORM

Solidgate

lo | noBEphycb |
CET

KOLO

t= | Aouo
superhumans Center |

About me El solidgate

Frontend Guildmaster
at Solidgate

8 years in IT

Wanna you to learn
from our mistakes

Agenda El solidgate

1. Company intro.

2. Payment form iterations
3. Public API

4. Race conditions

5. Q&A

About us El solidgate

2.8 billions USD
processed annually

2x YTY growth 125 businesses
using Payment form

Tech numbers El solidgate

6k+ RPS on balancer Payment Form

A

+ Add query © Queryhistory © Query inspector

Graph

Initial requirements EJ solidgate

Payment form 1 EY 시 8
Embeddable into other apps |! で |

We are controlling updates @

Restrict client data access O@

=> iframe

Initial solution

Your iframe
Card Number
1234 1234 1234 1234

Expiration Date

MMIYY

Subscribe for 120,00 EUR/30 day:

Ask iframe url

Returns url

Pass sensitive
info

回 solidgate

Your backend

Initial problems EJ solidgate

its looks so
you do something’

Merchant website

| Draws

1 Uh, sorry, could you set a 300px
Your iframe fixed heigh, we are updating our
documentation ATM?

Card Number

回 solidgate
3D-Secure ve En

CKACYBA TA

AlnpusarBanx VISA

Mepuawr: LQ
wa

Bara:
Kaprea:

Niareepaite onnary a honangy Npusar24,
ori Harwcuire xHonky pogosxcinn

Workarounds EJ solidgate

Uh, sorry, could you set a 300px
Your iframe fixed heigh, we are updating our
documentation ATM?

Card Number

Expiration Date

and there is a 3D redirect from
BigPopularBank with scrollbar

Sorry again, it should be 400px.

Your QA

store.soldgate.com 1 charge your You
nature payments in accesar

Workaround trap Elsolidgate

// publish, inside iframe
window. parent. postMessage({
type: "resize",
height: 400,
por);

// subscribe, outside iframe
window. addEventListener("message", e => {
if (e.type == "resize") て
iframe.height = e.height;

Ej
3)

More requirements

Extra fields

Apple pay

3D-Secure in modal

回 solidgate

4242 4242 4242 4242 vsa

«Pay

Your customer will proceed to the Apple
Pay to complete payment

Silver Bullet Elsolidgate

Requests SDK

Returns SDK

ñ

1 Your SDK | ER — |
Your iframe

Cord Number

Handles 별
non-sensetive info 1!

回 solidgate

Why silver bullet? |

Better payment conversion |
Better clients conversion |
Better ideas conversion |

HOUSTON,
WE HAVE
A PROBLEM

window.on(load', () => {
window.parent.postMessage(‘its ok’, '*)

»

Credit or Debit Card Number

Expiry Date CVVCVC

Email C

r
You are engineer, [Username] ㅣ

Doom picture EJ solidgate

opyao

回 solidgate

form.on("event", cb) is ugly past t> |

form.addEventListener("event", cb) is bright future &

You

Not migrating, past is OK,

gimme features 名

Merchant

Liskov
Substitution
Principle

If it looks like a duck,

quacks like a duck, but needs
batteries — you probably have
the wrong abstraction

Not perfect flow

interface Data {
containterld: string;
// rest props


| Your SDK | a

Your iframe

Call backend
for iframeUrl

Find containerld
and paste iframe

回 solidgate

interface Data {
containterld: string;
// rest props

Your SDK Draws

Your iframe

Call backend for
payment data

| 一

Continue

回 solidgate

Find containerld
and paste
static iframe

el

+

Notify error

Breaking changes? El solidgate

Before After

enum OrderStatus {
Initial = “initial”, // default
|] new status
Processing = “processing”,
Success = “success”,
Fail = “fail”

}

enum OrderStatus {
Initial = “initial”, // default
Success = "success",
Fail = “fail”

}

Somehow breaking El solidgate

/ no
function sendToApi(status: OrderStatus) {}

| / yes
ei. WOK! NANYTA HABUMBCA function readFromApi(status: OrderStatus) {
TOBOPHTH "3ANEHMTb BI] KOHTEKCTVS switch (status)

case OrderStatus. Initial {
doStuff();

に ヨ

ar
N oth di
TBHALITYBABCA IT-APXITEHTOPOM default {

/ 4 hideAllUlAndSayNO00000/): // breaking
}

}

Exceptions Elsolidgate

interface Error {
kind: "order_declined"
reason: "invalid_api_key"

csnwCorrelationId:

env: “sandbox

So weird environment El solidgate

Promise.finallyButNotAllways() Object.valuesButNotAll()

Race conditions

EJ solidgate

_jn React function Like({ initialLiked }) {

const [liked, setLiked] = useState(initialLiked);

function handleClick() {
const newLiked = !liked;

// optimistic update
setLiked (newLiked) ;

// api call
fetch("/api/like", {
method: "POST",
body: JSON.stringify({ liked: newLiked }),
»
3

return (
<button onClick={handleClick}>
fliked ? "@" : won]
</button>

)3

Explanation 回 solidgate

Click % -> expectY —— Request 2 一 >
Backend

Click Y -> expect '— Request 2 —>

What to do? import { Mutex } from 'asyno-mutex'
Mutexes class Liker {

private mutex = new Mutex()
async like(liked: boolean) {
// awaits release (if already in use)

const release = await mutex.acquire();

try {

await fetch("/api/like", {
method: "POST",
body: JSON.stringify({ liked: newLiked }),

»

了 finally {
// do release
release();

n Payment form

interface Data {
containterld: string;
// rest props

Your SDK

Your iframe

Elsolidgate

Sdk.init(data)



Call backend for Find containerld and
payment data paste static iframe

Y

Ensure iframe loaded

y

Pass init data and payment data to iframe

回 solidgate

Modal window

n Payment form

Your iframe

Card Number

1234 1234 1234 1234

Expiration Date

MMIYY

‚00 EUR/30 days

What to do? Explicit ownership

Please, do work, ID

回 solidgate

!
| Your SDK Your iframe

Are you alive?

Yes

Are you alive?

Yes

Here goes result from ID

N
1

1
1
À
1
|
1
1
1

Card Number

1234 1234 1234 1234

Expiration Date

MM/YY

Subscribe for 120,00 EUR/30 days

回 solidgate

Iframes are good,
but not enough

How to synchronise
SDK © iframe versions?

Client-side SDK

Testing best practices
are Public API

Race conditions
are everywhere

Percentages/canary rollouts
(we can do it with Cloudfront)

QA