Skip to content

Commit

Permalink
feature(types,links): deeplinks (#3147)
Browse files Browse the repository at this point in the history
  • Loading branch information
stackchain authored Mar 19, 2024
1 parent 542b9f7 commit f2b4742
Show file tree
Hide file tree
Showing 21 changed files with 554 additions and 70 deletions.
8 changes: 8 additions & 0 deletions apps/wallet-mobile/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="yoroi"/>
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="https"/>
<data android:scheme="yoroi-wallet.com"/>
</intent-filter>

</activity>
</application>
</manifest>
10 changes: 10 additions & 0 deletions apps/wallet-mobile/ios/nightly.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:yoroi-wallet.com</string>
</array>
</dict>
</plist>
8 changes: 8 additions & 0 deletions apps/wallet-mobile/ios/yoroi.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@
9A17D1FE4D734EC2A996EA26 /* Rubik-Medium.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Rubik-Medium.ttf"; path = "../src/assets/fonts/Rubik-Medium.ttf"; sourceTree = "<group>"; };
A230DBE7EEBA4B38AD9006D2 /* Rubik-Italic-VariableFont_wght.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Rubik-Italic-VariableFont_wght.ttf"; path = "../src/assets/fonts/Rubik-Italic-VariableFont_wght.ttf"; sourceTree = "<group>"; };
B4FF531EA86A409487D4A26C /* Rubik-BlackItalic.ttf */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = unknown; name = "Rubik-BlackItalic.ttf"; path = "../src/assets/fonts/Rubik-BlackItalic.ttf"; sourceTree = "<group>"; };
BD1BE1882BAA0839004E2DD9 /* yoroi.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = yoroi.entitlements; path = yoroi/yoroi.entitlements; sourceTree = "<group>"; };
BD1BE1892BAA0888004E2DD9 /* nightly.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = nightly.entitlements; sourceTree = "<group>"; };
BD60BE852A34B13000EFF020 /* nightly.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = nightly.app; sourceTree = BUILT_PRODUCTS_DIR; };
BD825DEA29FB507600E19149 /* BootSplash.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = BootSplash.storyboard; path = yoroi/BootSplash.storyboard; sourceTree = "<group>"; };
BDD74A382A34B82A003591A8 /* nightly.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = nightly.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -161,6 +163,7 @@
13B07FAE1A68108700A75B9A /* yoroi */ = {
isa = PBXGroup;
children = (
BD1BE1882BAA0839004E2DD9 /* yoroi.entitlements */,
BDD74A382A34B82A003591A8 /* nightly.plist */,
13B07FAF1A68108700A75B9A /* AppDelegate.h */,
13B07FB01A68108700A75B9A /* AppDelegate.mm */,
Expand Down Expand Up @@ -193,6 +196,7 @@
83CBB9F61A601CBA00E9B192 = {
isa = PBXGroup;
children = (
BD1BE1892BAA0888004E2DD9 /* nightly.entitlements */,
13B07FAE1A68108700A75B9A /* yoroi */,
832341AE1AAA6A7D00B99B32 /* Libraries */,
00E356EF1AD99517003FC87E /* yoroiTests */,
Expand Down Expand Up @@ -828,6 +832,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = yoroi/yoroi.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 513;
Expand Down Expand Up @@ -872,6 +877,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = yoroi/yoroi.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 513;
Expand Down Expand Up @@ -1066,6 +1072,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 513;
Expand Down Expand Up @@ -1110,6 +1117,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly";
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = nightly.entitlements;
CODE_SIGN_IDENTITY = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CURRENT_PROJECT_VERSION = 513;
Expand Down
7 changes: 7 additions & 0 deletions apps/wallet-mobile/ios/yoroi/AppDelegate.mm
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,11 @@ - (BOOL)application:(UIApplication *)application
return [RCTLinkingManager application:application openURL:url options:options];
}

- (BOOL)application:(UIApplication *)application continueUserActivity:(nonnull NSUserActivity *)userActivity
restorationHandler:(nonnull void (^)(NSArray<id<UIUserActivityRestoring>> * _Nullable))restorationHandler
{
return [RCTLinkingManager application:application
continueUserActivity:userActivity
restorationHandler:restorationHandler];
}
@end
10 changes: 10 additions & 0 deletions apps/wallet-mobile/ios/yoroi/yoroi.entitlements
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.associated-domains</key>
<array>
<string>applinks:yoroi-wallet.com</string>
</array>
</dict>
</plist>
43 changes: 43 additions & 0 deletions packages/links/.well-known/apple-app-site-association
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
{
"applinks": {
"apps": [],
"details": [
{
"appIDs": [
"F8NVT2G2L4.com.emurgo.yoroi",
"F8NVT2G2L4.com.yoroi.app",
"F8NVT2G2L4.io.emurgo.yoroi",
"F8NVT2G2L4.com.emurgo.yoroi-stag",
"F8NVT2G2L4.com.emurgo.yoroi-nightly"
],
"components": [
{
"/": "/w1/*",
"?": {
"$onlyBrowser": "true"
},
"exclude": true
},
{
"/": "/w1/*",
"?": {
"%24onlyBrowser": "true"
},
"exclude": true
},
{
"/": "/w1/*"
},
{
"/": "*",
"exclude": true
},
{
"/": "/",
"exclude": true
}
]
}
]
}
}
26 changes: 26 additions & 0 deletions packages/links/.well-known/assetlinks.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "com.emurgo",
"sha256_cert_fingerprints": [
"77:0C:19:DD:CF:1C:98:BF:07:49:47:44:1B:10:61:6E:E6:A3:36:42:35:CC:B1:D5:F4:15:35:2E:DD:14:68:5D"
]
}
},
{
"relation": [
"delegate_permission/common.handle_all_urls"
],
"target": {
"namespace": "android_app",
"package_name": "com.emurgo.nightly",
"sha256_cert_fingerprints": [
"C0:E4:33:9B:B3:2F:C5:29:04:A0:BE:C8:AD:0F:3A:0C:36:DC:20:9A:F4:60:C0:42:96:DA:7E:3C:1F:ED:B4:77"
]
}
}
]
72 changes: 58 additions & 14 deletions packages/links/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# @yoroi/links

