Skip to content

Commit

Permalink
Add externally connected wallets into Paima (#250)
Browse files Browse the repository at this point in the history
* Fix: Nami signMessage support

* checkpoint

* Broken: refactoring utility function location

* Fix compiler errors

* Remove posting mode as main switch for middleware behavior

* Fix batcher script

* Fix emulated block wait return type

* Fix new provider setup errors after debugging

* Add missing TruffleConnector

* Improve sendTransaction typing

* Fix wallet status check

* Fix deduplicatation causing wallets to be missed in named connections

* eslint fixes

* Add way to specify mode to use when posting a transaction
  • Loading branch information
SebastienGllmt authored Oct 31, 2023
1 parent 76269c8 commit 13e2cf7
Show file tree
Hide file tree
Showing 33 changed files with 729 additions and 3,818 deletions.
3,345 changes: 48 additions & 3,297 deletions package-lock.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
if [[ ! -f "./paima-batcher-linux" ]]; then
echo "Error: paima-batcher-linux binary not found. Docker requires the linux binary for the application."
exit 1
else
fi

if [ ! -x ./paima-batcher-linux ]; then chmod +x ./paima-batcher-linux; fi

Expand Down
2 changes: 1 addition & 1 deletion packages/batcher/batcher-transaction-poster/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class BatchedTransactionPoster {
const tx = {
data: this.storage.methods.paimaSubmitGameInput(hexMsg).encodeABI(),
to: this.contractAddress,
from: this.truffleProvider.getAddress(),
from: this.truffleProvider.getAddress().address,
value: this.truffleProvider.web3.utils.numberToHex(this.fee),
gas: estimateGasLimit(msg.length),
};
Expand Down
4 changes: 2 additions & 2 deletions packages/batcher/webserver/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ async function initializeServer(

const input: BatchedSubunit = {
addressType,
userAddress: truffleProvider.getAddress(),
userAddress: truffleProvider.getAddress().address,
gameInput,
millisecondTimestamp,
userSignature,
Expand Down Expand Up @@ -271,7 +271,7 @@ async function initializeServer(
await insertValidatedInput.run(
{
address_type: addressType,
user_address: truffleProvider.getAddress(),
user_address: truffleProvider.getAddress().address,
game_input: gameInput,
millisecond_timestamp: millisecondTimestamp,
user_signature: userSignature,
Expand Down
4 changes: 2 additions & 2 deletions packages/engine/paima-runtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ const paimaEngine: PaimaRuntimeInitializer = {
.then(([latestBlock]) => {
if (latestBlock == null) {
res.status(200).json({
success: false,
success: true,
result: blockNotYet,
});
return false;
Expand All @@ -107,7 +107,7 @@ const paimaEngine: PaimaRuntimeInitializer = {
// ex: waiting to see if there are other blocks that need to be bundled as part of the same emulated block
if (latestBlock.deployment_chain_block_height < deploymentBlockheight) {
res.status(200).json({
success: false,
success: true,
result: blockNotYet,
});
return false;
Expand Down
33 changes: 16 additions & 17 deletions packages/paima-sdk/paima-mw-core/src/endpoints/accounts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,10 @@ import {
localRemoteVersionsCompatible,
} from '../helpers/auxiliary-queries';
import { checkCardanoWalletStatus } from '../wallets/cardano';
import { checkEthWalletStatus } from '../wallets/evm';
import { checkEthWalletStatus } from '../wallets/evm/injected';
import { specificWalletLogin } from '../wallets/wallets';
import {
getEmulatedBlocksActive,
getPostingMode,
PostingMode,
setEmulatedBlocksActive,
setEmulatedBlocksInactive,
} from '../state';
Expand All @@ -20,30 +18,31 @@ import type { LoginInfo } from '../wallets/wallet-modes';
* Wrapper function for all wallet status checking functions
*/
async function checkWalletStatus(): Promise<OldResult> {
switch (getPostingMode()) {
case PostingMode.UNBATCHED:
case PostingMode.BATCHED_ETH:
return await checkEthWalletStatus();
case PostingMode.BATCHED_CARDANO:
return await checkCardanoWalletStatus();
// TODO: what about the other currency types?
default:
return {
success: true,
message: '',
};
// TODO: what about the other currency types?
const results = await Promise.all([checkEthWalletStatus(), checkCardanoWalletStatus()]);
for (const result of results) {
if (result.success === false) {
return result;
}
}
return {
success: true,
message: '',
};
}

/**
* Core "login" function which tells the frontend whether the user has a wallet in a valid state
* thus allowing the game to get past the login screen.
* @param preferBatchedMode - If true (or truthy value) even EVM wallet inputs will be batched.
*/
async function userWalletLogin(loginInfo: LoginInfo): Promise<Result<Wallet>> {
async function userWalletLogin(
loginInfo: LoginInfo,
setDefault: boolean = true
): Promise<Result<Wallet>> {
const errorFxn = buildEndpointErrorFxn('userWalletLogin');

const response = await specificWalletLogin(loginInfo);
const response = await specificWalletLogin(loginInfo, setDefault);
if (!response.success) {
return response;
}
Expand Down
72 changes: 7 additions & 65 deletions packages/paima-sdk/paima-mw-core/src/endpoints/internal.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,23 @@
import type { URI } from '@paima/utils';
import { buildEndpointErrorFxn, PaimaMiddlewareErrorCode } from '../errors';
import {
getActiveAddress,
getChainUri,
getPostingInfo,
setAutomaticMode,
setBackendUri,
setBatchedCardanoMode,
setBatchedEthMode,
setBatchedPolkadotMode,
setEmulatedBlocksActive,
setEmulatedBlocksInactive,
setUnbatchedMode,
} from '../state';
import type { PostingInfo, PostingModeSwitchResult, Result, Wallet } from '../types';
import type { Result, Wallet } from '../types';
import { specificWalletLogin } from '../wallets/wallets';
import { emulatedBlocksActiveOnBackend } from '../helpers/auxiliary-queries';
import { TruffleConnector } from '@paima/providers';
import HDWalletProvider from '@truffle/hdwallet-provider';
import type { LoginInfo } from '../wallets/wallet-modes';

export async function userWalletLoginWithoutChecks(loginInfo: LoginInfo): Promise<Result<Wallet>> {
return await specificWalletLogin(loginInfo);
export async function userWalletLoginWithoutChecks(
loginInfo: LoginInfo,
setDefault: boolean = true
): Promise<Result<Wallet>> {
return await specificWalletLogin(loginInfo, setDefault);
}

export async function automaticWalletLogin(privateKey: string): Promise<Result<Wallet>> {
Expand All @@ -47,68 +43,14 @@ export async function automaticWalletLogin(privateKey: string): Promise<Result<W
return {
success: true,
result: {
walletAddress: provider.getAddress(),
walletAddress: provider.getAddress().address,
},
};
} catch (err) {
return errorFxn(PaimaMiddlewareErrorCode.TRUFFLE_LOGIN, err);
}
}

export async function switchToUnbatchedMode(): Promise<PostingModeSwitchResult> {
setUnbatchedMode();
return {
success: true,
...getPostingInfo(),
};
}

export async function switchToBatchedEthMode(): Promise<PostingModeSwitchResult> {
setBatchedEthMode();
return {
success: true,
...getPostingInfo(),
};
}

export async function switchToBatchedCardanoMode(): Promise<PostingModeSwitchResult> {
setBatchedCardanoMode();
return {
success: true,
...getPostingInfo(),
};
}

export async function switchToBatchedPolkadotMode(): Promise<PostingModeSwitchResult> {
setBatchedPolkadotMode();
return {
success: true,
...getPostingInfo(),
};
}

export async function switchToAutomaticMode(): Promise<PostingModeSwitchResult> {
setAutomaticMode();
return {
success: true,
...getPostingInfo(),
};
}

export async function retrieveActiveAddress(): Promise<Result<string>> {
return {
success: true,
result: getActiveAddress(),
};
}

export async function retrievePostingInfo(): Promise<Result<PostingInfo>> {
return {
success: true,
result: getPostingInfo(),
};
}

export async function updateBackendUri(newUri: URI): Promise<void> {
setBackendUri(newUri);
}
37 changes: 6 additions & 31 deletions packages/paima-sdk/paima-mw-core/src/helpers/data-processing.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import { AddressType, getWriteNamespace } from '@paima/utils';
import { getWriteNamespace } from '@paima/utils';

import type { SignFunction } from '../types';
import {
AlgorandConnector,
CardanoConnector,
EvmConnector,
PolkadotConnector,
} from '@paima/providers';
import { createMessageForBatcher, type BatchedSubunit } from '@paima/concise';
import assertNever from 'assert-never';
import type { AddressAndType } from '@paima/providers';

export function batchedToJsonString(b: BatchedSubunit): string {
return JSON.stringify({
Expand All @@ -20,30 +14,11 @@ export function batchedToJsonString(b: BatchedSubunit): string {
});
}

function selectSignFunction(addressType: AddressType): SignFunction {
switch (addressType) {
case AddressType.EVM:
return EvmConnector.instance().getOrThrowProvider().signMessage;
case AddressType.CARDANO:
return CardanoConnector.instance().getOrThrowProvider().signMessage;
case AddressType.POLKADOT:
return PolkadotConnector.instance().getOrThrowProvider().signMessage;
case AddressType.ALGORAND:
return AlgorandConnector.instance().getOrThrowProvider().signMessage;
case AddressType.UNKNOWN:
throw new Error(`[selectSignFunction] unknown address type`);
default:
assertNever(addressType, true);
throw new Error(`[selectSignFunction] invalid address type: ${addressType}`);
}
}

export async function buildBatchedSubunit(
addressType: AddressType,
userAddress: string,
signFunction: SignFunction,
userAddress: AddressAndType,
gameInput: string
): Promise<BatchedSubunit> {
const signFunction = selectSignFunction(addressType);
const millisecondTimestamp: string = new Date().getTime().toString(10);
const message: string = createMessageForBatcher(
await getWriteNamespace(),
Expand All @@ -52,8 +27,8 @@ export async function buildBatchedSubunit(
);
const userSignature = await signFunction(message);
return {
addressType,
userAddress,
addressType: userAddress.type,
userAddress: userAddress.address,
userSignature,
gameInput,
millisecondTimestamp,
Expand Down
Loading

0 comments on commit 13e2cf7

Please sign in to comment.