Skip to content

Commit

Permalink
refactor(client): remove sdk proxy
Browse files Browse the repository at this point in the history
  • Loading branch information
Kalovelo committed Aug 1, 2022
1 parent 49e5f4b commit 2f441ab
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 70 deletions.
12 changes: 6 additions & 6 deletions client/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import RockPaperScissors from './components/RockPaperScissors.vue';
import PopUp from './components/PopUp.vue';
import { useChannelStore } from './stores/channel';
import { useGameStore } from './stores/game';
import { onBeforeUnmount, onMounted, toRaw } from 'vue';
import { getSdk, returnCoinsToFaucet } from './sdk/sdkService';
import { onBeforeUnmount, onMounted } from 'vue';
import { initSdk, returnCoinsToFaucet, sdk } from './sdk/sdkService';
import { GameChannel } from './sdk/GameChannel';
import GameManager from './game/GameManager';
import { AeSdk } from '@aeternity/aepp-sdk';
const channelStore = useChannelStore();
const gameStore = useGameStore();
Expand All @@ -23,13 +22,14 @@ async function initChannel() {
}
onMounted(async () => {
channelStore.channel = new GameChannel(await getSdk());
await initSdk();
channelStore.channel = new GameChannel();
gameStore.gameManager = new GameManager();
});
onBeforeUnmount(async () => {
if (channelStore.channel?.sdk) {
await returnCoinsToFaucet(toRaw(channelStore.channel.sdk) as AeSdk);
if (sdk) {
await returnCoinsToFaucet();
}
});
</script>
Expand Down
37 changes: 11 additions & 26 deletions client/src/sdk/GameChannel.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import {
AeSdk,
Channel,
encodeContractAddress,
unpackTx,
} from '@aeternity/aepp-sdk';
import { Channel, encodeContractAddress, unpackTx } from '@aeternity/aepp-sdk';
import contractSource from '@aeternity/rock-paper-scissors';
import { ChannelOptions } from '@aeternity/aepp-sdk/es/channel/internal';
import { Encoded } from '@aeternity/aepp-sdk/es/utils/encoder';
import { BigNumber } from 'bignumber.js';
import { toRaw } from 'vue';
import {
getSdk,
initSdk,
returnCoinsToFaucet,
sdk,
verifyContractBytecode,
} from './sdkService';
import { ContractInstance } from '@aeternity/aepp-sdk/es/contract/aci';
import { PopUpData, usePopUpStore } from '../stores/popup';

export class GameChannel {
sdk: AeSdk;
channelConfig?: ChannelOptions;
channelInstance?: Channel;
isOpen = false;
Expand All @@ -43,29 +38,22 @@ export class GameChannel {
contractAddress?: Encoded.ContractAddress;
autoSign = false;

constructor(sdk: AeSdk) {
this.sdk = sdk;
}

getChannelWithoutProxy() {
if (!this.channelInstance) {
throw new Error('Channel is not initialized');
}
return toRaw(this.channelInstance);
}
getSdkWithoutProxy() {
return toRaw(this.sdk);
}

async fetchChannelConfig(): Promise<ChannelOptions> {
if (!this.sdk) throw new Error('SDK is not set');
if (!sdk) throw new Error('SDK is not set');
const res = await fetch(import.meta.env.VITE_BOT_SERVICE_URL + '/open', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
address: this.sdk.selectedAddress,
address: sdk.selectedAddress,
port: import.meta.env.VITE_RESPONDER_PORT ?? '3333',
host: import.meta.env.VITE_RESPONDER_HOST ?? 'localhost',
}),
Expand All @@ -77,7 +65,7 @@ export class GameChannel {
if (res.status != 200) {
if (data.error.includes('greylisted')) {
console.log('Greylisted account, retrying with new account');
this.sdk = await getSdk();
initSdk();
return this.fetchChannelConfig();
} else
this.error = {
Expand Down Expand Up @@ -138,10 +126,7 @@ export class GameChannel {
// if we are signing a transaction that updates the contract
if (update?.op === 'OffChainNewContract') {
const proposedBytecode = update.code;
const isContractValid = await verifyContractBytecode(
this.getSdkWithoutProxy(),
proposedBytecode
);
const isContractValid = await verifyContractBytecode(proposedBytecode);
popupData.title = 'Contract validation';
popupData.text = `Contract bytecode is
${isContractValid ? 'matching' : 'not matching'}`;
Expand All @@ -153,7 +138,7 @@ export class GameChannel {
}
if (this.autoSign) {
return new Promise((resolve) => {
resolve(this.getSdkWithoutProxy().signTransaction(tx, {}));
resolve(sdk.signTransaction(tx, {}));
// call the callback if it exists
popupData?.mainBtnAction?.();
});
Expand All @@ -167,7 +152,7 @@ export class GameChannel {
secBtnText: popupData?.secBtnText ?? 'Cancel',
mainBtnAction: () => {
popupStore.resetPopUp();
resolve(this.getSdkWithoutProxy().signTransaction(tx, {}));
resolve(sdk.signTransaction(tx, {}));
// call the callback if it exists
popupData?.mainBtnAction?.();
},
Expand All @@ -186,7 +171,7 @@ export class GameChannel {
if (this.channelInstance) {
this.getChannelWithoutProxy().on('statusChanged', (status) => {
if (status === 'disconnected') {
returnCoinsToFaucet(this.getSdkWithoutProxy());
returnCoinsToFaucet();
}
if (status === 'open') {
this.isOpen = true;
Expand All @@ -201,7 +186,7 @@ export class GameChannel {
const contractCreationRound = unpackTx(tx).tx.round;
this.contractAddress = encodeContractAddress(owner, contractCreationRound);

this.contract = await this.getSdkWithoutProxy().getContractInstance({
this.contract = await sdk.getContractInstance({
source: contractSource,
});
}
Expand Down
25 changes: 15 additions & 10 deletions client/src/sdk/sdkService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,30 @@ export const IS_USING_LOCAL_NODE = !import.meta.env.VITE_NODE_URL.includes(
const FAUCET_PUBLIC_ADDRESS = import.meta.env
.VITE_FAUCET_PUBLIC_ADDRESS as Encoded.AccountAddress;

export async function getSdk() {
export let sdk: AeSdk;

export async function getNewSdk() {
const account = new MemoryAccount({ keypair: generateKeyPair() });
const node = new Node(NODE_URL);
const aeSdk = new AeSdk({
const newSdk = new AeSdk({
nodes: [{ name: 'testnet', instance: node }],
compilerUrl: COMPILER_URL,
});
await aeSdk.addAccount(account, { select: true });
return aeSdk;
await newSdk.addAccount(account, { select: true });
return newSdk;
}

export async function initSdk() {
sdk = await getNewSdk();
}

export async function returnCoinsToFaucet(aeSdk: AeSdk) {
const userBalance = await aeSdk.getBalance(
aeSdk.selectedAddress as Encoded.AccountAddress
export async function returnCoinsToFaucet() {
const userBalance = await sdk.getBalance(
sdk.selectedAddress as Encoded.AccountAddress
);
if (BigInt(userBalance) <= 0) return;
try {
await aeSdk.transferFunds(1, FAUCET_PUBLIC_ADDRESS);
await sdk.transferFunds(1, FAUCET_PUBLIC_ADDRESS);
} catch (e) {
console.error({ e }, 'failed to return funds to faucet');
}
Expand All @@ -51,13 +57,12 @@ export const FAUCET_ACCOUNT = IS_USING_LOCAL_NODE
: null;

export async function verifyContractBytecode(
aeSdk: AeSdk,
bytecode: Encoded.ContractBytearray,
source = contractSource
) {
let isEqual = false;
try {
await aeSdk.compilerApi.validateByteCode({
await sdk.compilerApi.validateByteCode({
bytecode,
source,
options: {},
Expand Down
27 changes: 16 additions & 11 deletions client/tests/game-manager.test.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import { describe, it, expect } from 'vitest';
import { describe, it, expect, beforeEach, beforeAll } from 'vitest';
import { createTestingPinia } from '@pinia/testing';
import GameManager, { Selections } from '../src/game/GameManager';
import { GameChannel } from '../src/sdk/GameChannel';
import { getSdk } from '../src/sdk/sdkService';
import { initSdk } from '../src/sdk/sdkService';
import { waitForChannelReady } from './utils';

describe('GameManager', async () => {
let gameManager: GameManager;
const gameChannel = new GameChannel(await getSdk());
gameChannel.autoSign = true;
await gameChannel.initializeChannel();
createTestingPinia({
initialState: {
channel: {
channel: gameChannel,
let gameChannel: GameChannel;

beforeAll(async () => {
await initSdk();
gameChannel = new GameChannel();
gameChannel.autoSign = true;
await gameChannel.initializeChannel();
createTestingPinia({
initialState: {
channel: {
channel: gameChannel,
},
},
},
});
await waitForChannelReady(gameChannel.getChannelWithoutProxy());
});
await waitForChannelReady(gameChannel.getChannelWithoutProxy());

it('creates game manager instance', async () => {
gameManager = new GameManager();
Expand Down
32 changes: 15 additions & 17 deletions client/tests/sdk.test.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
import { Encoded } from '@aeternity/aepp-sdk/es/utils/encoder';
import { describe, it, expect, vi } from 'vitest';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import {
getSdk,
getNewSdk,
FAUCET_ACCOUNT,
verifyContractBytecode,
initSdk,
sdk,
} from '../src/sdk/sdkService';
import { createTestingPinia } from '@pinia/testing';
import { GameChannel } from '../src/sdk/GameChannel';
import { AeSdk } from '@aeternity/aepp-sdk';
import contractSource from '@aeternity/rock-paper-scissors';
import { waitForChannelReady } from './utils';
import SHA from 'sha.js';

describe('SDK', () => {
beforeEach(async () => await initSdk());

it('creates and returns an SDK instance', async () => {
const sdk = await getSdk();
expect(sdk).toBeTruthy();
expect(Object.keys(sdk.accounts).length).toBe(1);
expect(sdk.selectedAddress).toBeTruthy();
});

it('cannot call contract when channel is not initialized', async () => {
const gameChannel = new GameChannel(await getSdk());
const gameChannel = new GameChannel();
gameChannel.autoSign = true;
await new Promise((resolve) => setTimeout(resolve, 3000));
await gameChannel.initializeChannel();
Expand All @@ -35,7 +37,7 @@ describe('SDK', () => {
await expect(gameChannel.callContract('init', [])).rejects.toThrow();
});
it('cannot call contract when contract is not deployed', async () => {
const gameChannel = new GameChannel(await getSdk());
const gameChannel = new GameChannel();
gameChannel.autoSign = true;
await gameChannel.initializeChannel();
createTestingPinia({
Expand All @@ -51,7 +53,7 @@ describe('SDK', () => {
});

it('can call contract after it is deployed', async () => {
const gameChannel = new GameChannel(await getSdk());
const gameChannel = new GameChannel();
gameChannel.autoSign = true;
await gameChannel.initializeChannel();
createTestingPinia({
Expand All @@ -75,7 +77,7 @@ describe('SDK', () => {
}, 8000);

it('creates game channel instance, initializes Channel and returns coins to faucet on channel closing', async () => {
const gameChannel = new GameChannel(await getSdk());
const gameChannel = new GameChannel();
gameChannel.autoSign = true;
await gameChannel.initializeChannel();
createTestingPinia({
Expand All @@ -86,8 +88,8 @@ describe('SDK', () => {
},
});
await waitForChannelReady(gameChannel.getChannelWithoutProxy());
const client = gameChannel.sdk as AeSdk;
const ae = await getSdk();
const client = sdk;
const ae = await getNewSdk();

expect(client?.selectedAddress).toBeTruthy();
expect(gameChannel.getStatus()).toBe('open');
Expand Down Expand Up @@ -131,28 +133,26 @@ describe('SDK', () => {
false => ()
`;
it('returns true if proposed bytecode is correct', async () => {
const sdk = await getSdk();
const contract = await sdk.getContractInstance({
source: contractSource,
});
await contract.compile();
if (!contract.bytecode)
throw new Error('Contract bytecode is not defined');
await expect(
verifyContractBytecode(sdk, contract.bytecode, contractSource)
verifyContractBytecode(contract.bytecode, contractSource)
).resolves.toBeTruthy();
});

it('returns false if proposed bytecode is wrong', async () => {
const sdk = await getSdk();
const contract = await sdk.getContractInstance({
source: contractSource,
});
await contract.compile();
if (!contract.bytecode)
throw new Error('Contract bytecode is not defined');
expect(
verifyContractBytecode(sdk, contract.bytecode, wrongSource)
verifyContractBytecode(contract.bytecode, wrongSource)
).resolves.toBeFalsy();
});
});
Expand All @@ -177,9 +177,7 @@ describe('GameChannel', () => {
url: '',
} as unknown as Response);

const sdk = await getSdk();

const gameChannel = new GameChannel(sdk);
const gameChannel = new GameChannel();
await gameChannel.fetchChannelConfig();
expect(fetchSpy).toHaveBeenCalledTimes(2);
}, 10000);
Expand Down

0 comments on commit 2f441ab

Please sign in to comment.