## Overview
This TypeScript package provides type-safe way to create and parse cryptocurrency-related links based on its URI definition (ABNF). It is designed to support different types of operations. It supports Cardano operations such as claims and legacy transfers within its blockchain ecosystem. It allows apps to interpret and build crypto links.
This package provides type-safe way to create and parse cryptocurrency-related links based on its URI definition (ABNF). It is designed to support different types of operations. It supports Cardano operations such as claims and legacy transfers within its blockchain ecosystem. It also allows to interpret and build crypto links.

## Features
- **Custom URI Scheme Handling**: Supports the 'web+cardano' URI scheme, tailored for Cardano blockchain interactions.
- **Type-Safe Link Creation and Parsing**: Utilizes TypeScript for ensuring the integrity and correctness of link structures.
- **Configurable for Different Operations/Chains**: Includes configurations for claim operations (`configCardanoClaimV1`) and legacy transfers (`configCardanoLegacyTransfer`).
- **Configurable for Different Operations/Chains**: Includes configurations for claim operations (`configCardanoClaimV1`) and legacy transfers (`configCardanoLegacyTransfer`), it can be extended.
- **Yoroi Deep Links**: Supports the 'yoroi' URI scheme, tailored for interation with Yoroi.

## Installation
How to install the package, e.g., via npm or yarn:
Expand All @@ -16,10 +17,10 @@ npm install @yoroi/links
yarn add @yoroi/links
```

## Usage
## Cardano Usage
### Importing the Module
```typescript
import { linksCardanoModuleMaker } from '@yoroi/links';
import { linksCardanoModuleMaker, configCardanoClaimV1 } from '@yoroi/links';
```

### How to create a link
Expand All @@ -46,26 +47,69 @@ const parsedLink = parse('web+cardano://claim/v1?code=123&faucet_url=http://exam
console.log(parsedLink);
```

## API reference
### API reference

### Interface
#### Interface
- `create`: Creates a crypto link based on the provided configuration and parameters.
- `parse`: Parses a given string into a Link object if supported, otherwise will throw.

