-
Notifications
You must be signed in to change notification settings - Fork 11.2k
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
8 changed files
with
289 additions
and
1 deletion.
There are no files selected for viewing
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
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
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
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
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
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,9 @@ | ||
[package] | ||
name = "tto" | ||
version = "0.0.1" | ||
|
||
[dependencies] | ||
Sui = { local = "../../../../../../crates/sui-framework/packages/sui-framework" } | ||
|
||
[addresses] | ||
tto = "0x0" |
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,46 @@ | ||
module tto::tto { | ||
use sui::object::{Self, UID}; | ||
use sui::tx_context::{Self, TxContext}; | ||
use sui::transfer::{Self, Receiving}; | ||
|
||
struct A has key, store { | ||
id: UID, | ||
} | ||
|
||
struct B has key, store { | ||
id: UID, | ||
} | ||
|
||
public fun start(ctx: &mut TxContext) { | ||
let a = A { id: object::new(ctx) }; | ||
let a_address = object::id_address(&a); | ||
let b = B { id: object::new(ctx) }; | ||
let c = B { id: object::new(ctx) }; | ||
transfer::share_object(c); | ||
transfer::public_transfer(a, tx_context::sender(ctx)); | ||
transfer::public_transfer(b, a_address); | ||
} | ||
|
||
public entry fun receiver(parent: &mut A, x: Receiving<B>) { | ||
let b = transfer::receive(&mut parent.id, x); | ||
transfer::public_transfer(b, @tto); | ||
} | ||
|
||
public entry fun deleter(parent: &mut A, x: Receiving<B>) { | ||
let B { id } = transfer::receive(&mut parent.id, x); | ||
object::delete(id); | ||
} | ||
|
||
public fun return_(parent: &mut A, x: Receiving<B>): B { | ||
transfer::receive(&mut parent.id, x) | ||
} | ||
|
||
public entry fun delete_(b: B) { | ||
let B { id } = b; | ||
object::delete(id); | ||
} | ||
|
||
public fun invalid_call_immut_ref(_parent: &mut A, _x: &Receiving<B>) { } | ||
public fun invalid_call_mut_ref(_parent: &mut A, _x: &mut Receiving<B>) { } | ||
public fun dropper(_parent: &mut A, _x: Receiving<B>) { } | ||
} |
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,146 @@ | ||
// Copyright (c) Mysten Labs, Inc. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
import { describe, it, expect, beforeAll, beforeEach } from 'vitest'; | ||
|
||
import { setup, TestToolbox, publishPackage } from './utils/setup'; | ||
import { OwnedObjectRef, SuiClient } from '../../src/client'; | ||
import { TransactionBlock } from '../../src/builder'; | ||
import type { Keypair } from '../../src/cryptography'; | ||
|
||
function getOwnerAddress(o: OwnedObjectRef): string | undefined { | ||
// const owner = getObjectOwner(o); | ||
if (typeof o.owner == 'object' && 'AddressOwner' in o.owner) { | ||
return o.owner.AddressOwner; | ||
} else { | ||
return undefined; | ||
} | ||
} | ||
|
||
describe('Transfer to Object', () => { | ||
let toolbox: TestToolbox; | ||
let packageId: string; | ||
let parentObjectId: OwnedObjectRef; | ||
let receiveObjectId: OwnedObjectRef; | ||
let sharedObjectId: string; | ||
|
||
beforeAll(async () => { | ||
const packagePath = __dirname + '/./data/tto'; | ||
({ packageId } = await publishPackage(packagePath)); | ||
}); | ||
|
||
beforeEach(async () => { | ||
toolbox = await setup(); | ||
const tx = new TransactionBlock(); | ||
tx.moveCall({ | ||
target: `${packageId}::tto::start`, | ||
typeArguments: [], | ||
arguments: [], | ||
}); | ||
const x = await validateTransaction(toolbox.client, toolbox.keypair, tx); | ||
const y = (x.effects?.created)!.map((o) => getOwnerAddress(o))!; | ||
receiveObjectId = (x.effects?.created)!.filter( | ||
(o) => !y.includes(o.reference.objectId) && getOwnerAddress(o) !== undefined, | ||
)[0]; | ||
parentObjectId = (x.effects?.created)!.filter( | ||
(o) => y.includes(o.reference.objectId) && getOwnerAddress(o) !== undefined, | ||
)[0]; | ||
const sharedObject = (x.effects?.created)!.filter((o) => getOwnerAddress(o) === undefined)[0]; | ||
sharedObjectId = sharedObject.reference.objectId; | ||
}); | ||
|
||
it('Basic Receive: receive and then transfer', async () => { | ||
const tx = new TransactionBlock(); | ||
tx.moveCall({ | ||
target: `${packageId}::tto::receiver`, | ||
typeArguments: [], | ||
arguments: [ | ||
tx.object(parentObjectId.reference.objectId), | ||
tx.object(receiveObjectId.reference.objectId), | ||
], | ||
}); | ||
await validateTransaction(toolbox.client, toolbox.keypair, tx); | ||
}); | ||
|
||
it('Basic Receive: receive and then delete', async () => { | ||
const tx = new TransactionBlock(); | ||
tx.moveCall({ | ||
target: `${packageId}::tto::deleter`, | ||
typeArguments: [], | ||
arguments: [ | ||
tx.object(parentObjectId.reference.objectId), | ||
tx.object(receiveObjectId.reference.objectId), | ||
], | ||
}); | ||
await validateTransaction(toolbox.client, toolbox.keypair, tx); | ||
}); | ||
|
||
it('receive + return, then delete', async () => { | ||
const tx = new TransactionBlock(); | ||
const b = tx.moveCall({ | ||
target: `${packageId}::tto::return_`, | ||
typeArguments: [], | ||
arguments: [ | ||
tx.object(parentObjectId.reference.objectId), | ||
tx.object(receiveObjectId.reference.objectId), | ||
], | ||
}); | ||
tx.moveCall({ | ||
target: `${packageId}::tto::delete_`, | ||
typeArguments: [], | ||
arguments: [b], | ||
}); | ||
await validateTransaction(toolbox.client, toolbox.keypair, tx); | ||
}); | ||
|
||
it('Basic Receive: &Receiving arg type', async () => { | ||
const tx = new TransactionBlock(); | ||
tx.moveCall({ | ||
target: `${packageId}::tto::invalid_call_immut_ref`, | ||
typeArguments: [], | ||
arguments: [ | ||
tx.object(parentObjectId.reference.objectId), | ||
tx.object(receiveObjectId.reference.objectId), | ||
], | ||
}); | ||
await validateTransaction(toolbox.client, toolbox.keypair, tx); | ||
}); | ||
|
||
it('Basic Receive: &mut Receiving arg type', async () => { | ||
const tx = new TransactionBlock(); | ||
tx.moveCall({ | ||
target: `${packageId}::tto::invalid_call_mut_ref`, | ||
typeArguments: [], | ||
arguments: [ | ||
tx.object(parentObjectId.reference.objectId), | ||
tx.object(receiveObjectId.reference.objectId), | ||
], | ||
}); | ||
await validateTransaction(toolbox.client, toolbox.keypair, tx); | ||
}); | ||
|
||
it.fails('Trying to pass shared object as receiving argument', async () => { | ||
const tx = new TransactionBlock(); | ||
tx.moveCall({ | ||
target: `${packageId}::tto::receiver`, | ||
typeArguments: [], | ||
arguments: [tx.object(parentObjectId.reference.objectId), tx.object(sharedObjectId)], | ||
}); | ||
await validateTransaction(toolbox.client, toolbox.keypair, tx); | ||
}); | ||
}); | ||
|
||
async function validateTransaction(client: SuiClient, signer: Keypair, tx: TransactionBlock) { | ||
tx.setSenderIfNotSet(signer.getPublicKey().toSuiAddress()); | ||
const localDigest = await tx.getDigest({ client }); | ||
const result = await client.signAndExecuteTransactionBlock({ | ||
signer, | ||
transactionBlock: tx, | ||
options: { | ||
showEffects: true, | ||
}, | ||
}); | ||
expect(localDigest).toEqual(result.digest); | ||
expect(result.effects?.status.status).toEqual('success'); | ||
return result; | ||
} |