-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
222 additions
and
0 deletions.
There are no files selected for viewing
16 changes: 16 additions & 0 deletions
16
docs/home/700-multichain-support/3-delegate-wallet/1-introduction.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
# Introduction | ||
|
||
Delegate Wallet allows for a wallet address to be delegated to another wallet address. | ||
|
||
In practice, a user can use wallet address `A` to play, but their real wallet address is `B` | ||
|
||
Some use cases: | ||
* **Better UX**: By using a "Local Wallet" within the browser and sending transactions through the "Batcher", so each transaction gets signed automatically. | ||
* **Security**: Allowing players to have a "Burner Wallet" with limited funds to only play. | ||
* **Security**: Reduce interaction with real wallet. | ||
* **Account Recovery**: account can be re-delegated to a new wallet address. | ||
* **Identity Privacy**: real wallet address is not exposed. | ||
|
||
|
||
This feature is optional, but you can implement at any time. | ||
As good practice use `user_id` in the STF to identify the user, and not the wallet address. |
116 changes: 116 additions & 0 deletions
116
docs/home/700-multichain-support/3-delegate-wallet/2-getting-started.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
# Getting Started | ||
|
||
We are going to implement a workflow to delegate a Local Wallet to an EVM Wallet. | ||
|
||
|
||
## In your middleware | ||
|
||
1. First implement a [Local Wallet](../wallet-layer/introduction#thirdweb-support) | ||
|
||
2. Create a function to sign messages with your local wallet. `WalletConnectHelper` and `getActiveAddress` is provided by @paima/sdk. `LocalWallet` is provided by `thirdweb`. | ||
```js | ||
const signMessageWithLocalWallet = async (message: string) => { | ||
const toSign = new WalletConnectHelper().buildMessageToSign(message); | ||
|
||
return { | ||
message: toSign, | ||
walletAddress: getActiveAddress(WalletMode.EvmEthers).toLocaleLowerCase(), | ||
/* localWallet is an instance of LocalWallet from the previous step */ | ||
signedMessage: await localWallet.signMessage(message), | ||
}; | ||
}; | ||
``` | ||
|
||
3. Now create a function to get User Wallets. `allInjectedWallets` is provided by `@paima/sdk`. | ||
```js | ||
const getWallets = async () => { | ||
/* "wallets" is a map of connected wallets */ | ||
const wallets = await allInjectedWallets({ | ||
gameName: 'GameName', | ||
gameChainId: undefined, | ||
}); | ||
return wallets; | ||
} | ||
``` | ||
|
||
4. Create a final function to sign messages with an external wallet. `WalletConnectHelper` is provided by `@paima/sdk`. | ||
```js | ||
const connectAndSignExternalWallet = async ( | ||
walletType: AddressType, | ||
walletName: string, /* Provided in wallets[WalletMode].metadata.name */ | ||
otherAddress: string | ||
) => { | ||
return await new WalletConnectHelper().connectExternalWalletAndSign(walletType, walletName, message); | ||
}; | ||
``` | ||
|
||
5. Put it all together. `walletConnectPromise` is provided by `@paima/sdk`. | ||
```js | ||
const localWalletMessage = await signMessageWithLocalWallet(); | ||
const wallets = getWallets(); | ||
|
||
// This is to use only the first EVM wallet. | ||
// You should check the contents of "wallets" and display the necessary options. | ||
const injectedWalletMessage = await connectAndSignExternalWallet( | ||
AddressType.EVM, | ||
wallets[WalletMode.EvmInjected].metadata.name, | ||
localWalletSignedMessage.walletAddress | ||
); | ||
|
||
// Send message to blockchain. | ||
await walletConnectPromise( | ||
injectedWalletMessage.walletAddress, | ||
null, // localWalletMessage.walletAddress, | ||
injectedWalletMessage.signedMessage, | ||
localWalletMessage.signedMessage | ||
); | ||
``` | ||
|
||
|
||
## In your backend | ||
|
||
|
||
1. In the default API index: `/backend/api/index.ts` | ||
Add the following code: | ||
```js | ||
// Clear wallet-connection cache. | ||
clearDelegateWalletCacheOnChanges(requirePersistentConnection()); | ||
``` | ||
This allows to clear the API cache when the user changes the wallet connection. | ||
|
||
2. STF Changes | ||
As user wallet might change over time, as they can delegate, migrate and cancel delegations, we need to use `userId` instead of `userAddress` or `realAddress` for user identification in our STF. | ||
```js | ||
export default async function ( | ||
inputData: SubmittedChainData, | ||
blockHeight: number, | ||
randomnessGenerator: Prando, | ||
dbConn: Pool | ||
): Promise<SQLUpdate[]> { | ||
const user = String(inputData.userId); | ||
/* use user to identify user instead of userAddress or realAddress */ | ||
... | ||
} | ||
``` | ||
* userAddress: contains the main wallet address. | ||
* realAddress: contains the real wallet address that sent the transaction. | ||
* userId: contains the user id, which is the same for all wallets of the same user. | ||
|
||
|
||
3. API Controllers | ||
In your API, if receiving user wallet address, convert them into the USER ID. | ||
```js | ||
@Route('items') | ||
export class ItemController extends Controller { | ||
@Get('/user') | ||
public async getItemsForUser( | ||
@Query() wallet: string | ||
): Promise<{ items: IGetAllItemsForUserResult[] }> { | ||
const pool = requirePool(); | ||
const address = await getMainAddress(wallet, pool); | ||
/* now use address, instead of wallet */ | ||
const items = await getAllItemsForUser.run({ wallet: address }, pool); | ||
return { items }; | ||
} | ||
} | ||
``` |
87 changes: 87 additions & 0 deletions
87
docs/home/700-multichain-support/3-delegate-wallet/3-how-it-works.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
# How it works | ||
|
||
|
||
## Wallet Delegate API | ||
|
||
The user must send a transaction to delegate their wallet address to another wallet address, through a concise command. | ||
IMPORTANT: This functionally is automatically provided by the SDK helpers. | ||
``` | ||
delegate = &wd|from?|to?|from_signature|to_signature | ||
migrate = &wm|from?|to?|from_signature|to_signature | ||
cancelDelegations = &wc|to_signature | ||
``` | ||
They must sign the transaction with the following message: | ||
``` | ||
DELEGATE-WALLET:<other-address-lowercase>:<env-contract-address>` | ||
``` | ||
* from: the main address that will be | ||
* to | ||
* other-address-lowercase: is "to" or "from" for "from" and "to" respectively address in lowercase. | ||
* env-contract-address: is defined in .env CONTRACT_ADDRESS | ||
|
||
## STF | ||
|
||
STF data is slightly changed: | ||
* userAddress: contains the main wallet address. | ||
* realAddress: contains the real wallet address that sent the transaction. | ||
* userId: contains the user id, which is the same for all wallets of the same user. | ||
|
||
userAddress and realAddress will be the same for the main wallet or if there are no delegations. | ||
|
||
## Wallet Delegate Tables | ||
|
||
There will to managed tables | ||
* addresses: maps a unique user id to each wallet address. | ||
* delegations: maps delegated wallet addresses. | ||
|
||
## API | ||
|
||
1. This function delegates Wallet "to" to "from". | ||
null "from" or "to" gets replace by wallet that sends (or signs if using the batcher) the transaction. | ||
```js | ||
function walletConnect( | ||
from: string | null, | ||
to: string | null, | ||
from_signature: string, | ||
to_signature: string | ||
): Promise<SuccessfulResult<PostDataResponse> | FailedResult> | ||
``` | ||
|
||
2. This function removes any current delegation to the sender address. | ||
The message has the format: | ||
```js | ||
DELEGATE-WALLET::<env-contract-address>`; | ||
``` | ||
|
||
```js | ||
function walletConnectCancelDelegations( | ||
to_signature: string | ||
): Promise<SuccessfulResult<PostDataResponse> | FailedResult> { | ||
``` | ||
3. This function migrates the address "from" to "to". | ||
null "from" or "to" gets replace by wallet that sends (or signs if using the batcher) the transaction. | ||
```js | ||
function walletConnectMigrate( | ||
from: string | null, | ||
to: string | null, | ||
from_signature: string, | ||
to_signature: string | ||
): Promise<SuccessfulResult<PostDataResponse> | FailedResult> | ||
``` | ||
|
||
4. This class contains helper functions to sign with injected or generate the message for local wallets. | ||
```js | ||
class WalletConnectHelper { | ||
buildMessageToSign(subMessage: string): string; | ||
connectExternalWalletAndSign( | ||
walletType: AddressType, | ||
walletName: string, | ||
subMessage: string | ||
): Promise<{ | ||
message: string; | ||
signedMessage: string; | ||
walletAddress: string; | ||
}> | ||
} | ||
``` |
3 changes: 3 additions & 0 deletions
3
docs/home/700-multichain-support/3-delegate-wallet/_category_.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"label": "Delegate Wallet" | ||
} |