Skip to content

Commit

Permalink
Add guarded tx in a batch (#180)
Browse files Browse the repository at this point in the history
* add guarded tx in a batch

* add guarded property in submitGateway function

* update @etherspot/contracts
  • Loading branch information
0xSulpiride authored Oct 25, 2022
1 parent 639ee40 commit c126a63
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 22 deletions.
18 changes: 9 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "etherspot",
"version": "1.38.1",
"version": "1.38.2",
"description": "Etherspot SDK",
"keywords": [
"ether",
Expand Down Expand Up @@ -41,7 +41,7 @@
},
"dependencies": {
"@apollo/client": "3.4.0",
"@etherspot/contracts": "1.9.0",
"@etherspot/contracts": "1.9.3",
"@lifi/sdk": "1.6.0",
"@nerdwallet/apollo-cache-policies": "1.2.1",
"class-transformer": "0.4.0",
Expand Down
2 changes: 2 additions & 0 deletions src/sdk/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import {
ENSReverseRegistrarContract,
ERC20TokenContract,
GatewayContract,
GatewayV2Contract,
PaymentRegistryContract,
PersonalAccountRegistryContract,
} from './contract';
Expand All @@ -40,6 +41,7 @@ export class Context {
gatewayContract: GatewayContract;
paymentRegistryContract: PaymentRegistryContract;
personalAccountRegistryContract: PersonalAccountRegistryContract;
gatewayV2Contract: GatewayV2Contract,
},
readonly services: {
accountService: AccountService;
Expand Down
8 changes: 8 additions & 0 deletions src/sdk/contract/internal/__mocks__/gatewayV2.contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ContractNames } from '@etherspot/contracts';
import { mockContract } from '../../../../testing';

export const GatewayV2Contract = mockContract(ContractNames.GatewayV2, {
encodeSendBatchFromAccount: jest.fn(),
encodeDelegateBatch: jest.fn(),
buildDelegatedBatchTypedData: jest.fn(),
});
43 changes: 43 additions & 0 deletions src/sdk/contract/internal/gatewayV2.contract.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { ContractNames } from '@etherspot/contracts';
import { TransactionRequest } from '../../common';
import { InternalContract } from './internal.contract';

export class GatewayV2Contract extends InternalContract {
constructor() {
super(ContractNames.GatewayV2);
}

encodeSendBatchFromAccount?(account: string, to: string[], data: string[]): TransactionRequest;

encodeDelegateBatch?(
account: string,
nonce: number,
to: string[],
data: string[],
senderSignature: string,
): TransactionRequest;

encodeSendBatchFromAccountGuarded?(
account: string,
to: string[],
data: string[],
): TransactionRequest;

hashDelegatedBatch(account: string, nonce: number, to: string[], data: string[]): Buffer {
return this.hashMessagePayload(
'DelegatedBatch',
[
{ name: 'account', type: 'address' }, //
{ name: 'nonce', type: 'uint256' },
{ name: 'to', type: 'address[]' },
{ name: 'data', type: 'bytes[]' },
],
{
account, //
nonce,
to,
data,
},
);
}
}
1 change: 1 addition & 0 deletions src/sdk/contract/internal/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './gateway.contract';
export * from './internal.contract';
export * from './payment-registry.contract';
export * from './personal-account-registry.contract';
export * from './gatewayV2.contract';
13 changes: 13 additions & 0 deletions src/sdk/contract/internal/personal-account-registry.contract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,19 @@ export class PersonalAccountRegistryContract extends InternalContract {
data: BytesLike,
): TransactionRequest;

encodeIsAccountDeployed(
account: string
): TransactionRequest {
const data = this.interface.encodeFunctionData(
'isAccountDeployed',
[account]
);
return {
to: this.address,
data
}
};

computeAccountAddress(saltOwner: string): string {
let result: string = null;

Expand Down
3 changes: 3 additions & 0 deletions src/sdk/dto/custom-project-metadata.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ export class CustomProjectMetadataDto {
@IsOptional()
@MaxLength(128)
customProjectMetadata?: string = null;

@IsOptional()
guarded?: boolean = false;
}
36 changes: 26 additions & 10 deletions src/sdk/gateway/gateway.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ export class GatewayService extends Service {
throw new Exception('Can not submit empty batch');
}

const { estimation } = statelessBatch || this.gatewayBatch;
const { estimation } = statelessBatch?.estimation ? statelessBatch : this.gatewayBatch;

if (!estimation || estimation.expiredAt.getTime() < estimation.createdAt.getTime()) {
throw new Exception('Can not submit not estimated batch');
Expand All @@ -501,7 +501,12 @@ export class GatewayService extends Service {
const { nonce, feeToken } = this.estimationOptions;

const { accountService, walletService, apiService } = this.services;
const { gatewayContract, personalAccountRegistryContract, erc20TokenContract } = this.internalContracts;
const {
gatewayContract,
personalAccountRegistryContract,
erc20TokenContract,
gatewayV2Contract,
} = this.internalContracts;

const account = accountService.accountAddress;

Expand All @@ -520,12 +525,20 @@ export class GatewayService extends Service {
feeTransactionRequest = personalAccountRegistryContract.encodeRefundAccountCall(account, null, feeAmount);
}

const messageHash = gatewayContract.hashDelegatedBatch(
account,
nonce,
[...to, feeTransactionRequest.to],
[...data, feeTransactionRequest.data],
);
let guardedTx: TransactionRequest = null;
if (statelessBatch.guarded) {
const guardedTxContent = personalAccountRegistryContract.encodeIsAccountDeployed(gatewayContract.address);
guardedTx = gatewayV2Contract.encodeSendBatchFromAccountGuarded(
gatewayContract.address,
[guardedTxContent.to],
[guardedTxContent.data],
);
}

const destinations = [guardedTx && guardedTx.to, ...to, feeTransactionRequest.to].filter((addr) => !!addr);
const datas = [guardedTx && guardedTx.data, ...data, feeTransactionRequest.data].filter((data) => !!data);
const messageHash = gatewayContract.hashDelegatedBatch(account, nonce, destinations, datas);

const senderSignature = await walletService.signMessage(messageHash);

const { result } = await apiService.mutate<{
Expand All @@ -545,6 +558,7 @@ export class GatewayService extends Service {
$estimatedGasPrice: BigNumber!
$estimationExpiredAt: DateTime!
$estimationSignature: String!
$guarded: Boolean,
) {
result: submitGatewayBatch(
chainId: $chainId
Expand All @@ -559,6 +573,7 @@ export class GatewayService extends Service {
estimatedGasPrice: $estimatedGasPrice
estimationExpiredAt: $estimationExpiredAt
estimationSignature: $estimationSignature
guarded: $guarded
) {
transaction {
hash
Expand Down Expand Up @@ -604,11 +619,12 @@ export class GatewayService extends Service {
estimatedGasPrice,
estimationExpiredAt,
estimationSignature,
guarded: statelessBatch.guarded,
},
},
);

if (!statelessBatch) {
if (!statelessBatch || (!statelessBatch.requests && !statelessBatch.estimation)) {
this.clearGatewayBatch();
}

Expand Down Expand Up @@ -732,7 +748,7 @@ export class GatewayService extends Service {
}

private extractToAndData(statelessBatch?: GatewayBatch): { to: string[]; data: string[] } {
return (statelessBatch || this.gatewayBatch).requests.reduce(
return (statelessBatch?.requests ? statelessBatch : this.gatewayBatch).requests.reduce(
(result, { to, data }) => {
result.to.push(to);
result.data.push(data);
Expand Down
1 change: 1 addition & 0 deletions src/sdk/gateway/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ export interface GatewayBatch {
data: string;
}[];
estimation: GatewayEstimatedBatch;
guarded?: boolean;
}
8 changes: 7 additions & 1 deletion src/sdk/sdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
ENSReverseRegistrarContract,
ERC20TokenContract,
GatewayContract,
GatewayV2Contract,
PaymentRegistryContract,
PersonalAccountRegistryContract,
} from './contract';
Expand Down Expand Up @@ -213,6 +214,7 @@ export class Sdk {
gatewayContract: new GatewayContract(),
paymentRegistryContract: new PaymentRegistryContract(),
personalAccountRegistryContract: new PersonalAccountRegistryContract(),
gatewayV2Contract: new GatewayV2Contract(),
};

this.services = {
Expand Down Expand Up @@ -507,7 +509,11 @@ export class Sdk {

return projectService.withCustomProjectMetadata(
customProjectMetadata, //
() => gatewayService.submitGatewayBatch(),
() => gatewayService.submitGatewayBatch({
requests: null,
estimation: null,
guarded: dto.guarded
}),
);
}

Expand Down

0 comments on commit c126a63

Please sign in to comment.