### Built-in configurations
#### Built-in configurations
- `configCardanoClaimV1`: Configuration for Cardano `claim` operations. [CIP99](https://github.com/cardano-foundation/CIPs/pull/546/files)
- `configCardanoLegacyTransfer`: Configuration for Cardano `legacy` transfers. [CIP13](https://cips.cardano.org/cips/cip13/)

#### Supported Schemes and Authorities

| Scheme | Authority | Description |
|----------------|-----------|---------------------------------------------|
| `web+cardano` | `claim` | Used for proof of onboarding / airdrops |
| `web+cardano` | ` ` | Used for legacy payment requests |


## Yoroi Usage
### Importing the Module
```typescript
import { linksYoroiModuleMaker, linksCardanoModuleMaker, configCardanoLegacyTransfer } from '@yoroi/links';
```

### How to create a link
```typescript
const { create } = linksCardanoModuleMaker();
const { transfer } = linksYoroiModuleMaker('yoroi');

const cardanoLink = create({
config: configCardanoLegacyTransfer,
params: {
amount: 1,
address: "$stackchain"
}
});

const yoroiPaymentRequestWithAdaLink = transfer.request.adaWithLink(cardanoLink.link)

console.log(yoroiPaymentRequestWithAdaLink);
```

### Supported Schemes and Authorities

| Scheme | Authority | Description |
|-----------------|------------|---------------------------------------------|
| `yoroi` `https` | `transfer` | Used for requesting payments |
| `yoroi` `https` | `exchange` | Used for iteracting with exchanges |
| `yoroi` `https` | `dapp` | **soon** |


## Testing the deep & universal links developing
```shell
# iOS
xcrun simctl openurl booted "https://yoroi-wallet.com/w1/transfer/request/ada?amount=1&address=$stackchain"

# Android
adb shell am start -W -a android.intent.action.VIEW -d "yoroi://yoroi-wallet.com/w1/transfer/request/ada?amount=1&address=$stackchain"
```

## For more
- [BIP-21](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki)
- [EIP-681](https://eips.ethereum.org/EIPS/eip-681)
- [URI](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwiGtpWV-eOCAxVSmokEHdBOAn0QFnoECBQQAQ&url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FUniform_Resource_Identifier&usg=AOvVaw2i8uSyn7gtMV9bW4Nmh4dK&opi=89978449)
- [ABNF](https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjYq-3u-OOCAxVxvokEHTx1CqsQFnoECBIQAQ&url=https%3A%2F%2Fen.wikipedia.org%2Fwiki%2FAugmented_Backus%25E2%2580%2593Naur_form&usg=AOvVaw3GEFuH6Hby-NUw6cxQpQUz&opi=89978449)
- [RFC-2234](https://datatracker.ietf.org/doc/html/rfc2234)

## Supported Schemes and Authorities

| Scheme | Authority | Description |
|----------------|-----------|---------------------------------------------|
| `web+cardano` | `claim` | Used for proof of onboarding / airdrops |
| `web+cardano` | ` ` | Used for legacy payment requests |
8 changes: 6 additions & 2 deletions packages/links/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@
"eslint-plugin-ft-flow": "^3.0.0",
"eslint-plugin-prettier": "^4.0.0",
"flowgen": "^1.21.0",
"immer": "^10.0.2",
"jest": "^29.7.0",
"pod-install": "^0.1.0",
"prettier": "^2.0.5",
Expand All @@ -167,12 +168,15 @@
"react-query": "^3.39.3",
"react-test-renderer": "^18.2.0",
"release-it": "^15.0.0",
"typescript": "^5.3.3"
"typescript": "^5.3.3",
"zod": "^3.22.2"
},
"peerDependencies": {
"@react-native-async-storage/async-storage": ">= 1.19.3 <= 1.20.0",
"immer": "^10.0.2",
"react": ">= 16.8.0 <= 19.0.0",
"react-query": "^3.39.3"
"react-query": "^3.39.3",
"zod": "^3.22.2"
},
"optionalDependencies": {
"@react-native-async-storage/async-storage": "^1.19.3"
Expand Down
36 changes: 36 additions & 0 deletions packages/links/src/cardano/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import {Links} from '@yoroi/types'
import {freeze} from 'immer'

import {LinksCardanoClaimV1, LinksCardanoLegacyTransfer} from './types'

export const cardanoScheme: Links.WebCardanoUriConfig['scheme'] = 'web+cardano'
export const configCardanoClaimV1: Readonly<LinksCardanoClaimV1> = freeze(
{
scheme: cardanoScheme,
authority: 'claim',
version: 'v1',
rules: {
requiredParams: ['code', 'faucet_url'],
optionalParams: [],
forbiddenParams: ['address'],
extraParams: 'include',
},
},
true,
)

export const configCardanoLegacyTransfer: Readonly<LinksCardanoLegacyTransfer> =
freeze(
{
scheme: cardanoScheme,
authority: '',
version: '',
rules: {
requiredParams: ['address'],
optionalParams: ['amount', 'memo', 'message'],
forbiddenParams: [],
extraParams: 'drop',
},
},
true,
)
7 changes: 2 additions & 5 deletions packages/links/src/cardano/module.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import {Links} from '@yoroi/types'
import {
configCardanoClaimV1,
configCardanoLegacyTransfer,
linksCardanoModuleMaker,
} from './module'
import {linksCardanoModuleMaker} from './module'
import {configCardanoClaimV1, configCardanoLegacyTransfer} from './constants'

describe('linksCardanoModuleMaker', () => {
it('should return a Links.Module', () => {
Expand Down
Loading

0 comments on commit f2b4742

Please sign in to comment.